html.py 20 KB

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