asciidoc.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. Language: AsciiDoc
  3. Requires: xml.js
  4. Author: Dan Allen <dan.j.allen@gmail.com>
  5. Website: http://asciidoc.org
  6. Description: A semantic, text-based document format that can be exported to HTML, DocBook and other backends.
  7. Category: markup
  8. */
  9. /** @type LanguageFn */
  10. function asciidoc(hljs) {
  11. const regex = hljs.regex;
  12. const HORIZONTAL_RULE = {
  13. begin: '^\'{3,}[ \\t]*$',
  14. relevance: 10
  15. };
  16. const ESCAPED_FORMATTING = [
  17. // escaped constrained formatting marks (i.e., \* \_ or \`)
  18. { begin: /\\[*_`]/ },
  19. // escaped unconstrained formatting marks (i.e., \\** \\__ or \\``)
  20. // must ignore until the next formatting marks
  21. // this rule might not be 100% compliant with Asciidoctor 2.0 but we are entering undefined behavior territory...
  22. { begin: /\\\\\*{2}[^\n]*?\*{2}/ },
  23. { begin: /\\\\_{2}[^\n]*_{2}/ },
  24. { begin: /\\\\`{2}[^\n]*`{2}/ },
  25. // guard: constrained formatting mark may not be preceded by ":", ";" or
  26. // "}". match these so the constrained rule doesn't see them
  27. { begin: /[:;}][*_`](?![*_`])/ }
  28. ];
  29. const STRONG = [
  30. // inline unconstrained strong (single line)
  31. {
  32. className: 'strong',
  33. begin: /\*{2}([^\n]+?)\*{2}/
  34. },
  35. // inline unconstrained strong (multi-line)
  36. {
  37. className: 'strong',
  38. begin: regex.concat(
  39. /\*\*/,
  40. /((\*(?!\*)|\\[^\n]|[^*\n\\])+\n)+/,
  41. /(\*(?!\*)|\\[^\n]|[^*\n\\])*/,
  42. /\*\*/
  43. ),
  44. relevance: 0
  45. },
  46. // inline constrained strong (single line)
  47. {
  48. className: 'strong',
  49. // must not precede or follow a word character
  50. begin: /\B\*(\S|\S[^\n]*?\S)\*(?!\w)/
  51. },
  52. // inline constrained strong (multi-line)
  53. {
  54. className: 'strong',
  55. // must not precede or follow a word character
  56. begin: /\*[^\s]([^\n]+\n)+([^\n]+)\*/
  57. }
  58. ];
  59. const EMPHASIS = [
  60. // inline unconstrained emphasis (single line)
  61. {
  62. className: 'emphasis',
  63. begin: /_{2}([^\n]+?)_{2}/
  64. },
  65. // inline unconstrained emphasis (multi-line)
  66. {
  67. className: 'emphasis',
  68. begin: regex.concat(
  69. /__/,
  70. /((_(?!_)|\\[^\n]|[^_\n\\])+\n)+/,
  71. /(_(?!_)|\\[^\n]|[^_\n\\])*/,
  72. /__/
  73. ),
  74. relevance: 0
  75. },
  76. // inline constrained emphasis (single line)
  77. {
  78. className: 'emphasis',
  79. // must not precede or follow a word character
  80. begin: /\b_(\S|\S[^\n]*?\S)_(?!\w)/
  81. },
  82. // inline constrained emphasis (multi-line)
  83. {
  84. className: 'emphasis',
  85. // must not precede or follow a word character
  86. begin: /_[^\s]([^\n]+\n)+([^\n]+)_/
  87. },
  88. // inline constrained emphasis using single quote (legacy)
  89. {
  90. className: 'emphasis',
  91. // must not follow a word character or be followed by a single quote or space
  92. begin: '\\B\'(?![\'\\s])',
  93. end: '(\\n{2}|\')',
  94. // allow escaped single quote followed by word char
  95. contains: [
  96. {
  97. begin: '\\\\\'\\w',
  98. relevance: 0
  99. }
  100. ],
  101. relevance: 0
  102. }
  103. ];
  104. const ADMONITION = {
  105. className: 'symbol',
  106. begin: '^(NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s+',
  107. relevance: 10
  108. };
  109. const BULLET_LIST = {
  110. className: 'bullet',
  111. begin: '^(\\*+|-+|\\.+|[^\\n]+?::)\\s+'
  112. };
  113. return {
  114. name: 'AsciiDoc',
  115. aliases: [ 'adoc' ],
  116. contains: [
  117. // block comment
  118. hljs.COMMENT(
  119. '^/{4,}\\n',
  120. '\\n/{4,}$',
  121. // can also be done as...
  122. // '^/{4,}$',
  123. // '^/{4,}$',
  124. { relevance: 10 }
  125. ),
  126. // line comment
  127. hljs.COMMENT(
  128. '^//',
  129. '$',
  130. { relevance: 0 }
  131. ),
  132. // title
  133. {
  134. className: 'title',
  135. begin: '^\\.\\w.*$'
  136. },
  137. // example, admonition & sidebar blocks
  138. {
  139. begin: '^[=\\*]{4,}\\n',
  140. end: '\\n^[=\\*]{4,}$',
  141. relevance: 10
  142. },
  143. // headings
  144. {
  145. className: 'section',
  146. relevance: 10,
  147. variants: [
  148. { begin: '^(={1,6})[ \t].+?([ \t]\\1)?$' },
  149. { begin: '^[^\\[\\]\\n]+?\\n[=\\-~\\^\\+]{2,}$' }
  150. ]
  151. },
  152. // document attributes
  153. {
  154. className: 'meta',
  155. begin: '^:.+?:',
  156. end: '\\s',
  157. excludeEnd: true,
  158. relevance: 10
  159. },
  160. // block attributes
  161. {
  162. className: 'meta',
  163. begin: '^\\[.+?\\]$',
  164. relevance: 0
  165. },
  166. // quoteblocks
  167. {
  168. className: 'quote',
  169. begin: '^_{4,}\\n',
  170. end: '\\n_{4,}$',
  171. relevance: 10
  172. },
  173. // listing and literal blocks
  174. {
  175. className: 'code',
  176. begin: '^[\\-\\.]{4,}\\n',
  177. end: '\\n[\\-\\.]{4,}$',
  178. relevance: 10
  179. },
  180. // passthrough blocks
  181. {
  182. begin: '^\\+{4,}\\n',
  183. end: '\\n\\+{4,}$',
  184. contains: [
  185. {
  186. begin: '<',
  187. end: '>',
  188. subLanguage: 'xml',
  189. relevance: 0
  190. }
  191. ],
  192. relevance: 10
  193. },
  194. BULLET_LIST,
  195. ADMONITION,
  196. ...ESCAPED_FORMATTING,
  197. ...STRONG,
  198. ...EMPHASIS,
  199. // inline smart quotes
  200. {
  201. className: 'string',
  202. variants: [
  203. { begin: "``.+?''" },
  204. { begin: "`.+?'" }
  205. ]
  206. },
  207. // inline unconstrained emphasis
  208. {
  209. className: 'code',
  210. begin: /`{2}/,
  211. end: /(\n{2}|`{2})/
  212. },
  213. // inline code snippets (TODO should get same treatment as strong and emphasis)
  214. {
  215. className: 'code',
  216. begin: '(`.+?`|\\+.+?\\+)',
  217. relevance: 0
  218. },
  219. // indented literal block
  220. {
  221. className: 'code',
  222. begin: '^[ \\t]',
  223. end: '$',
  224. relevance: 0
  225. },
  226. HORIZONTAL_RULE,
  227. // images and links
  228. {
  229. begin: '(link:)?(http|https|ftp|file|irc|image:?):\\S+?\\[[^[]*?\\]',
  230. returnBegin: true,
  231. contains: [
  232. {
  233. begin: '(link|image:?):',
  234. relevance: 0
  235. },
  236. {
  237. className: 'link',
  238. begin: '\\w',
  239. end: '[^\\[]+',
  240. relevance: 0
  241. },
  242. {
  243. className: 'string',
  244. begin: '\\[',
  245. end: '\\]',
  246. excludeBegin: true,
  247. excludeEnd: true,
  248. relevance: 0
  249. }
  250. ],
  251. relevance: 10
  252. }
  253. ]
  254. };
  255. }
  256. module.exports = asciidoc;