configs.py 37 KB

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