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