(function(Prism) {
  var attributes = {
    pattern: /(^[ \t]*)\[(?!\[)(?:(["'$`])(?:(?!\2)[^\\]|\\.)*\2|\[(?:[^\]\\]|\\.)*\]|[^\]\\]|\\.)*\]/m,
    lookbehind: true,
    inside: {
      quoted: {
        pattern: /([$`])(?:(?!\1)[^\\]|\\.)*\1/,
        inside: {
          punctuation: /^[$`]|[$`]$/,
        },
      },
      interpreted: {
        pattern: /'(?:[^'\\]|\\.)*'/,
        inside: {
          punctuation: /^'|'$/,
          // See rest below
        },
      },
      string: /"(?:[^"\\]|\\.)*"/,
      variable: /\w+(?==)/,
      punctuation: /^\[|\]$|,/,
      operator: /=/,
      // The negative look-ahead prevents blank matches
      'attr-value': /(?!^\s+$).+/,
    },
  };
  Prism.languages.asciidoc = {
    'comment-block': {
      pattern: /^(\/{4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1/m,
      alias: 'comment',
    },
    table: {
      pattern: /^\|={3,}(?:(?:\r?\n|\r).*)*?(?:\r?\n|\r)\|={3,}$/m,
      inside: {
        specifiers: {
          pattern: /(?!\|)(?:(?:(?:\d+(?:\.\d+)?|\.\d+)[+*])?(?:[<^>](?:\.[<^>])?|\.[<^>])?[a-z]*)(?=\|)/,
          alias: 'attr-value',
        },
        punctuation: {
          pattern: /(^|[^\\])[|!]=*/,
          lookbehind: true,
        },
        // See rest below
      },
    },

    'passthrough-block': {
      pattern: /^(\+{4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1$/m,
      inside: {
        punctuation: /^\++|\++$/,
        // See rest below
      },
    },
    // Literal blocks and listing blocks
    'literal-block': {
      pattern: /^(-{4,}|\.{4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1$/m,
      inside: {
        punctuation: /^(?:-+|\.+)|(?:-+|\.+)$/,
        // See rest below
      },
    },
    // Sidebar blocks, quote blocks, example blocks and open blocks
    'other-block': {
      pattern: /^(--|\*{4,}|_{4,}|={4,})(?:\r?\n|\r)(?:[\s\S]*(?:\r?\n|\r))??\1$/m,
      inside: {
        punctuation: /^(?:-+|\*+|_+|=+)|(?:-+|\*+|_+|=+)$/,
        // See rest below
      },
    },

    // list-punctuation and list-label must appear before indented-block
    'list-punctuation': {
      pattern: /(^[ \t]*)(?:-|\*{1,5}|\.{1,5}|(?:[a-z]|\d+)\.|[xvi]+\))(?= )/im,
      lookbehind: true,
      alias: 'punctuation',
    },
    'list-label': {
      pattern: /(^[ \t]*)[a-z\d].+(?::{2,4}|;;)(?=\s)/im,
      lookbehind: true,
      alias: 'symbol',
    },
    'indented-block': {
      pattern: /((\r?\n|\r)\2)([ \t]+)\S.*(?:(?:\r?\n|\r)\3.+)*(?=\2{2}|$)/,
      lookbehind: true,
    },

    comment: /^\/\/.*/m,
    title: {
      pattern: /^.+(?:\r?\n|\r)(?:={3,}|-{3,}|~{3,}|\^{3,}|\+{3,})$|^={1,5} +.+|^\.(?![\s.]).*/m,
      alias: 'important',
      inside: {
        punctuation: /^(?:\.|=+)|(?:=+|-+|~+|\^+|\++)$/,
        // See rest below
      },
    },
    'attribute-entry': {
      pattern: /^:[^:\r\n]+:(?: .*?(?: \+(?:\r?\n|\r).*?)*)?$/m,
      alias: 'tag',
    },
    attributes: attributes,
    hr: {
      pattern: /^'{3,}$/m,
      alias: 'punctuation',
    },
    'page-break': {
      pattern: /^<{3,}$/m,
      alias: 'punctuation',
    },
    admonition: {
      pattern: /^(?:TIP|NOTE|IMPORTANT|WARNING|CAUTION):/m,
      alias: 'keyword',
    },
    callout: [
      {
        pattern: /(^[ \t]*)<?\d*>/m,
        lookbehind: true,
        alias: 'symbol',
      },
      {
        pattern: /<\d+>/,
        alias: 'symbol',
      },
    ],
    macro: {
      pattern: /\b[a-z\d][a-z\d-]*::?(?:(?:\S+)??\[(?:[^\]\\"]|(["'])(?:(?!\1)[^\\]|\\.)*\1|\\.)*\])/,
      inside: {
        function: /^[a-z\d-]+(?=:)/,
        punctuation: /^::?/,
        attributes: {
          pattern: /(?:\[(?:[^\]\\"]|(["'])(?:(?!\1)[^\\]|\\.)*\1|\\.)*\])/,
          inside: attributes.inside,
        },
      },
    },
    inline: {
      /*
			The initial look-behind prevents the highlighting of escaped quoted text.

			Quoted text can be multi-line but cannot span an empty line.
			All quoted text can have attributes before [foobar, 'foobar', baz="bar"].

			First, we handle the constrained quotes.
			Those must be bounded by non-word chars and cannot have spaces between the delimiter and the first char.
			They are, in order: _emphasis_, ``double quotes'', `single quotes', `monospace`, 'emphasis', *strong*, +monospace+ and #unquoted#

			Then we handle the unconstrained quotes.
			Those do not have the restrictions of the constrained quotes.
			They are, in order: __emphasis__, **strong**, ++monospace++, +++passthrough+++, ##unquoted##, $$passthrough$$, ~subscript~, ^superscript^, {attribute-reference}, [[anchor]], [[[bibliography anchor]]], <<xref>>, (((indexes))) and ((indexes))
			 */
      pattern: /(^|[^\\])(?:(?:\B\[(?:[^\]\\"]|(["'])(?:(?!\2)[^\\]|\\.)*\2|\\.)*\])?(?:\b_(?!\s)(?: _|[^_\\\r\n]|\\.)+(?:(?:\r?\n|\r)(?: _|[^_\\\r\n]|\\.)+)*_\b|\B``(?!\s).+?(?:(?:\r?\n|\r).+?)*''\B|\B`(?!\s)(?: ['`]|.)+?(?:(?:\r?\n|\r)(?: ['`]|.)+?)*['`]\B|\B(['*+#])(?!\s)(?: \3|(?!\3)[^\\\r\n]|\\.)+(?:(?:\r?\n|\r)(?: \3|(?!\3)[^\\\r\n]|\\.)+)*\3\B)|(?:\[(?:[^\]\\"]|(["'])(?:(?!\4)[^\\]|\\.)*\4|\\.)*\])?(?:(__|\*\*|\+\+\+?|##|\$\$|[~^]).+?(?:(?:\r?\n|\r).+?)*\5|\{[^}\r\n]+\}|\[\[\[?.+?(?:(?:\r?\n|\r).+?)*\]?\]\]|<<.+?(?:(?:\r?\n|\r).+?)*>>|\(\(\(?.+?(?:(?:\r?\n|\r).+?)*\)?\)\)))/m,
      lookbehind: true,
      inside: {
        attributes: attributes,
        url: {
          pattern: /^(?:\[\[\[?.+?\]?\]\]|<<.+?>>)$/,
          inside: {
            punctuation: /^(?:\[\[\[?|<<)|(?:\]\]\]?|>>)$/,
          },
        },
        'attribute-ref': {
          pattern: /^\{.+\}$/,
          inside: {
            variable: {
              pattern: /(^\{)[a-z\d,+_-]+/,
              lookbehind: true,
            },
            operator: /^[=?!#%@$]|!(?=[:}])/,
            punctuation: /^\{|\}$|::?/,
          },
        },
        italic: {
          pattern: /^(['_])[\s\S]+\1$/,
          inside: {
            punctuation: /^(?:''?|__?)|(?:''?|__?)$/,
          },
        },
        bold: {
          pattern: /^\*[\s\S]+\*$/,
          inside: {
            punctuation: /^\*\*?|\*\*?$/,
          },
        },
        punctuation: /^(?:``?|\+{1,3}|##?|\$\$|[~^]|\(\(\(?)|(?:''?|\+{1,3}|##?|\$\$|[~^`]|\)?\)\))$/,
      },
    },
    replacement: {
      pattern: /\((?:C|TM|R)\)/,
      alias: 'builtin',
    },
    entity: /&#?[\da-z]{1,8};/i,
    'line-continuation': {
      pattern: /(^| )\+$/m,
      lookbehind: true,
      alias: 'punctuation',
    },
  };

  // Allow some nesting. There is no recursion though, so cloning should not be needed.

  attributes.inside['interpreted'].inside.rest = {
    macro: Prism.languages.asciidoc['macro'],
    inline: Prism.languages.asciidoc['inline'],
    replacement: Prism.languages.asciidoc['replacement'],
    entity: Prism.languages.asciidoc['entity'],
  };

  Prism.languages.asciidoc['passthrough-block'].inside.rest = {
    macro: Prism.languages.asciidoc['macro'],
  };

  Prism.languages.asciidoc['literal-block'].inside.rest = {
    callout: Prism.languages.asciidoc['callout'],
  };

  Prism.languages.asciidoc['table'].inside.rest = {
    'comment-block': Prism.languages.asciidoc['comment-block'],
    'passthrough-block': Prism.languages.asciidoc['passthrough-block'],
    'literal-block': Prism.languages.asciidoc['literal-block'],
    'other-block': Prism.languages.asciidoc['other-block'],
    'list-punctuation': Prism.languages.asciidoc['list-punctuation'],
    'indented-block': Prism.languages.asciidoc['indented-block'],
    comment: Prism.languages.asciidoc['comment'],
    title: Prism.languages.asciidoc['title'],
    'attribute-entry': Prism.languages.asciidoc['attribute-entry'],
    attributes: Prism.languages.asciidoc['attributes'],
    hr: Prism.languages.asciidoc['hr'],
    'page-break': Prism.languages.asciidoc['page-break'],
    admonition: Prism.languages.asciidoc['admonition'],
    'list-label': Prism.languages.asciidoc['list-label'],
    callout: Prism.languages.asciidoc['callout'],
    macro: Prism.languages.asciidoc['macro'],
    inline: Prism.languages.asciidoc['inline'],
    replacement: Prism.languages.asciidoc['replacement'],
    entity: Prism.languages.asciidoc['entity'],
    'line-continuation': Prism.languages.asciidoc['line-continuation'],
  };

  Prism.languages.asciidoc['other-block'].inside.rest = {
    table: Prism.languages.asciidoc['table'],
    'list-punctuation': Prism.languages.asciidoc['list-punctuation'],
    'indented-block': Prism.languages.asciidoc['indented-block'],
    comment: Prism.languages.asciidoc['comment'],
    'attribute-entry': Prism.languages.asciidoc['attribute-entry'],
    attributes: Prism.languages.asciidoc['attributes'],
    hr: Prism.languages.asciidoc['hr'],
    'page-break': Prism.languages.asciidoc['page-break'],
    admonition: Prism.languages.asciidoc['admonition'],
    'list-label': Prism.languages.asciidoc['list-label'],
    macro: Prism.languages.asciidoc['macro'],
    inline: Prism.languages.asciidoc['inline'],
    replacement: Prism.languages.asciidoc['replacement'],
    entity: Prism.languages.asciidoc['entity'],
    'line-continuation': Prism.languages.asciidoc['line-continuation'],
  };

  Prism.languages.asciidoc['title'].inside.rest = {
    macro: Prism.languages.asciidoc['macro'],
    inline: Prism.languages.asciidoc['inline'],
    replacement: Prism.languages.asciidoc['replacement'],
    entity: Prism.languages.asciidoc['entity'],
  };

  // Plugin to make entity title show the real entity, idea by Roman Komarov
  Prism.hooks.add('wrap', function(env) {
    if (env.type === 'entity') {
      env.attributes['title'] = env.content.replace(/&amp;/, '&');
    }
  });
})(Prism);
