configs.py 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319
  1. """
  2. pygments.lexers.configs
  3. ~~~~~~~~~~~~~~~~~~~~~~~
  4. Lexers for configuration file formats.
  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 ExtendedRegexLexer, RegexLexer, default, words, \
  10. bygroups, include, using, line_re
  11. from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
  12. Number, Punctuation, Whitespace, Literal, Error, Generic
  13. from pygments.lexers.shell import BashLexer
  14. from pygments.lexers.data import JsonLexer
  15. __all__ = ['IniLexer', 'SystemdLexer', 'DesktopLexer', 'RegeditLexer', 'PropertiesLexer',
  16. 'KconfigLexer', 'Cfengine3Lexer', 'ApacheConfLexer', 'SquidConfLexer',
  17. 'NginxConfLexer', 'LighttpdConfLexer', 'DockerLexer',
  18. 'TerraformLexer', 'TermcapLexer', 'TerminfoLexer',
  19. 'PkgConfigLexer', 'PacmanConfLexer', 'AugeasLexer', 'TOMLLexer',
  20. 'NestedTextLexer', 'SingularityLexer', 'UnixConfigLexer']
  21. class IniLexer(RegexLexer):
  22. """
  23. Lexer for configuration files in INI style.
  24. """
  25. name = 'INI'
  26. aliases = ['ini', 'cfg', 'dosini']
  27. filenames = [
  28. '*.ini', '*.cfg', '*.inf', '.editorconfig',
  29. ]
  30. mimetypes = ['text/x-ini', 'text/inf']
  31. tokens = {
  32. 'root': [
  33. (r'\s+', Whitespace),
  34. (r'[;#].*', Comment.Single),
  35. (r'(\[.*?\])([ \t]*)$', bygroups(Keyword, Whitespace)),
  36. (r'(.*?)([  \t]*)([=:])([ \t]*)([^;#\n]*)(\\)(\s+)',
  37. bygroups(Name.Attribute, Whitespace, Operator, Whitespace, String,
  38. Text, Whitespace),
  39. "value"),
  40. (r'(.*?)([ \t]*)([=:])([  \t]*)([^ ;#\n]*(?: +[^ ;#\n]+)*)',
  41. bygroups(Name.Attribute, Whitespace, Operator, Whitespace, String)),
  42. # standalone option, supported by some INI parsers
  43. (r'(.+?)$', Name.Attribute),
  44. ],
  45. 'value': [ # line continuation
  46. (r'\s+', Whitespace),
  47. (r'(\s*)(.*)(\\)([ \t]*)',
  48. bygroups(Whitespace, String, Text, Whitespace)),
  49. (r'.*$', String, "#pop"),
  50. ],
  51. }
  52. def analyse_text(text):
  53. npos = text.find('\n')
  54. if npos < 3:
  55. return False
  56. if text[0] == '[' and text[npos-1] == ']':
  57. return 0.8
  58. return False
  59. class DesktopLexer(RegexLexer):
  60. """
  61. Lexer for .desktop files.
  62. .. versionadded:: 2.16
  63. """
  64. name = 'Desktop file'
  65. url = "https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html"
  66. aliases = ['desktop']
  67. filenames = ['*.desktop']
  68. tokens = {
  69. 'root': [
  70. (r'^[ \t]*\n', Whitespace),
  71. (r'^(#.*)(\n)', bygroups(Comment.Single, Whitespace)),
  72. (r'(\[[^\]\n]+\])(\n)', bygroups(Keyword, Whitespace)),
  73. (r'([-A-Za-z0-9]+)(\[[^\] \t=]+\])?([ \t]*)(=)([ \t]*)([^\n]*)([ \t\n]*\n)',
  74. bygroups(Name.Attribute, Name.Namespace, Whitespace, Operator, Whitespace, String, Whitespace)),
  75. ],
  76. }
  77. def analyse_text(text):
  78. if text.startswith("[Desktop Entry]"):
  79. return 1.0
  80. if re.search(r"^\[Desktop Entry\][ \t]*$", text[:500], re.MULTILINE) is not None:
  81. return 0.9
  82. return 0.0
  83. class SystemdLexer(RegexLexer):
  84. """
  85. Lexer for systemd unit files.
  86. .. versionadded:: 2.16
  87. """
  88. name = 'Systemd'
  89. url = "https://www.freedesktop.org/software/systemd/man/systemd.syntax.html"
  90. aliases = ['systemd']
  91. filenames = [
  92. '*.service', '*.socket', '*.device', '*.mount', '*.automount',
  93. '*.swap', '*.target', '*.path', '*.timer', '*.slice', '*.scope',
  94. ]
  95. tokens = {
  96. 'root': [
  97. (r'^[ \t]*\n', Whitespace),
  98. (r'^([;#].*)(\n)', bygroups(Comment.Single, Whitespace)),
  99. (r'(\[[^\]\n]+\])(\n)', bygroups(Keyword, Whitespace)),
  100. (r'([^=]+)([ \t]*)(=)([ \t]*)([^\n]*)(\\)(\n)',
  101. bygroups(Name.Attribute, Whitespace, Operator, Whitespace, String,
  102. Text, Whitespace),
  103. "value"),
  104. (r'([^=]+)([ \t]*)(=)([ \t]*)([^\n]*)(\n)',
  105. bygroups(Name.Attribute, Whitespace, Operator, Whitespace, String, Whitespace)),
  106. ],
  107. 'value': [
  108. # line continuation
  109. (r'^([;#].*)(\n)', bygroups(Comment.Single, Whitespace)),
  110. (r'([ \t]*)([^\n]*)(\\)(\n)',
  111. bygroups(Whitespace, String, Text, Whitespace)),
  112. (r'([ \t]*)([^\n]*)(\n)',
  113. bygroups(Whitespace, String, Whitespace), "#pop"),
  114. ],
  115. }
  116. def analyse_text(text):
  117. if text.startswith("[Unit]"):
  118. return 1.0
  119. if re.search(r"^\[Unit\][ \t]*$", text[:500], re.MULTILINE) is not None:
  120. return 0.9
  121. return 0.0
  122. class RegeditLexer(RegexLexer):
  123. """
  124. Lexer for Windows Registry files produced by regedit.
  125. .. versionadded:: 1.6
  126. """
  127. name = 'reg'
  128. url = 'http://en.wikipedia.org/wiki/Windows_Registry#.REG_files'
  129. aliases = ['registry']
  130. filenames = ['*.reg']
  131. mimetypes = ['text/x-windows-registry']
  132. tokens = {
  133. 'root': [
  134. (r'Windows Registry Editor.*', Text),
  135. (r'\s+', Whitespace),
  136. (r'[;#].*', Comment.Single),
  137. (r'(\[)(-?)(HKEY_[A-Z_]+)(.*?\])$',
  138. bygroups(Keyword, Operator, Name.Builtin, Keyword)),
  139. # String keys, which obey somewhat normal escaping
  140. (r'("(?:\\"|\\\\|[^"])+")([ \t]*)(=)([ \t]*)',
  141. bygroups(Name.Attribute, Whitespace, Operator, Whitespace),
  142. 'value'),
  143. # Bare keys (includes @)
  144. (r'(.*?)([ \t]*)(=)([ \t]*)',
  145. bygroups(Name.Attribute, Whitespace, Operator, Whitespace),
  146. 'value'),
  147. ],
  148. 'value': [
  149. (r'-', Operator, '#pop'), # delete value
  150. (r'(dword|hex(?:\([0-9a-fA-F]\))?)(:)([0-9a-fA-F,]+)',
  151. bygroups(Name.Variable, Punctuation, Number), '#pop'),
  152. # As far as I know, .reg files do not support line continuation.
  153. (r'.+', String, '#pop'),
  154. default('#pop'),
  155. ]
  156. }
  157. def analyse_text(text):
  158. return text.startswith('Windows Registry Editor')
  159. class PropertiesLexer(RegexLexer):
  160. """
  161. Lexer for configuration files in Java's properties format.
  162. Note: trailing whitespace counts as part of the value as per spec
  163. .. versionadded:: 1.4
  164. """
  165. name = 'Properties'
  166. aliases = ['properties', 'jproperties']
  167. filenames = ['*.properties']
  168. mimetypes = ['text/x-java-properties']
  169. tokens = {
  170. 'root': [
  171. # comments
  172. (r'[!#].*|/{2}.*', Comment.Single),
  173. # ending a comment or whitespace-only line
  174. (r'\n', Whitespace),
  175. # eat whitespace at the beginning of a line
  176. (r'^[^\S\n]+', Whitespace),
  177. # start lexing a key
  178. default('key'),
  179. ],
  180. 'key': [
  181. # non-escaped key characters
  182. (r'[^\\:=\s]+', Name.Attribute),
  183. # escapes
  184. include('escapes'),
  185. # separator is the first non-escaped whitespace or colon or '=' on the line;
  186. # if it's whitespace, = and : are gobbled after it
  187. (r'([^\S\n]*)([:=])([^\S\n]*)',
  188. bygroups(Whitespace, Operator, Whitespace),
  189. ('#pop', 'value')),
  190. (r'[^\S\n]+', Whitespace, ('#pop', 'value')),
  191. # maybe we got no value after all
  192. (r'\n', Whitespace, '#pop'),
  193. ],
  194. 'value': [
  195. # non-escaped value characters
  196. (r'[^\\\n]+', String),
  197. # escapes
  198. include('escapes'),
  199. # end the value on an unescaped newline
  200. (r'\n', Whitespace, '#pop'),
  201. ],
  202. 'escapes': [
  203. # line continuations; these gobble whitespace at the beginning of the next line
  204. (r'(\\\n)([^\S\n]*)', bygroups(String.Escape, Whitespace)),
  205. # other escapes
  206. (r'\\(.|\n)', String.Escape),
  207. ],
  208. }
  209. def _rx_indent(level):
  210. # Kconfig *always* interprets a tab as 8 spaces, so this is the default.
  211. # Edit this if you are in an environment where KconfigLexer gets expanded
  212. # input (tabs expanded to spaces) and the expansion tab width is != 8,
  213. # e.g. in connection with Trac (trac.ini, [mimeviewer], tab_width).
  214. # Value range here is 2 <= {tab_width} <= 8.
  215. tab_width = 8
  216. # Regex matching a given indentation {level}, assuming that indentation is
  217. # a multiple of {tab_width}. In other cases there might be problems.
  218. if tab_width == 2:
  219. space_repeat = '+'
  220. else:
  221. space_repeat = '{1,%d}' % (tab_width - 1)
  222. if level == 1:
  223. level_repeat = ''
  224. else:
  225. level_repeat = '{%s}' % level
  226. return r'(?:\t| %s\t| {%s})%s.*\n' % (space_repeat, tab_width, level_repeat)
  227. class KconfigLexer(RegexLexer):
  228. """
  229. For Linux-style Kconfig files.
  230. .. versionadded:: 1.6
  231. """
  232. name = 'Kconfig'
  233. aliases = ['kconfig', 'menuconfig', 'linux-config', 'kernel-config']
  234. # Adjust this if new kconfig file names appear in your environment
  235. filenames = ['Kconfig*', '*Config.in*', 'external.in*',
  236. 'standard-modules.in']
  237. mimetypes = ['text/x-kconfig']
  238. # No re.MULTILINE, indentation-aware help text needs line-by-line handling
  239. flags = 0
  240. def call_indent(level):
  241. # If indentation >= {level} is detected, enter state 'indent{level}'
  242. return (_rx_indent(level), String.Doc, 'indent%s' % level)
  243. def do_indent(level):
  244. # Print paragraphs of indentation level >= {level} as String.Doc,
  245. # ignoring blank lines. Then return to 'root' state.
  246. return [
  247. (_rx_indent(level), String.Doc),
  248. (r'\s*\n', Text),
  249. default('#pop:2')
  250. ]
  251. tokens = {
  252. 'root': [
  253. (r'\s+', Whitespace),
  254. (r'#.*?\n', Comment.Single),
  255. (words((
  256. 'mainmenu', 'config', 'menuconfig', 'choice', 'endchoice',
  257. 'comment', 'menu', 'endmenu', 'visible if', 'if', 'endif',
  258. 'source', 'prompt', 'select', 'depends on', 'default',
  259. 'range', 'option'), suffix=r'\b'),
  260. Keyword),
  261. (r'(---help---|help)[\t ]*\n', Keyword, 'help'),
  262. (r'(bool|tristate|string|hex|int|defconfig_list|modules|env)\b',
  263. Name.Builtin),
  264. (r'[!=&|]', Operator),
  265. (r'[()]', Punctuation),
  266. (r'[0-9]+', Number.Integer),
  267. (r"'(''|[^'])*'", String.Single),
  268. (r'"(""|[^"])*"', String.Double),
  269. (r'\S+', Text),
  270. ],
  271. # Help text is indented, multi-line and ends when a lower indentation
  272. # level is detected.
  273. 'help': [
  274. # Skip blank lines after help token, if any
  275. (r'\s*\n', Text),
  276. # Determine the first help line's indentation level heuristically(!).
  277. # Attention: this is not perfect, but works for 99% of "normal"
  278. # indentation schemes up to a max. indentation level of 7.
  279. call_indent(7),
  280. call_indent(6),
  281. call_indent(5),
  282. call_indent(4),
  283. call_indent(3),
  284. call_indent(2),
  285. call_indent(1),
  286. default('#pop'), # for incomplete help sections without text
  287. ],
  288. # Handle text for indentation levels 7 to 1
  289. 'indent7': do_indent(7),
  290. 'indent6': do_indent(6),
  291. 'indent5': do_indent(5),
  292. 'indent4': do_indent(4),
  293. 'indent3': do_indent(3),
  294. 'indent2': do_indent(2),
  295. 'indent1': do_indent(1),
  296. }
  297. class Cfengine3Lexer(RegexLexer):
  298. """
  299. Lexer for CFEngine3 policy files.
  300. .. versionadded:: 1.5
  301. """
  302. name = 'CFEngine3'
  303. url = 'http://cfengine.org'
  304. aliases = ['cfengine3', 'cf3']
  305. filenames = ['*.cf']
  306. mimetypes = []
  307. tokens = {
  308. 'root': [
  309. (r'#.*?\n', Comment),
  310. (r'(body)(\s+)(\S+)(\s+)(control)',
  311. bygroups(Keyword, Whitespace, Keyword, Whitespace, Keyword)),
  312. (r'(body|bundle)(\s+)(\S+)(\s+)(\w+)(\()',
  313. bygroups(Keyword, Whitespace, Keyword, Whitespace, Name.Function, Punctuation),
  314. 'arglist'),
  315. (r'(body|bundle)(\s+)(\S+)(\s+)(\w+)',
  316. bygroups(Keyword, Whitespace, Keyword, Whitespace, Name.Function)),
  317. (r'(")([^"]+)(")(\s+)(string|slist|int|real)(\s*)(=>)(\s*)',
  318. bygroups(Punctuation, Name.Variable, Punctuation,
  319. Whitespace, Keyword.Type, Whitespace, Operator, Whitespace)),
  320. (r'(\S+)(\s*)(=>)(\s*)',
  321. bygroups(Keyword.Reserved, Whitespace, Operator, Text)),
  322. (r'"', String, 'string'),
  323. (r'(\w+)(\()', bygroups(Name.Function, Punctuation)),
  324. (r'([\w.!&|()]+)(::)', bygroups(Name.Class, Punctuation)),
  325. (r'(\w+)(:)', bygroups(Keyword.Declaration, Punctuation)),
  326. (r'@[{(][^)}]+[})]', Name.Variable),
  327. (r'[(){},;]', Punctuation),
  328. (r'=>', Operator),
  329. (r'->', Operator),
  330. (r'\d+\.\d+', Number.Float),
  331. (r'\d+', Number.Integer),
  332. (r'\w+', Name.Function),
  333. (r'\s+', Whitespace),
  334. ],
  335. 'string': [
  336. (r'\$[{(]', String.Interpol, 'interpol'),
  337. (r'\\.', String.Escape),
  338. (r'"', String, '#pop'),
  339. (r'\n', String),
  340. (r'.', String),
  341. ],
  342. 'interpol': [
  343. (r'\$[{(]', String.Interpol, '#push'),
  344. (r'[})]', String.Interpol, '#pop'),
  345. (r'[^${()}]+', String.Interpol),
  346. ],
  347. 'arglist': [
  348. (r'\)', Punctuation, '#pop'),
  349. (r',', Punctuation),
  350. (r'\w+', Name.Variable),
  351. (r'\s+', Whitespace),
  352. ],
  353. }
  354. class ApacheConfLexer(RegexLexer):
  355. """
  356. Lexer for configuration files following the Apache config file
  357. format.
  358. .. versionadded:: 0.6
  359. """
  360. name = 'ApacheConf'
  361. aliases = ['apacheconf', 'aconf', 'apache']
  362. filenames = ['.htaccess', 'apache.conf', 'apache2.conf']
  363. mimetypes = ['text/x-apacheconf']
  364. flags = re.MULTILINE | re.IGNORECASE
  365. tokens = {
  366. 'root': [
  367. (r'\s+', Whitespace),
  368. (r'#(.*\\\n)+.*$|(#.*?)$', Comment),
  369. (r'(<[^\s>/][^\s>]*)(?:(\s+)(.*))?(>)',
  370. bygroups(Name.Tag, Whitespace, String, Name.Tag)),
  371. (r'(</[^\s>]+)(>)',
  372. bygroups(Name.Tag, Name.Tag)),
  373. (r'[a-z]\w*', Name.Builtin, 'value'),
  374. (r'\.+', Text),
  375. ],
  376. 'value': [
  377. (r'\\\n', Text),
  378. (r'\n+', Whitespace, '#pop'),
  379. (r'\\', Text),
  380. (r'[^\S\n]+', Whitespace),
  381. (r'\d+\.\d+\.\d+\.\d+(?:/\d+)?', Number),
  382. (r'\d+', Number),
  383. (r'/([*a-z0-9][*\w./-]+)', String.Other),
  384. (r'(on|off|none|any|all|double|email|dns|min|minimal|'
  385. r'os|productonly|full|emerg|alert|crit|error|warn|'
  386. r'notice|info|debug|registry|script|inetd|standalone|'
  387. r'user|group)\b', Keyword),
  388. (r'"([^"\\]*(?:\\(.|\n)[^"\\]*)*)"', String.Double),
  389. (r'[^\s"\\]+', Text)
  390. ],
  391. }
  392. class SquidConfLexer(RegexLexer):
  393. """
  394. Lexer for squid configuration files.
  395. .. versionadded:: 0.9
  396. """
  397. name = 'SquidConf'
  398. url = 'http://www.squid-cache.org/'
  399. aliases = ['squidconf', 'squid.conf', 'squid']
  400. filenames = ['squid.conf']
  401. mimetypes = ['text/x-squidconf']
  402. flags = re.IGNORECASE
  403. keywords = (
  404. "access_log", "acl", "always_direct", "announce_host",
  405. "announce_period", "announce_port", "announce_to", "anonymize_headers",
  406. "append_domain", "as_whois_server", "auth_param_basic",
  407. "authenticate_children", "authenticate_program", "authenticate_ttl",
  408. "broken_posts", "buffered_logs", "cache_access_log", "cache_announce",
  409. "cache_dir", "cache_dns_program", "cache_effective_group",
  410. "cache_effective_user", "cache_host", "cache_host_acl",
  411. "cache_host_domain", "cache_log", "cache_mem", "cache_mem_high",
  412. "cache_mem_low", "cache_mgr", "cachemgr_passwd", "cache_peer",
  413. "cache_peer_access", "cache_replacement_policy", "cache_stoplist",
  414. "cache_stoplist_pattern", "cache_store_log", "cache_swap",
  415. "cache_swap_high", "cache_swap_log", "cache_swap_low", "client_db",
  416. "client_lifetime", "client_netmask", "connect_timeout", "coredump_dir",
  417. "dead_peer_timeout", "debug_options", "delay_access", "delay_class",
  418. "delay_initial_bucket_level", "delay_parameters", "delay_pools",
  419. "deny_info", "dns_children", "dns_defnames", "dns_nameservers",
  420. "dns_testnames", "emulate_httpd_log", "err_html_text",
  421. "fake_user_agent", "firewall_ip", "forwarded_for", "forward_snmpd_port",
  422. "fqdncache_size", "ftpget_options", "ftpget_program", "ftp_list_width",
  423. "ftp_passive", "ftp_user", "half_closed_clients", "header_access",
  424. "header_replace", "hierarchy_stoplist", "high_response_time_warning",
  425. "high_page_fault_warning", "hosts_file", "htcp_port", "http_access",
  426. "http_anonymizer", "httpd_accel", "httpd_accel_host",
  427. "httpd_accel_port", "httpd_accel_uses_host_header",
  428. "httpd_accel_with_proxy", "http_port", "http_reply_access",
  429. "icp_access", "icp_hit_stale", "icp_port", "icp_query_timeout",
  430. "ident_lookup", "ident_lookup_access", "ident_timeout",
  431. "incoming_http_average", "incoming_icp_average", "inside_firewall",
  432. "ipcache_high", "ipcache_low", "ipcache_size", "local_domain",
  433. "local_ip", "logfile_rotate", "log_fqdn", "log_icp_queries",
  434. "log_mime_hdrs", "maximum_object_size", "maximum_single_addr_tries",
  435. "mcast_groups", "mcast_icp_query_timeout", "mcast_miss_addr",
  436. "mcast_miss_encode_key", "mcast_miss_port", "memory_pools",
  437. "memory_pools_limit", "memory_replacement_policy", "mime_table",
  438. "min_http_poll_cnt", "min_icp_poll_cnt", "minimum_direct_hops",
  439. "minimum_object_size", "minimum_retry_timeout", "miss_access",
  440. "negative_dns_ttl", "negative_ttl", "neighbor_timeout",
  441. "neighbor_type_domain", "netdb_high", "netdb_low", "netdb_ping_period",
  442. "netdb_ping_rate", "never_direct", "no_cache", "passthrough_proxy",
  443. "pconn_timeout", "pid_filename", "pinger_program", "positive_dns_ttl",
  444. "prefer_direct", "proxy_auth", "proxy_auth_realm", "query_icmp",
  445. "quick_abort", "quick_abort_max", "quick_abort_min",
  446. "quick_abort_pct", "range_offset_limit", "read_timeout",
  447. "redirect_children", "redirect_program",
  448. "redirect_rewrites_host_header", "reference_age",
  449. "refresh_pattern", "reload_into_ims", "request_body_max_size",
  450. "request_size", "request_timeout", "shutdown_lifetime",
  451. "single_parent_bypass", "siteselect_timeout", "snmp_access",
  452. "snmp_incoming_address", "snmp_port", "source_ping", "ssl_proxy",
  453. "store_avg_object_size", "store_objects_per_bucket",
  454. "strip_query_terms", "swap_level1_dirs", "swap_level2_dirs",
  455. "tcp_incoming_address", "tcp_outgoing_address", "tcp_recv_bufsize",
  456. "test_reachability", "udp_hit_obj", "udp_hit_obj_size",
  457. "udp_incoming_address", "udp_outgoing_address", "unique_hostname",
  458. "unlinkd_program", "uri_whitespace", "useragent_log",
  459. "visible_hostname", "wais_relay", "wais_relay_host", "wais_relay_port",
  460. )
  461. opts = (
  462. "proxy-only", "weight", "ttl", "no-query", "default", "round-robin",
  463. "multicast-responder", "on", "off", "all", "deny", "allow", "via",
  464. "parent", "no-digest", "heap", "lru", "realm", "children", "q1", "q2",
  465. "credentialsttl", "none", "disable", "offline_toggle", "diskd",
  466. )
  467. actions = (
  468. "shutdown", "info", "parameter", "server_list", "client_list",
  469. r'squid.conf',
  470. )
  471. actions_stats = (
  472. "objects", "vm_objects", "utilization", "ipcache", "fqdncache", "dns",
  473. "redirector", "io", "reply_headers", "filedescriptors", "netdb",
  474. )
  475. actions_log = ("status", "enable", "disable", "clear")
  476. acls = (
  477. "url_regex", "urlpath_regex", "referer_regex", "port", "proto",
  478. "req_mime_type", "rep_mime_type", "method", "browser", "user", "src",
  479. "dst", "time", "dstdomain", "ident", "snmp_community",
  480. )
  481. ip_re = (
  482. r'(?:(?:(?:[3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}|0x0*[0-9a-f]{1,2}|'
  483. r'0+[1-3]?[0-7]{0,2})(?:\.(?:[3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}|'
  484. r'0x0*[0-9a-f]{1,2}|0+[1-3]?[0-7]{0,2})){3})|(?!.*::.*::)(?:(?!:)|'
  485. r':(?=:))(?:[0-9a-f]{0,4}(?:(?<=::)|(?<!::):)){6}(?:[0-9a-f]{0,4}'
  486. r'(?:(?<=::)|(?<!::):)[0-9a-f]{0,4}(?:(?<=::)|(?<!:)|(?<=:)(?<!::):)|'
  487. r'(?:25[0-4]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-4]|2[0-4]\d|1\d\d|'
  488. r'[1-9]?\d)){3}))'
  489. )
  490. tokens = {
  491. 'root': [
  492. (r'\s+', Whitespace),
  493. (r'#', Comment, 'comment'),
  494. (words(keywords, prefix=r'\b', suffix=r'\b'), Keyword),
  495. (words(opts, prefix=r'\b', suffix=r'\b'), Name.Constant),
  496. # Actions
  497. (words(actions, prefix=r'\b', suffix=r'\b'), String),
  498. (words(actions_stats, prefix=r'stats/', suffix=r'\b'), String),
  499. (words(actions_log, prefix=r'log/', suffix=r'='), String),
  500. (words(acls, prefix=r'\b', suffix=r'\b'), Keyword),
  501. (ip_re + r'(?:/(?:' + ip_re + r'|\b\d+\b))?', Number.Float),
  502. (r'(?:\b\d+\b(?:-\b\d+|%)?)', Number),
  503. (r'\S+', Text),
  504. ],
  505. 'comment': [
  506. (r'\s*TAG:.*', String.Escape, '#pop'),
  507. (r'.+', Comment, '#pop'),
  508. default('#pop'),
  509. ],
  510. }
  511. class NginxConfLexer(RegexLexer):
  512. """
  513. Lexer for Nginx configuration files.
  514. .. versionadded:: 0.11
  515. """
  516. name = 'Nginx configuration file'
  517. url = 'http://nginx.net/'
  518. aliases = ['nginx']
  519. filenames = ['nginx.conf']
  520. mimetypes = ['text/x-nginx-conf']
  521. tokens = {
  522. 'root': [
  523. (r'(include)(\s+)([^\s;]+)', bygroups(Keyword, Whitespace, Name)),
  524. (r'[^\s;#]+', Keyword, 'stmt'),
  525. include('base'),
  526. ],
  527. 'block': [
  528. (r'\}', Punctuation, '#pop:2'),
  529. (r'[^\s;#]+', Keyword.Namespace, 'stmt'),
  530. include('base'),
  531. ],
  532. 'stmt': [
  533. (r'\{', Punctuation, 'block'),
  534. (r';', Punctuation, '#pop'),
  535. include('base'),
  536. ],
  537. 'base': [
  538. (r'#.*\n', Comment.Single),
  539. (r'on|off', Name.Constant),
  540. (r'\$[^\s;#()]+', Name.Variable),
  541. (r'([a-z0-9.-]+)(:)([0-9]+)',
  542. bygroups(Name, Punctuation, Number.Integer)),
  543. (r'[a-z-]+/[a-z-+]+', String), # mimetype
  544. # (r'[a-zA-Z._-]+', Keyword),
  545. (r'[0-9]+[km]?\b', Number.Integer),
  546. (r'(~)(\s*)([^\s{]+)', bygroups(Punctuation, Whitespace, String.Regex)),
  547. (r'[:=~]', Punctuation),
  548. (r'[^\s;#{}$]+', String), # catch all
  549. (r'/[^\s;#]*', Name), # pathname
  550. (r'\s+', Whitespace),
  551. (r'[$;]', Text), # leftover characters
  552. ],
  553. }
  554. class LighttpdConfLexer(RegexLexer):
  555. """
  556. Lexer for Lighttpd configuration files.
  557. .. versionadded:: 0.11
  558. """
  559. name = 'Lighttpd configuration file'
  560. url = 'http://lighttpd.net/'
  561. aliases = ['lighttpd', 'lighty']
  562. filenames = ['lighttpd.conf']
  563. mimetypes = ['text/x-lighttpd-conf']
  564. tokens = {
  565. 'root': [
  566. (r'#.*\n', Comment.Single),
  567. (r'/\S*', Name), # pathname
  568. (r'[a-zA-Z._-]+', Keyword),
  569. (r'\d+\.\d+\.\d+\.\d+(?:/\d+)?', Number),
  570. (r'[0-9]+', Number),
  571. (r'=>|=~|\+=|==|=|\+', Operator),
  572. (r'\$[A-Z]+', Name.Builtin),
  573. (r'[(){}\[\],]', Punctuation),
  574. (r'"([^"\\]*(?:\\.[^"\\]*)*)"', String.Double),
  575. (r'\s+', Whitespace),
  576. ],
  577. }
  578. class DockerLexer(RegexLexer):
  579. """
  580. Lexer for Docker configuration files.
  581. .. versionadded:: 2.0
  582. """
  583. name = 'Docker'
  584. url = 'http://docker.io'
  585. aliases = ['docker', 'dockerfile']
  586. filenames = ['Dockerfile', '*.docker']
  587. mimetypes = ['text/x-dockerfile-config']
  588. _keywords = (r'(?:MAINTAINER|EXPOSE|WORKDIR|USER|STOPSIGNAL)')
  589. _bash_keywords = (r'(?:RUN|CMD|ENTRYPOINT|ENV|ARG|LABEL|ADD|COPY)')
  590. _lb = r'(?:\s*\\?\s*)' # dockerfile line break regex
  591. flags = re.IGNORECASE | re.MULTILINE
  592. tokens = {
  593. 'root': [
  594. (r'#.*', Comment),
  595. (r'(FROM)([ \t]*)(\S*)([ \t]*)(?:(AS)([ \t]*)(\S*))?',
  596. bygroups(Keyword, Whitespace, String, Whitespace, Keyword, Whitespace, String)),
  597. (r'(ONBUILD)(\s+)(%s)' % (_lb,), bygroups(Keyword, Whitespace, using(BashLexer))),
  598. (r'(HEALTHCHECK)(\s+)((%s--\w+=\w+%s)*)' % (_lb, _lb),
  599. bygroups(Keyword, Whitespace, using(BashLexer))),
  600. (r'(VOLUME|ENTRYPOINT|CMD|SHELL)(\s+)(%s)(\[.*?\])' % (_lb,),
  601. bygroups(Keyword, Whitespace, using(BashLexer), using(JsonLexer))),
  602. (r'(LABEL|ENV|ARG)(\s+)((%s\w+=\w+%s)*)' % (_lb, _lb),
  603. bygroups(Keyword, Whitespace, using(BashLexer))),
  604. (r'(%s|VOLUME)\b(\s+)(.*)' % (_keywords), bygroups(Keyword, Whitespace, String)),
  605. (r'(%s)(\s+)' % (_bash_keywords,), bygroups(Keyword, Whitespace)),
  606. (r'(.*\\\n)*.+', using(BashLexer)),
  607. ]
  608. }
  609. class TerraformLexer(ExtendedRegexLexer):
  610. """
  611. Lexer for terraformi ``.tf`` files.
  612. .. versionadded:: 2.1
  613. """
  614. name = 'Terraform'
  615. url = 'https://www.terraform.io/'
  616. aliases = ['terraform', 'tf', 'hcl']
  617. filenames = ['*.tf', '*.hcl']
  618. mimetypes = ['application/x-tf', 'application/x-terraform']
  619. classes = ('backend', 'data', 'module', 'output', 'provider',
  620. 'provisioner', 'resource', 'variable')
  621. classes_re = "({})".format(('|').join(classes))
  622. types = ('string', 'number', 'bool', 'list', 'tuple', 'map', 'set', 'object', 'null')
  623. numeric_functions = ('abs', 'ceil', 'floor', 'log', 'max',
  624. 'mix', 'parseint', 'pow', 'signum')
  625. string_functions = ('chomp', 'format', 'formatlist', 'indent',
  626. 'join', 'lower', 'regex', 'regexall', 'replace',
  627. 'split', 'strrev', 'substr', 'title', 'trim',
  628. 'trimprefix', 'trimsuffix', 'trimspace', 'upper'
  629. )
  630. collection_functions = ('alltrue', 'anytrue', 'chunklist', 'coalesce',
  631. 'coalescelist', 'compact', 'concat', 'contains',
  632. 'distinct', 'element', 'flatten', 'index', 'keys',
  633. 'length', 'list', 'lookup', 'map', 'matchkeys',
  634. 'merge', 'range', 'reverse', 'setintersection',
  635. 'setproduct', 'setsubtract', 'setunion', 'slice',
  636. 'sort', 'sum', 'transpose', 'values', 'zipmap'
  637. )
  638. encoding_functions = ('base64decode', 'base64encode', 'base64gzip',
  639. 'csvdecode', 'jsondecode', 'jsonencode', 'textdecodebase64',
  640. 'textencodebase64', 'urlencode', 'yamldecode', 'yamlencode')
  641. filesystem_functions = ('abspath', 'dirname', 'pathexpand', 'basename',
  642. 'file', 'fileexists', 'fileset', 'filebase64', 'templatefile')
  643. date_time_functions = ('formatdate', 'timeadd', 'timestamp')
  644. hash_crypto_functions = ('base64sha256', 'base64sha512', 'bcrypt', 'filebase64sha256',
  645. 'filebase64sha512', 'filemd5', 'filesha1', 'filesha256', 'filesha512',
  646. 'md5', 'rsadecrypt', 'sha1', 'sha256', 'sha512', 'uuid', 'uuidv5')
  647. ip_network_functions = ('cidrhost', 'cidrnetmask', 'cidrsubnet', 'cidrsubnets')
  648. type_conversion_functions = ('can', 'defaults', 'tobool', 'tolist', 'tomap',
  649. 'tonumber', 'toset', 'tostring', 'try')
  650. builtins = numeric_functions + string_functions + collection_functions + encoding_functions +\
  651. filesystem_functions + date_time_functions + hash_crypto_functions + ip_network_functions +\
  652. type_conversion_functions
  653. builtins_re = "({})".format(('|').join(builtins))
  654. def heredoc_callback(self, match, ctx):
  655. # Parse a terraform heredoc
  656. # match: 1 = <<[-]?, 2 = name 3 = rest of line
  657. start = match.start(1)
  658. yield start, Operator, match.group(1) # <<[-]?
  659. yield match.start(2), String.Delimiter, match.group(2) # heredoc name
  660. ctx.pos = match.start(3)
  661. ctx.end = match.end(3)
  662. yield ctx.pos, String.Heredoc, match.group(3)
  663. ctx.pos = match.end()
  664. hdname = match.group(2)
  665. tolerant = True # leading whitespace is always accepted
  666. lines = []
  667. for match in line_re.finditer(ctx.text, ctx.pos):
  668. if tolerant:
  669. check = match.group().strip()
  670. else:
  671. check = match.group().rstrip()
  672. if check == hdname:
  673. for amatch in lines:
  674. yield amatch.start(), String.Heredoc, amatch.group()
  675. yield match.start(), String.Delimiter, match.group()
  676. ctx.pos = match.end()
  677. break
  678. else:
  679. lines.append(match)
  680. else:
  681. # end of heredoc not found -- error!
  682. for amatch in lines:
  683. yield amatch.start(), Error, amatch.group()
  684. ctx.end = len(ctx.text)
  685. tokens = {
  686. 'root': [
  687. include('basic'),
  688. include('whitespace'),
  689. # Strings
  690. (r'(".*")', bygroups(String.Double)),
  691. # Constants
  692. (words(('true', 'false'), prefix=r'\b', suffix=r'\b'), Name.Constant),
  693. # Types
  694. (words(types, prefix=r'\b', suffix=r'\b'), Keyword.Type),
  695. include('identifier'),
  696. include('punctuation'),
  697. (r'[0-9]+', Number),
  698. ],
  699. 'basic': [
  700. (r'\s*/\*', Comment.Multiline, 'comment'),
  701. (r'\s*(#|//).*\n', Comment.Single),
  702. include('whitespace'),
  703. # e.g. terraform {
  704. # e.g. egress {
  705. (r'(\s*)([0-9a-zA-Z-_]+)(\s*)(=?)(\s*)(\{)',
  706. bygroups(Whitespace, Name.Builtin, Whitespace, Operator, Whitespace, Punctuation)),
  707. # Assignment with attributes, e.g. something = ...
  708. (r'(\s*)([0-9a-zA-Z-_]+)(\s*)(=)(\s*)',
  709. bygroups(Whitespace, Name.Attribute, Whitespace, Operator, Whitespace)),
  710. # Assignment with environment variables and similar, e.g. "something" = ...
  711. # or key value assignment, e.g. "SlotName" : ...
  712. (r'(\s*)("\S+")(\s*)([=:])(\s*)',
  713. bygroups(Whitespace, Literal.String.Double, Whitespace, Operator, Whitespace)),
  714. # Functions, e.g. jsonencode(element("value"))
  715. (builtins_re + r'(\()', bygroups(Name.Function, Punctuation)),
  716. # List of attributes, e.g. ignore_changes = [last_modified, filename]
  717. (r'(\[)([a-z_,\s]+)(\])', bygroups(Punctuation, Name.Builtin, Punctuation)),
  718. # e.g. resource "aws_security_group" "allow_tls" {
  719. # e.g. backend "consul" {
  720. (classes_re + r'(\s+)("[0-9a-zA-Z-_]+")?(\s*)("[0-9a-zA-Z-_]+")(\s+)(\{)',
  721. bygroups(Keyword.Reserved, Whitespace, Name.Class, Whitespace, Name.Variable, Whitespace, Punctuation)),
  722. # here-doc style delimited strings
  723. (r'(<<-?)\s*([a-zA-Z_]\w*)(.*?\n)', heredoc_callback),
  724. ],
  725. 'identifier': [
  726. (r'\b(var\.[0-9a-zA-Z-_\.\[\]]+)\b', bygroups(Name.Variable)),
  727. (r'\b([0-9a-zA-Z-_\[\]]+\.[0-9a-zA-Z-_\.\[\]]+)\b',
  728. bygroups(Name.Variable)),
  729. ],
  730. 'punctuation': [
  731. (r'[\[\]()\{\},.?:!=]', Punctuation),
  732. ],
  733. 'comment': [
  734. (r'[^*/]', Comment.Multiline),
  735. (r'/\*', Comment.Multiline, '#push'),
  736. (r'\*/', Comment.Multiline, '#pop'),
  737. (r'[*/]', Comment.Multiline)
  738. ],
  739. 'whitespace': [
  740. (r'\n', Whitespace),
  741. (r'\s+', Whitespace),
  742. (r'(\\)(\n)', bygroups(Text, Whitespace)),
  743. ],
  744. }
  745. class TermcapLexer(RegexLexer):
  746. """
  747. Lexer for termcap database source.
  748. This is very simple and minimal.
  749. .. versionadded:: 2.1
  750. """
  751. name = 'Termcap'
  752. aliases = ['termcap']
  753. filenames = ['termcap', 'termcap.src']
  754. mimetypes = []
  755. # NOTE:
  756. # * multiline with trailing backslash
  757. # * separator is ':'
  758. # * to embed colon as data, we must use \072
  759. # * space after separator is not allowed (mayve)
  760. tokens = {
  761. 'root': [
  762. (r'^#.*', Comment),
  763. (r'^[^\s#:|]+', Name.Tag, 'names'),
  764. (r'\s+', Whitespace),
  765. ],
  766. 'names': [
  767. (r'\n', Whitespace, '#pop'),
  768. (r':', Punctuation, 'defs'),
  769. (r'\|', Punctuation),
  770. (r'[^:|]+', Name.Attribute),
  771. ],
  772. 'defs': [
  773. (r'(\\)(\n[ \t]*)', bygroups(Text, Whitespace)),
  774. (r'\n[ \t]*', Whitespace, '#pop:2'),
  775. (r'(#)([0-9]+)', bygroups(Operator, Number)),
  776. (r'=', Operator, 'data'),
  777. (r':', Punctuation),
  778. (r'[^\s:=#]+', Name.Class),
  779. ],
  780. 'data': [
  781. (r'\\072', Literal),
  782. (r':', Punctuation, '#pop'),
  783. (r'[^:\\]+', Literal), # for performance
  784. (r'.', Literal),
  785. ],
  786. }
  787. class TerminfoLexer(RegexLexer):
  788. """
  789. Lexer for terminfo database source.
  790. This is very simple and minimal.
  791. .. versionadded:: 2.1
  792. """
  793. name = 'Terminfo'
  794. aliases = ['terminfo']
  795. filenames = ['terminfo', 'terminfo.src']
  796. mimetypes = []
  797. # NOTE:
  798. # * multiline with leading whitespace
  799. # * separator is ','
  800. # * to embed comma as data, we can use \,
  801. # * space after separator is allowed
  802. tokens = {
  803. 'root': [
  804. (r'^#.*$', Comment),
  805. (r'^[^\s#,|]+', Name.Tag, 'names'),
  806. (r'\s+', Whitespace),
  807. ],
  808. 'names': [
  809. (r'\n', Whitespace, '#pop'),
  810. (r'(,)([ \t]*)', bygroups(Punctuation, Whitespace), 'defs'),
  811. (r'\|', Punctuation),
  812. (r'[^,|]+', Name.Attribute),
  813. ],
  814. 'defs': [
  815. (r'\n[ \t]+', Whitespace),
  816. (r'\n', Whitespace, '#pop:2'),
  817. (r'(#)([0-9]+)', bygroups(Operator, Number)),
  818. (r'=', Operator, 'data'),
  819. (r'(,)([ \t]*)', bygroups(Punctuation, Whitespace)),
  820. (r'[^\s,=#]+', Name.Class),
  821. ],
  822. 'data': [
  823. (r'\\[,\\]', Literal),
  824. (r'(,)([ \t]*)', bygroups(Punctuation, Whitespace), '#pop'),
  825. (r'[^\\,]+', Literal), # for performance
  826. (r'.', Literal),
  827. ],
  828. }
  829. class PkgConfigLexer(RegexLexer):
  830. """
  831. Lexer for pkg-config
  832. (see also `manual page <http://linux.die.net/man/1/pkg-config>`_).
  833. .. versionadded:: 2.1
  834. """
  835. name = 'PkgConfig'
  836. url = 'http://www.freedesktop.org/wiki/Software/pkg-config/'
  837. aliases = ['pkgconfig']
  838. filenames = ['*.pc']
  839. mimetypes = []
  840. tokens = {
  841. 'root': [
  842. (r'#.*$', Comment.Single),
  843. # variable definitions
  844. (r'^(\w+)(=)', bygroups(Name.Attribute, Operator)),
  845. # keyword lines
  846. (r'^([\w.]+)(:)',
  847. bygroups(Name.Tag, Punctuation), 'spvalue'),
  848. # variable references
  849. include('interp'),
  850. # fallback
  851. (r'\s+', Whitespace),
  852. (r'[^${}#=:\n.]+', Text),
  853. (r'.', Text),
  854. ],
  855. 'interp': [
  856. # you can escape literal "$" as "$$"
  857. (r'\$\$', Text),
  858. # variable references
  859. (r'\$\{', String.Interpol, 'curly'),
  860. ],
  861. 'curly': [
  862. (r'\}', String.Interpol, '#pop'),
  863. (r'\w+', Name.Attribute),
  864. ],
  865. 'spvalue': [
  866. include('interp'),
  867. (r'#.*$', Comment.Single, '#pop'),
  868. (r'\n', Whitespace, '#pop'),
  869. # fallback
  870. (r'\s+', Whitespace),
  871. (r'[^${}#\n\s]+', Text),
  872. (r'.', Text),
  873. ],
  874. }
  875. class PacmanConfLexer(RegexLexer):
  876. """
  877. Lexer for pacman.conf.
  878. Actually, IniLexer works almost fine for this format,
  879. but it yield error token. It is because pacman.conf has
  880. a form without assignment like:
  881. UseSyslog
  882. Color
  883. TotalDownload
  884. CheckSpace
  885. VerbosePkgLists
  886. These are flags to switch on.
  887. .. versionadded:: 2.1
  888. """
  889. name = 'PacmanConf'
  890. url = 'https://www.archlinux.org/pacman/pacman.conf.5.html'
  891. aliases = ['pacmanconf']
  892. filenames = ['pacman.conf']
  893. mimetypes = []
  894. tokens = {
  895. 'root': [
  896. # comment
  897. (r'#.*$', Comment.Single),
  898. # section header
  899. (r'^(\s*)(\[.*?\])(\s*)$', bygroups(Whitespace, Keyword, Whitespace)),
  900. # variable definitions
  901. # (Leading space is allowed...)
  902. (r'(\w+)(\s*)(=)',
  903. bygroups(Name.Attribute, Whitespace, Operator)),
  904. # flags to on
  905. (r'^(\s*)(\w+)(\s*)$',
  906. bygroups(Whitespace, Name.Attribute, Whitespace)),
  907. # built-in special values
  908. (words((
  909. '$repo', # repository
  910. '$arch', # architecture
  911. '%o', # outfile
  912. '%u', # url
  913. ), suffix=r'\b'),
  914. Name.Variable),
  915. # fallback
  916. (r'\s+', Whitespace),
  917. (r'.', Text),
  918. ],
  919. }
  920. class AugeasLexer(RegexLexer):
  921. """
  922. Lexer for Augeas.
  923. .. versionadded:: 2.4
  924. """
  925. name = 'Augeas'
  926. url = 'http://augeas.net'
  927. aliases = ['augeas']
  928. filenames = ['*.aug']
  929. tokens = {
  930. 'root': [
  931. (r'(module)(\s*)([^\s=]+)', bygroups(Keyword.Namespace, Whitespace, Name.Namespace)),
  932. (r'(let)(\s*)([^\s=]+)', bygroups(Keyword.Declaration, Whitespace, Name.Variable)),
  933. (r'(del|store|value|counter|seq|key|label|autoload|incl|excl|transform|test|get|put)(\s+)', bygroups(Name.Builtin, Whitespace)),
  934. (r'(\()([^:]+)(\:)(unit|string|regexp|lens|tree|filter)(\))', bygroups(Punctuation, Name.Variable, Punctuation, Keyword.Type, Punctuation)),
  935. (r'\(\*', Comment.Multiline, 'comment'),
  936. (r'[*+\-.;=?|]', Operator),
  937. (r'[()\[\]{}]', Operator),
  938. (r'"', String.Double, 'string'),
  939. (r'\/', String.Regex, 'regex'),
  940. (r'([A-Z]\w*)(\.)(\w+)', bygroups(Name.Namespace, Punctuation, Name.Variable)),
  941. (r'.', Name.Variable),
  942. (r'\s+', Whitespace),
  943. ],
  944. 'string': [
  945. (r'\\.', String.Escape),
  946. (r'[^"]', String.Double),
  947. (r'"', String.Double, '#pop'),
  948. ],
  949. 'regex': [
  950. (r'\\.', String.Escape),
  951. (r'[^/]', String.Regex),
  952. (r'\/', String.Regex, '#pop'),
  953. ],
  954. 'comment': [
  955. (r'[^*)]', Comment.Multiline),
  956. (r'\(\*', Comment.Multiline, '#push'),
  957. (r'\*\)', Comment.Multiline, '#pop'),
  958. (r'[)*]', Comment.Multiline)
  959. ],
  960. }
  961. class TOMLLexer(RegexLexer):
  962. """
  963. Lexer for TOML, a simple language
  964. for config files.
  965. .. versionadded:: 2.4
  966. """
  967. name = 'TOML'
  968. url = 'https://github.com/toml-lang/toml'
  969. aliases = ['toml']
  970. filenames = ['*.toml', 'Pipfile', 'poetry.lock']
  971. tokens = {
  972. 'root': [
  973. # Table
  974. (r'^(\s*)(\[.*?\])$', bygroups(Whitespace, Keyword)),
  975. # Basics, comments, strings
  976. (r'[ \t]+', Whitespace),
  977. (r'\n', Whitespace),
  978. (r'#.*?$', Comment.Single),
  979. # Basic string
  980. (r'"(\\\\|\\[^\\]|[^"\\])*"', String),
  981. # Literal string
  982. (r'\'\'\'(.*)\'\'\'', String),
  983. (r'\'[^\']*\'', String),
  984. (r'(true|false)$', Keyword.Constant),
  985. (r'[a-zA-Z_][\w\-]*', Name),
  986. # Datetime
  987. # TODO this needs to be expanded, as TOML is rather flexible:
  988. # https://github.com/toml-lang/toml#offset-date-time
  989. (r'\d{4}-\d{2}-\d{2}(?:T| )\d{2}:\d{2}:\d{2}(?:Z|[-+]\d{2}:\d{2})', Number.Integer),
  990. # Numbers
  991. (r'(\d+\.\d*|\d*\.\d+)([eE][+-]?[0-9]+)?j?', Number.Float),
  992. (r'\d+[eE][+-]?[0-9]+j?', Number.Float),
  993. # Handle +-inf, +-infinity, +-nan
  994. (r'[+-]?(?:(inf(?:inity)?)|nan)', Number.Float),
  995. (r'[+-]?\d+', Number.Integer),
  996. # Punctuation
  997. (r'[]{}:(),;[]', Punctuation),
  998. (r'\.', Punctuation),
  999. # Operators
  1000. (r'=', Operator)
  1001. ]
  1002. }
  1003. class NestedTextLexer(RegexLexer):
  1004. """
  1005. Lexer for *NextedText*, a human-friendly data format.
  1006. .. versionadded:: 2.9
  1007. .. versionchanged:: 2.16
  1008. Added support for *NextedText* v3.0.
  1009. """
  1010. name = 'NestedText'
  1011. url = 'https://nestedtext.org'
  1012. aliases = ['nestedtext', 'nt']
  1013. filenames = ['*.nt']
  1014. tokens = {
  1015. 'root': [
  1016. # Comment: # ...
  1017. (r'^([ ]*)(#.*)$', bygroups(Whitespace, Comment)),
  1018. # Inline dictionary: {...}
  1019. (r'^([ ]*)(\{)', bygroups(Whitespace, Punctuation), 'inline_dict'),
  1020. # Inline list: [...]
  1021. (r'^([ ]*)(\[)', bygroups(Whitespace, Punctuation), 'inline_list'),
  1022. # empty multiline string item: >
  1023. (r'^([ ]*)(>)$', bygroups(Whitespace, Punctuation)),
  1024. # multiline string item: > ...
  1025. (r'^([ ]*)(>)( )(.*?)([ \t]*)$', bygroups(Whitespace, Punctuation, Whitespace, Text, Whitespace)),
  1026. # empty list item: -
  1027. (r'^([ ]*)(-)$', bygroups(Whitespace, Punctuation)),
  1028. # list item: - ...
  1029. (r'^([ ]*)(-)( )(.*?)([ \t]*)$', bygroups(Whitespace, Punctuation, Whitespace, Text, Whitespace)),
  1030. # empty multiline key item: :
  1031. (r'^([ ]*)(:)$', bygroups(Whitespace, Punctuation)),
  1032. # multiline key item: : ...
  1033. (r'^([ ]*)(:)( )([^\n]*?)([ \t]*)$', bygroups(Whitespace, Punctuation, Whitespace, Name.Tag, Whitespace)),
  1034. # empty dict key item: ...:
  1035. (r'^([ ]*)([^\{\[\s].*?)(:)$', bygroups(Whitespace, Name.Tag, Punctuation)),
  1036. # dict key item: ...: ...
  1037. (r'^([ ]*)([^\{\[\s].*?)(:)( )(.*?)([ \t]*)$', bygroups(Whitespace, Name.Tag, Punctuation, Whitespace, Text, Whitespace)),
  1038. ],
  1039. 'inline_list': [
  1040. include('whitespace'),
  1041. (r'[^\{\}\[\],\s]+', Text),
  1042. include('inline_value'),
  1043. (r',', Punctuation),
  1044. (r'\]', Punctuation, '#pop'),
  1045. (r'\n', Error, '#pop'),
  1046. ],
  1047. 'inline_dict': [
  1048. include('whitespace'),
  1049. (r'[^\{\}\[\],:\s]+', Name.Tag),
  1050. (r':', Punctuation, 'inline_dict_value'),
  1051. (r'\}', Punctuation, '#pop'),
  1052. (r'\n', Error, '#pop'),
  1053. ],
  1054. 'inline_dict_value': [
  1055. include('whitespace'),
  1056. (r'[^\{\}\[\],:\s]+', Text),
  1057. include('inline_value'),
  1058. (r',', Punctuation, '#pop'),
  1059. (r'\}', Punctuation, '#pop:2'),
  1060. ],
  1061. 'inline_value': [
  1062. include('whitespace'),
  1063. (r'\{', Punctuation, 'inline_dict'),
  1064. (r'\[', Punctuation, 'inline_list'),
  1065. ],
  1066. 'whitespace': [
  1067. (r'[ \t]+', Whitespace),
  1068. ],
  1069. }
  1070. class SingularityLexer(RegexLexer):
  1071. """
  1072. Lexer for Singularity definition files.
  1073. .. versionadded:: 2.6
  1074. """
  1075. name = 'Singularity'
  1076. url = 'https://www.sylabs.io/guides/3.0/user-guide/definition_files.html'
  1077. aliases = ['singularity']
  1078. filenames = ['*.def', 'Singularity']
  1079. flags = re.IGNORECASE | re.MULTILINE | re.DOTALL
  1080. _headers = r'^(\s*)(bootstrap|from|osversion|mirrorurl|include|registry|namespace|includecmd)(:)'
  1081. _section = r'^(%(?:pre|post|setup|environment|help|labels|test|runscript|files|startscript))(\s*)'
  1082. _appsect = r'^(%app(?:install|help|run|labels|env|test|files))(\s*)'
  1083. tokens = {
  1084. 'root': [
  1085. (_section, bygroups(Generic.Heading, Whitespace), 'script'),
  1086. (_appsect, bygroups(Generic.Heading, Whitespace), 'script'),
  1087. (_headers, bygroups(Whitespace, Keyword, Text)),
  1088. (r'\s*#.*?\n', Comment),
  1089. (r'\b(([0-9]+\.?[0-9]*)|(\.[0-9]+))\b', Number),
  1090. (r'[ \t]+', Whitespace),
  1091. (r'(?!^\s*%).', Text),
  1092. ],
  1093. 'script': [
  1094. (r'(.+?(?=^\s*%))|(.*)', using(BashLexer), '#pop'),
  1095. ],
  1096. }
  1097. def analyse_text(text):
  1098. """This is a quite simple script file, but there are a few keywords
  1099. which seem unique to this language."""
  1100. result = 0
  1101. if re.search(r'\b(?:osversion|includecmd|mirrorurl)\b', text, re.IGNORECASE):
  1102. result += 0.5
  1103. if re.search(SingularityLexer._section[1:], text):
  1104. result += 0.49
  1105. return result
  1106. class UnixConfigLexer(RegexLexer):
  1107. """
  1108. Lexer for Unix/Linux config files using colon-separated values, e.g.
  1109. * ``/etc/group``
  1110. * ``/etc/passwd``
  1111. * ``/etc/shadow``
  1112. .. versionadded:: 2.12
  1113. """
  1114. name = 'Unix/Linux config files'
  1115. aliases = ['unixconfig', 'linuxconfig']
  1116. filenames = []
  1117. tokens = {
  1118. 'root': [
  1119. (r'^#.*', Comment),
  1120. (r'\n', Whitespace),
  1121. (r':', Punctuation),
  1122. (r'[0-9]+', Number),
  1123. (r'((?!\n)[a-zA-Z0-9\_\-\s\(\),]){2,}', Text),
  1124. (r'[^:\n]+', String),
  1125. ],
  1126. }