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