html.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. # -*- coding: utf-8 -*-
  2. """
  3. pygments.lexers.html
  4. ~~~~~~~~~~~~~~~~~~~~
  5. Lexers for HTML, XML and related markup.
  6. :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS.
  7. :license: BSD, see LICENSE for details.
  8. """
  9. import re
  10. from pygments.lexer import RegexLexer, ExtendedRegexLexer, include, bygroups, \
  11. default, using
  12. from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
  13. Punctuation
  14. from pygments.util import looks_like_xml, html_doctype_matches
  15. from pygments.lexers.javascript import JavascriptLexer
  16. from pygments.lexers.jvm import ScalaLexer
  17. from pygments.lexers.css import CssLexer, _indentation, _starts_block
  18. from pygments.lexers.ruby import RubyLexer
  19. __all__ = ['HtmlLexer', 'DtdLexer', 'XmlLexer', 'XsltLexer', 'HamlLexer',
  20. 'ScamlLexer', 'PugLexer']
  21. class HtmlLexer(RegexLexer):
  22. """
  23. For HTML 4 and XHTML 1 markup. Nested JavaScript and CSS is highlighted
  24. by the appropriate lexer.
  25. """
  26. name = 'HTML'
  27. aliases = ['html']
  28. filenames = ['*.html', '*.htm', '*.xhtml', '*.xslt']
  29. mimetypes = ['text/html', 'application/xhtml+xml']
  30. flags = re.IGNORECASE | re.DOTALL
  31. tokens = {
  32. 'root': [
  33. ('[^<&]+', Text),
  34. (r'&\S*?;', Name.Entity),
  35. (r'\<\!\[CDATA\[.*?\]\]\>', Comment.Preproc),
  36. ('<!--', Comment, 'comment'),
  37. (r'<\?.*?\?>', Comment.Preproc),
  38. ('<![^>]*>', Comment.Preproc),
  39. (r'(<)(\s*)(script)(\s*)',
  40. bygroups(Punctuation, Text, Name.Tag, Text),
  41. ('script-content', 'tag')),
  42. (r'(<)(\s*)(style)(\s*)',
  43. bygroups(Punctuation, Text, Name.Tag, Text),
  44. ('style-content', 'tag')),
  45. # note: this allows tag names not used in HTML like <x:with-dash>,
  46. # this is to support yet-unknown template engines and the like
  47. (r'(<)(\s*)([\w:.-]+)',
  48. bygroups(Punctuation, Text, Name.Tag), 'tag'),
  49. (r'(<)(\s*)(/)(\s*)([\w:.-]+)(\s*)(>)',
  50. bygroups(Punctuation, Text, Punctuation, Text, Name.Tag, Text,
  51. Punctuation)),
  52. ],
  53. 'comment': [
  54. ('[^-]+', Comment),
  55. ('-->', Comment, '#pop'),
  56. ('-', Comment),
  57. ],
  58. 'tag': [
  59. (r'\s+', Text),
  60. (r'([\w:-]+\s*)(=)(\s*)', bygroups(Name.Attribute, Operator, Text),
  61. 'attr'),
  62. (r'[\w:-]+', Name.Attribute),
  63. (r'(/?)(\s*)(>)', bygroups(Punctuation, Text, Punctuation), '#pop'),
  64. ],
  65. 'script-content': [
  66. (r'(<)(\s*)(/)(\s*)(script)(\s*)(>)',
  67. bygroups(Punctuation, Text, Punctuation, Text, Name.Tag, Text,
  68. Punctuation), '#pop'),
  69. (r'.+?(?=<\s*/\s*script\s*>)', using(JavascriptLexer)),
  70. ],
  71. 'style-content': [
  72. (r'(<)(\s*)(/)(\s*)(style)(\s*)(>)',
  73. bygroups(Punctuation, Text, Punctuation, Text, Name.Tag, Text,
  74. Punctuation),'#pop'),
  75. (r'.+?(?=<\s*/\s*style\s*>)', using(CssLexer)),
  76. ],
  77. 'attr': [
  78. ('".*?"', String, '#pop'),
  79. ("'.*?'", String, '#pop'),
  80. (r'[^\s>]+', String, '#pop'),
  81. ],
  82. }
  83. def analyse_text(text):
  84. if html_doctype_matches(text):
  85. return 0.5
  86. class DtdLexer(RegexLexer):
  87. """
  88. A lexer for DTDs (Document Type Definitions).
  89. .. versionadded:: 1.5
  90. """
  91. flags = re.MULTILINE | re.DOTALL
  92. name = 'DTD'
  93. aliases = ['dtd']
  94. filenames = ['*.dtd']
  95. mimetypes = ['application/xml-dtd']
  96. tokens = {
  97. 'root': [
  98. include('common'),
  99. (r'(<!ELEMENT)(\s+)(\S+)',
  100. bygroups(Keyword, Text, Name.Tag), 'element'),
  101. (r'(<!ATTLIST)(\s+)(\S+)',
  102. bygroups(Keyword, Text, Name.Tag), 'attlist'),
  103. (r'(<!ENTITY)(\s+)(\S+)',
  104. bygroups(Keyword, Text, Name.Entity), 'entity'),
  105. (r'(<!NOTATION)(\s+)(\S+)',
  106. bygroups(Keyword, Text, Name.Tag), 'notation'),
  107. (r'(<!\[)([^\[\s]+)(\s*)(\[)', # conditional sections
  108. bygroups(Keyword, Name.Entity, Text, Keyword)),
  109. (r'(<!DOCTYPE)(\s+)([^>\s]+)',
  110. bygroups(Keyword, Text, Name.Tag)),
  111. (r'PUBLIC|SYSTEM', Keyword.Constant),
  112. (r'[\[\]>]', Keyword),
  113. ],
  114. 'common': [
  115. (r'\s+', Text),
  116. (r'(%|&)[^;]*;', Name.Entity),
  117. ('<!--', Comment, 'comment'),
  118. (r'[(|)*,?+]', Operator),
  119. (r'"[^"]*"', String.Double),
  120. (r'\'[^\']*\'', String.Single),
  121. ],
  122. 'comment': [
  123. ('[^-]+', Comment),
  124. ('-->', Comment, '#pop'),
  125. ('-', Comment),
  126. ],
  127. 'element': [
  128. include('common'),
  129. (r'EMPTY|ANY|#PCDATA', Keyword.Constant),
  130. (r'[^>\s|()?+*,]+', Name.Tag),
  131. (r'>', Keyword, '#pop'),
  132. ],
  133. 'attlist': [
  134. include('common'),
  135. (r'CDATA|IDREFS|IDREF|ID|NMTOKENS|NMTOKEN|ENTITIES|ENTITY|NOTATION',
  136. Keyword.Constant),
  137. (r'#REQUIRED|#IMPLIED|#FIXED', Keyword.Constant),
  138. (r'xml:space|xml:lang', Keyword.Reserved),
  139. (r'[^>\s|()?+*,]+', Name.Attribute),
  140. (r'>', Keyword, '#pop'),
  141. ],
  142. 'entity': [
  143. include('common'),
  144. (r'SYSTEM|PUBLIC|NDATA', Keyword.Constant),
  145. (r'[^>\s|()?+*,]+', Name.Entity),
  146. (r'>', Keyword, '#pop'),
  147. ],
  148. 'notation': [
  149. include('common'),
  150. (r'SYSTEM|PUBLIC', Keyword.Constant),
  151. (r'[^>\s|()?+*,]+', Name.Attribute),
  152. (r'>', Keyword, '#pop'),
  153. ],
  154. }
  155. def analyse_text(text):
  156. if not looks_like_xml(text) and \
  157. ('<!ELEMENT' in text or '<!ATTLIST' in text or '<!ENTITY' in text):
  158. return 0.8
  159. class XmlLexer(RegexLexer):
  160. """
  161. Generic lexer for XML (eXtensible Markup Language).
  162. """
  163. flags = re.MULTILINE | re.DOTALL | re.UNICODE
  164. name = 'XML'
  165. aliases = ['xml']
  166. filenames = ['*.xml', '*.xsl', '*.rss', '*.xslt', '*.xsd',
  167. '*.wsdl', '*.wsf']
  168. mimetypes = ['text/xml', 'application/xml', 'image/svg+xml',
  169. 'application/rss+xml', 'application/atom+xml']
  170. tokens = {
  171. 'root': [
  172. ('[^<&]+', Text),
  173. (r'&\S*?;', Name.Entity),
  174. (r'\<\!\[CDATA\[.*?\]\]\>', Comment.Preproc),
  175. ('<!--', Comment, 'comment'),
  176. (r'<\?.*?\?>', Comment.Preproc),
  177. ('<![^>]*>', Comment.Preproc),
  178. (r'<\s*[\w:.-]+', Name.Tag, 'tag'),
  179. (r'<\s*/\s*[\w:.-]+\s*>', Name.Tag),
  180. ],
  181. 'comment': [
  182. ('[^-]+', Comment),
  183. ('-->', Comment, '#pop'),
  184. ('-', Comment),
  185. ],
  186. 'tag': [
  187. (r'\s+', Text),
  188. (r'[\w.:-]+\s*=', Name.Attribute, 'attr'),
  189. (r'/?\s*>', Name.Tag, '#pop'),
  190. ],
  191. 'attr': [
  192. (r'\s+', Text),
  193. ('".*?"', String, '#pop'),
  194. ("'.*?'", String, '#pop'),
  195. (r'[^\s>]+', String, '#pop'),
  196. ],
  197. }
  198. def analyse_text(text):
  199. if looks_like_xml(text):
  200. return 0.45 # less than HTML
  201. class XsltLexer(XmlLexer):
  202. """
  203. A lexer for XSLT.
  204. .. versionadded:: 0.10
  205. """
  206. name = 'XSLT'
  207. aliases = ['xslt']
  208. filenames = ['*.xsl', '*.xslt', '*.xpl'] # xpl is XProc
  209. mimetypes = ['application/xsl+xml', 'application/xslt+xml']
  210. EXTRA_KEYWORDS = {
  211. 'apply-imports', 'apply-templates', 'attribute',
  212. 'attribute-set', 'call-template', 'choose', 'comment',
  213. 'copy', 'copy-of', 'decimal-format', 'element', 'fallback',
  214. 'for-each', 'if', 'import', 'include', 'key', 'message',
  215. 'namespace-alias', 'number', 'otherwise', 'output', 'param',
  216. 'preserve-space', 'processing-instruction', 'sort',
  217. 'strip-space', 'stylesheet', 'template', 'text', 'transform',
  218. 'value-of', 'variable', 'when', 'with-param'
  219. }
  220. def get_tokens_unprocessed(self, text):
  221. for index, token, value in XmlLexer.get_tokens_unprocessed(self, text):
  222. m = re.match('</?xsl:([^>]*)/?>?', value)
  223. if token is Name.Tag and m and m.group(1) in self.EXTRA_KEYWORDS:
  224. yield index, Keyword, value
  225. else:
  226. yield index, token, value
  227. def analyse_text(text):
  228. if looks_like_xml(text) and '<xsl' in text:
  229. return 0.8
  230. class HamlLexer(ExtendedRegexLexer):
  231. """
  232. For Haml markup.
  233. .. versionadded:: 1.3
  234. """
  235. name = 'Haml'
  236. aliases = ['haml']
  237. filenames = ['*.haml']
  238. mimetypes = ['text/x-haml']
  239. flags = re.IGNORECASE
  240. # Haml can include " |\n" anywhere,
  241. # which is ignored and used to wrap long lines.
  242. # To accomodate this, use this custom faux dot instead.
  243. _dot = r'(?: \|\n(?=.* \|)|.)'
  244. # In certain places, a comma at the end of the line
  245. # allows line wrapping as well.
  246. _comma_dot = r'(?:,\s*\n|' + _dot + ')'
  247. tokens = {
  248. 'root': [
  249. (r'[ \t]*\n', Text),
  250. (r'[ \t]*', _indentation),
  251. ],
  252. 'css': [
  253. (r'\.[\w:-]+', Name.Class, 'tag'),
  254. (r'\#[\w:-]+', Name.Function, 'tag'),
  255. ],
  256. 'eval-or-plain': [
  257. (r'[&!]?==', Punctuation, 'plain'),
  258. (r'([&!]?[=~])(' + _comma_dot + r'*\n)',
  259. bygroups(Punctuation, using(RubyLexer)),
  260. 'root'),
  261. default('plain'),
  262. ],
  263. 'content': [
  264. include('css'),
  265. (r'%[\w:-]+', Name.Tag, 'tag'),
  266. (r'!!!' + _dot + r'*\n', Name.Namespace, '#pop'),
  267. (r'(/)(\[' + _dot + r'*?\])(' + _dot + r'*\n)',
  268. bygroups(Comment, Comment.Special, Comment),
  269. '#pop'),
  270. (r'/' + _dot + r'*\n', _starts_block(Comment, 'html-comment-block'),
  271. '#pop'),
  272. (r'-#' + _dot + r'*\n', _starts_block(Comment.Preproc,
  273. 'haml-comment-block'), '#pop'),
  274. (r'(-)(' + _comma_dot + r'*\n)',
  275. bygroups(Punctuation, using(RubyLexer)),
  276. '#pop'),
  277. (r':' + _dot + r'*\n', _starts_block(Name.Decorator, 'filter-block'),
  278. '#pop'),
  279. include('eval-or-plain'),
  280. ],
  281. 'tag': [
  282. include('css'),
  283. (r'\{(,\n|' + _dot + r')*?\}', using(RubyLexer)),
  284. (r'\[' + _dot + r'*?\]', using(RubyLexer)),
  285. (r'\(', Text, 'html-attributes'),
  286. (r'/[ \t]*\n', Punctuation, '#pop:2'),
  287. (r'[<>]{1,2}(?=[ \t=])', Punctuation),
  288. include('eval-or-plain'),
  289. ],
  290. 'plain': [
  291. (r'([^#\n]|#[^{\n]|(\\\\)*\\#\{)+', Text),
  292. (r'(#\{)(' + _dot + r'*?)(\})',
  293. bygroups(String.Interpol, using(RubyLexer), String.Interpol)),
  294. (r'\n', Text, 'root'),
  295. ],
  296. 'html-attributes': [
  297. (r'\s+', Text),
  298. (r'[\w:-]+[ \t]*=', Name.Attribute, 'html-attribute-value'),
  299. (r'[\w:-]+', Name.Attribute),
  300. (r'\)', Text, '#pop'),
  301. ],
  302. 'html-attribute-value': [
  303. (r'[ \t]+', Text),
  304. (r'\w+', Name.Variable, '#pop'),
  305. (r'@\w+', Name.Variable.Instance, '#pop'),
  306. (r'\$\w+', Name.Variable.Global, '#pop'),
  307. (r"'(\\\\|\\'|[^'\n])*'", String, '#pop'),
  308. (r'"(\\\\|\\"|[^"\n])*"', String, '#pop'),
  309. ],
  310. 'html-comment-block': [
  311. (_dot + '+', Comment),
  312. (r'\n', Text, 'root'),
  313. ],
  314. 'haml-comment-block': [
  315. (_dot + '+', Comment.Preproc),
  316. (r'\n', Text, 'root'),
  317. ],
  318. 'filter-block': [
  319. (r'([^#\n]|#[^{\n]|(\\\\)*\\#\{)+', Name.Decorator),
  320. (r'(#\{)(' + _dot + r'*?)(\})',
  321. bygroups(String.Interpol, using(RubyLexer), String.Interpol)),
  322. (r'\n', Text, 'root'),
  323. ],
  324. }
  325. class ScamlLexer(ExtendedRegexLexer):
  326. """
  327. For `Scaml markup <http://scalate.fusesource.org/>`_. Scaml is Haml for Scala.
  328. .. versionadded:: 1.4
  329. """
  330. name = 'Scaml'
  331. aliases = ['scaml']
  332. filenames = ['*.scaml']
  333. mimetypes = ['text/x-scaml']
  334. flags = re.IGNORECASE
  335. # Scaml does not yet support the " |\n" notation to
  336. # wrap long lines. Once it does, use the custom faux
  337. # dot instead.
  338. # _dot = r'(?: \|\n(?=.* \|)|.)'
  339. _dot = r'.'
  340. tokens = {
  341. 'root': [
  342. (r'[ \t]*\n', Text),
  343. (r'[ \t]*', _indentation),
  344. ],
  345. 'css': [
  346. (r'\.[\w:-]+', Name.Class, 'tag'),
  347. (r'\#[\w:-]+', Name.Function, 'tag'),
  348. ],
  349. 'eval-or-plain': [
  350. (r'[&!]?==', Punctuation, 'plain'),
  351. (r'([&!]?[=~])(' + _dot + r'*\n)',
  352. bygroups(Punctuation, using(ScalaLexer)),
  353. 'root'),
  354. default('plain'),
  355. ],
  356. 'content': [
  357. include('css'),
  358. (r'%[\w:-]+', Name.Tag, 'tag'),
  359. (r'!!!' + _dot + r'*\n', Name.Namespace, '#pop'),
  360. (r'(/)(\[' + _dot + r'*?\])(' + _dot + r'*\n)',
  361. bygroups(Comment, Comment.Special, Comment),
  362. '#pop'),
  363. (r'/' + _dot + r'*\n', _starts_block(Comment, 'html-comment-block'),
  364. '#pop'),
  365. (r'-#' + _dot + r'*\n', _starts_block(Comment.Preproc,
  366. 'scaml-comment-block'), '#pop'),
  367. (r'(-@\s*)(import)?(' + _dot + r'*\n)',
  368. bygroups(Punctuation, Keyword, using(ScalaLexer)),
  369. '#pop'),
  370. (r'(-)(' + _dot + r'*\n)',
  371. bygroups(Punctuation, using(ScalaLexer)),
  372. '#pop'),
  373. (r':' + _dot + r'*\n', _starts_block(Name.Decorator, 'filter-block'),
  374. '#pop'),
  375. include('eval-or-plain'),
  376. ],
  377. 'tag': [
  378. include('css'),
  379. (r'\{(,\n|' + _dot + r')*?\}', using(ScalaLexer)),
  380. (r'\[' + _dot + r'*?\]', using(ScalaLexer)),
  381. (r'\(', Text, 'html-attributes'),
  382. (r'/[ \t]*\n', Punctuation, '#pop:2'),
  383. (r'[<>]{1,2}(?=[ \t=])', Punctuation),
  384. include('eval-or-plain'),
  385. ],
  386. 'plain': [
  387. (r'([^#\n]|#[^{\n]|(\\\\)*\\#\{)+', Text),
  388. (r'(#\{)(' + _dot + r'*?)(\})',
  389. bygroups(String.Interpol, using(ScalaLexer), String.Interpol)),
  390. (r'\n', Text, 'root'),
  391. ],
  392. 'html-attributes': [
  393. (r'\s+', Text),
  394. (r'[\w:-]+[ \t]*=', Name.Attribute, 'html-attribute-value'),
  395. (r'[\w:-]+', Name.Attribute),
  396. (r'\)', Text, '#pop'),
  397. ],
  398. 'html-attribute-value': [
  399. (r'[ \t]+', Text),
  400. (r'\w+', Name.Variable, '#pop'),
  401. (r'@\w+', Name.Variable.Instance, '#pop'),
  402. (r'\$\w+', Name.Variable.Global, '#pop'),
  403. (r"'(\\\\|\\'|[^'\n])*'", String, '#pop'),
  404. (r'"(\\\\|\\"|[^"\n])*"', String, '#pop'),
  405. ],
  406. 'html-comment-block': [
  407. (_dot + '+', Comment),
  408. (r'\n', Text, 'root'),
  409. ],
  410. 'scaml-comment-block': [
  411. (_dot + '+', Comment.Preproc),
  412. (r'\n', Text, 'root'),
  413. ],
  414. 'filter-block': [
  415. (r'([^#\n]|#[^{\n]|(\\\\)*\\#\{)+', Name.Decorator),
  416. (r'(#\{)(' + _dot + r'*?)(\})',
  417. bygroups(String.Interpol, using(ScalaLexer), String.Interpol)),
  418. (r'\n', Text, 'root'),
  419. ],
  420. }
  421. class PugLexer(ExtendedRegexLexer):
  422. """
  423. For Pug markup.
  424. Pug is a variant of Scaml, see:
  425. http://scalate.fusesource.org/documentation/scaml-reference.html
  426. .. versionadded:: 1.4
  427. """
  428. name = 'Pug'
  429. aliases = ['pug', 'jade']
  430. filenames = ['*.pug', '*.jade']
  431. mimetypes = ['text/x-pug', 'text/x-jade']
  432. flags = re.IGNORECASE
  433. _dot = r'.'
  434. tokens = {
  435. 'root': [
  436. (r'[ \t]*\n', Text),
  437. (r'[ \t]*', _indentation),
  438. ],
  439. 'css': [
  440. (r'\.[\w:-]+', Name.Class, 'tag'),
  441. (r'\#[\w:-]+', Name.Function, 'tag'),
  442. ],
  443. 'eval-or-plain': [
  444. (r'[&!]?==', Punctuation, 'plain'),
  445. (r'([&!]?[=~])(' + _dot + r'*\n)',
  446. bygroups(Punctuation, using(ScalaLexer)), 'root'),
  447. default('plain'),
  448. ],
  449. 'content': [
  450. include('css'),
  451. (r'!!!' + _dot + r'*\n', Name.Namespace, '#pop'),
  452. (r'(/)(\[' + _dot + r'*?\])(' + _dot + r'*\n)',
  453. bygroups(Comment, Comment.Special, Comment),
  454. '#pop'),
  455. (r'/' + _dot + r'*\n', _starts_block(Comment, 'html-comment-block'),
  456. '#pop'),
  457. (r'-#' + _dot + r'*\n', _starts_block(Comment.Preproc,
  458. 'scaml-comment-block'), '#pop'),
  459. (r'(-@\s*)(import)?(' + _dot + r'*\n)',
  460. bygroups(Punctuation, Keyword, using(ScalaLexer)),
  461. '#pop'),
  462. (r'(-)(' + _dot + r'*\n)',
  463. bygroups(Punctuation, using(ScalaLexer)),
  464. '#pop'),
  465. (r':' + _dot + r'*\n', _starts_block(Name.Decorator, 'filter-block'),
  466. '#pop'),
  467. (r'[\w:-]+', Name.Tag, 'tag'),
  468. (r'\|', Text, 'eval-or-plain'),
  469. ],
  470. 'tag': [
  471. include('css'),
  472. (r'\{(,\n|' + _dot + r')*?\}', using(ScalaLexer)),
  473. (r'\[' + _dot + r'*?\]', using(ScalaLexer)),
  474. (r'\(', Text, 'html-attributes'),
  475. (r'/[ \t]*\n', Punctuation, '#pop:2'),
  476. (r'[<>]{1,2}(?=[ \t=])', Punctuation),
  477. include('eval-or-plain'),
  478. ],
  479. 'plain': [
  480. (r'([^#\n]|#[^{\n]|(\\\\)*\\#\{)+', Text),
  481. (r'(#\{)(' + _dot + r'*?)(\})',
  482. bygroups(String.Interpol, using(ScalaLexer), String.Interpol)),
  483. (r'\n', Text, 'root'),
  484. ],
  485. 'html-attributes': [
  486. (r'\s+', Text),
  487. (r'[\w:-]+[ \t]*=', Name.Attribute, 'html-attribute-value'),
  488. (r'[\w:-]+', Name.Attribute),
  489. (r'\)', Text, '#pop'),
  490. ],
  491. 'html-attribute-value': [
  492. (r'[ \t]+', Text),
  493. (r'\w+', Name.Variable, '#pop'),
  494. (r'@\w+', Name.Variable.Instance, '#pop'),
  495. (r'\$\w+', Name.Variable.Global, '#pop'),
  496. (r"'(\\\\|\\'|[^'\n])*'", String, '#pop'),
  497. (r'"(\\\\|\\"|[^"\n])*"', String, '#pop'),
  498. ],
  499. 'html-comment-block': [
  500. (_dot + '+', Comment),
  501. (r'\n', Text, 'root'),
  502. ],
  503. 'scaml-comment-block': [
  504. (_dot + '+', Comment.Preproc),
  505. (r'\n', Text, 'root'),
  506. ],
  507. 'filter-block': [
  508. (r'([^#\n]|#[^{\n]|(\\\\)*\\#\{)+', Name.Decorator),
  509. (r'(#\{)(' + _dot + r'*?)(\})',
  510. bygroups(String.Interpol, using(ScalaLexer), String.Interpol)),
  511. (r'\n', Text, 'root'),
  512. ],
  513. }
  514. JadeLexer = PugLexer # compat