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

1""" 

2 pygments.lexers.configs 

3 ~~~~~~~~~~~~~~~~~~~~~~~ 

4 

5 Lexers for configuration file formats. 

6 

7 :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. 

8 :license: BSD, see LICENSE for details. 

9""" 

10 

11import re 

12 

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 

19 

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'] 

26 

27 

28class IniLexer(RegexLexer): 

29 """ 

30 Lexer for configuration files in INI style. 

31 """ 

32 

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'] 

43 

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 } 

65 

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] == ']' 

71 

72 

73class RegeditLexer(RegexLexer): 

74 """ 

75 Lexer for Windows Registry files produced by regedit. 

76 

77 .. versionadded:: 1.6 

78 """ 

79 

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'] 

85 

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 } 

111 

112 def analyse_text(text): 

113 return text.startswith('Windows Registry Editor') 

114 

115 

116class PropertiesLexer(RegexLexer): 

117 """ 

118 Lexer for configuration files in Java's properties format. 

119 

120 Note: trailing whitespace counts as part of the value as per spec 

121 

122 .. versionadded:: 1.4 

123 """ 

124 

125 name = 'Properties' 

126 aliases = ['properties', 'jproperties'] 

127 filenames = ['*.properties'] 

128 mimetypes = ['text/x-java-properties'] 

129 

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 } 

170 

171 

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) 

190 

191 

192class KconfigLexer(RegexLexer): 

193 """ 

194 For Linux-style Kconfig files. 

195 

196 .. versionadded:: 1.6 

197 """ 

198 

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 

207 

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) 

211 

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 ] 

220 

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 } 

267 

268 

269class Cfengine3Lexer(RegexLexer): 

270 """ 

271 Lexer for CFEngine3 policy files. 

272 

273 .. versionadded:: 1.5 

274 """ 

275 

276 name = 'CFEngine3' 

277 url = 'http://cfengine.org' 

278 aliases = ['cfengine3', 'cf3'] 

279 filenames = ['*.cf'] 

280 mimetypes = [] 

281 

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 } 

329 

330 

331class ApacheConfLexer(RegexLexer): 

332 """ 

333 Lexer for configuration files following the Apache config file 

334 format. 

335 

336 .. versionadded:: 0.6 

337 """ 

338 

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 

344 

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 } 

372 

373 

374class SquidConfLexer(RegexLexer): 

375 """ 

376 Lexer for squid configuration files. 

377 

378 .. versionadded:: 0.9 

379 """ 

380 

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 

387 

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 ) 

446 

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 ) 

453 

454 actions = ( 

455 "shutdown", "info", "parameter", "server_list", "client_list", 

456 r'squid.conf', 

457 ) 

458 

459 actions_stats = ( 

460 "objects", "vm_objects", "utilization", "ipcache", "fqdncache", "dns", 

461 "redirector", "io", "reply_headers", "filedescriptors", "netdb", 

462 ) 

463 

464 actions_log = ("status", "enable", "disable", "clear") 

465 

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 ) 

471 

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 ) 

481 

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 } 

503 

504 

505class NginxConfLexer(RegexLexer): 

506 """ 

507 Lexer for Nginx configuration files. 

508 

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'] 

516 

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 } 

550 

551 

552class LighttpdConfLexer(RegexLexer): 

553 """ 

554 Lexer for Lighttpd configuration files. 

555 

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'] 

563 

564 tokens = { 

565 'root': [ 

566 (r'#.*\n', Comment.Single), 

567 (r'/\S*', Name), # pathname 

568 (r'[a-zA-Z._-]+', Keyword), 

569 (r'\d+\.\d+\.\d+\.\d+(?:/\d+)?', Number), 

570 (r'[0-9]+', Number), 

571 (r'=>|=~|\+=|==|=|\+', Operator), 

572 (r'\$[A-Z]+', Name.Builtin), 

573 (r'[(){}\[\],]', Punctuation), 

574 (r'"([^"\\]*(?:\\.[^"\\]*)*)"', String.Double), 

575 (r'\s+', Whitespace), 

576 ], 

577 

578 } 

579 

580 

581class DockerLexer(RegexLexer): 

582 """ 

583 Lexer for Docker configuration files. 

584 

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'] 

592 

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 

597 

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 } 

615 

616 

617class TerraformLexer(ExtendedRegexLexer): 

618 """ 

619 Lexer for terraformi ``.tf`` files. 

620 

621 .. versionadded:: 2.1 

622 """ 

623 

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'] 

629 

630 classes = ('backend', 'data', 'module', 'output', 'provider', 

631 'provisioner', 'resource', 'variable') 

632 classes_re = "({})".format(('|').join(classes)) 

633 

634 types = ('string', 'number', 'bool', 'list', 'tuple', 'map', 'set', 'object', 'null') 

635 

636 numeric_functions = ('abs', 'ceil', 'floor', 'log', 'max', 

637 'mix', 'parseint', 'pow', 'signum') 

638 

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 ) 

644 

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 ) 

653 

654 encoding_functions = ('base64decode', 'base64encode', 'base64gzip', 

655 'csvdecode', 'jsondecode', 'jsonencode', 'textdecodebase64', 

656 'textencodebase64', 'urlencode', 'yamldecode', 'yamlencode') 

657 

658 filesystem_functions = ('abspath', 'dirname', 'pathexpand', 'basename', 

659 'file', 'fileexists', 'fileset', 'filebase64', 'templatefile') 

660 

661 date_time_functions = ('formatdate', 'timeadd', 'timestamp') 

662 

663 hash_crypto_functions = ('base64sha256', 'base64sha512', 'bcrypt', 'filebase64sha256', 

664 'filebase64sha512', 'filemd5', 'filesha1', 'filesha256', 'filesha512', 

665 'md5', 'rsadecrypt', 'sha1', 'sha256', 'sha512', 'uuid', 'uuidv5') 

666 

667 ip_network_functions = ('cidrhost', 'cidrnetmask', 'cidrsubnet', 'cidrsubnets') 

668 

669 type_conversion_functions = ('can', 'defaults', 'tobool', 'tolist', 'tomap', 

670 'tonumber', 'toset', 'tostring', 'try') 

671 

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)) 

676 

677 def heredoc_callback(self, match, ctx): 

678 # Parse a terraform heredoc 

679 # match: 1 = <<[-]?, 2 = name 3 = rest of line 

680 

681 start = match.start(1) 

682 yield start, Operator, match.group(1) # <<[-]? 

683 yield match.start(2), String.Delimiter, match.group(2) # heredoc name 

684 

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() 

689 

690 hdname = match.group(2) 

691 tolerant = True # leading whitespace is always accepted 

692 

693 lines = [] 

694 

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) 

713 

714 tokens = { 

715 'root': [ 

716 include('basic'), 

717 include('whitespace'), 

718 

719 # Strings 

720 (r'(".*")', bygroups(String.Double)), 

721 

722 # Constants 

723 (words(('true', 'false'), prefix=r'\b', suffix=r'\b'), Name.Constant), 

724 

725 # Types 

726 (words(types, prefix=r'\b', suffix=r'\b'), Keyword.Type), 

727 

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'), 

736 

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)), 

741 

742 # Assignment with attributes, e.g. something = ... 

743 (r'(\s*)([0-9a-zA-Z-_]+)(\s*)(=)(\s*)', 

744 bygroups(Whitespace, Name.Attribute, Whitespace, Operator, Whitespace)), 

745 

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)), 

750 

751 # Functions, e.g. jsonencode(element("value")) 

752 (builtins_re + r'(\()', bygroups(Name.Function, Punctuation)), 

753 

754 # List of attributes, e.g. ignore_changes = [last_modified, filename] 

755 (r'(\[)([a-z_,\s]+)(\])', bygroups(Punctuation, Name.Builtin, Punctuation)), 

756 

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)), 

761 

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 } 

785 

786 

787class TermcapLexer(RegexLexer): 

788 """ 

789 Lexer for termcap database source. 

790 

791 This is very simple and minimal. 

792 

793 .. versionadded:: 2.1 

794 """ 

795 name = 'Termcap' 

796 aliases = ['termcap'] 

797 filenames = ['termcap', 'termcap.src'] 

798 mimetypes = [] 

799 

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 } 

832 

833 

834class TerminfoLexer(RegexLexer): 

835 """ 

836 Lexer for terminfo database source. 

837 

838 This is very simple and minimal. 

839 

840 .. versionadded:: 2.1 

841 """ 

842 name = 'Terminfo' 

843 aliases = ['terminfo'] 

844 filenames = ['terminfo', 'terminfo.src'] 

845 mimetypes = [] 

846 

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 } 

879 

880 

881class PkgConfigLexer(RegexLexer): 

882 """ 

883 Lexer for pkg-config 

884 (see also `manual page <http://linux.die.net/man/1/pkg-config>`_). 

885 

886 .. versionadded:: 2.1 

887 """ 

888 

889 name = 'PkgConfig' 

890 url = 'http://www.freedesktop.org/wiki/Software/pkg-config/' 

891 aliases = ['pkgconfig'] 

892 filenames = ['*.pc'] 

893 mimetypes = [] 

894 

895 tokens = { 

896 'root': [ 

897 (r'#.*$', Comment.Single), 

898 

899 # variable definitions 

900 (r'^(\w+)(=)', bygroups(Name.Attribute, Operator)), 

901 

902 # keyword lines 

903 (r'^([\w.]+)(:)', 

904 bygroups(Name.Tag, Punctuation), 'spvalue'), 

905 

906 # variable references 

907 include('interp'), 

908 

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), 

917 

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'), 

927 

928 (r'#.*$', Comment.Single, '#pop'), 

929 (r'\n', Whitespace, '#pop'), 

930 

931 # fallback 

932 (r'\s+', Whitespace), 

933 (r'[^${}#\n\s]+', Text), 

934 (r'.', Text), 

935 ], 

936 } 

937 

938 

939class PacmanConfLexer(RegexLexer): 

940 """ 

941 Lexer for pacman.conf. 

942 

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: 

946 

947 UseSyslog 

948 Color 

949 TotalDownload 

950 CheckSpace 

951 VerbosePkgLists 

952 

953 These are flags to switch on. 

954 

955 .. versionadded:: 2.1 

956 """ 

957 

958 name = 'PacmanConf' 

959 url = 'https://www.archlinux.org/pacman/pacman.conf.5.html' 

960 aliases = ['pacmanconf'] 

961 filenames = ['pacman.conf'] 

962 mimetypes = [] 

963 

964 tokens = { 

965 'root': [ 

966 # comment 

967 (r'#.*$', Comment.Single), 

968 

969 # section header 

970 (r'^(\s*)(\[.*?\])(\s*)$', bygroups(Whitespace, Keyword, Whitespace)), 

971 

972 # variable definitions 

973 # (Leading space is allowed...) 

974 (r'(\w+)(\s*)(=)', 

975 bygroups(Name.Attribute, Whitespace, Operator)), 

976 

977 # flags to on 

978 (r'^(\s*)(\w+)(\s*)$', 

979 bygroups(Whitespace, Name.Attribute, Whitespace)), 

980 

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), 

989 

990 # fallback 

991 (r'\s+', Whitespace), 

992 (r'.', Text), 

993 ], 

994 } 

995 

996 

997class AugeasLexer(RegexLexer): 

998 """ 

999 Lexer for Augeas. 

1000 

1001 .. versionadded:: 2.4 

1002 """ 

1003 name = 'Augeas' 

1004 url = 'http://augeas.net' 

1005 aliases = ['augeas'] 

1006 filenames = ['*.aug'] 

1007 

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 } 

1040 

1041 

1042class TOMLLexer(RegexLexer): 

1043 """ 

1044 Lexer for TOML, a simple language 

1045 for config files. 

1046 

1047 .. versionadded:: 2.4 

1048 """ 

1049 

1050 name = 'TOML' 

1051 url = 'https://github.com/toml-lang/toml' 

1052 aliases = ['toml'] 

1053 filenames = ['*.toml', 'Pipfile', 'poetry.lock'] 

1054 

1055 tokens = { 

1056 'root': [ 

1057 # Table 

1058 (r'^(\s*)(\[.*?\])$', bygroups(Whitespace, Keyword)), 

1059 

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), 

1071 

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), 

1076 

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), 

1083 

1084 # Punctuation 

1085 (r'[]{}:(),;[]', Punctuation), 

1086 (r'\.', Punctuation), 

1087 

1088 # Operators 

1089 (r'=', Operator) 

1090 

1091 ] 

1092 } 

1093 

1094class NestedTextLexer(RegexLexer): 

1095 """ 

1096 Lexer for NextedText, a human-friendly data 

1097 format. 

1098 

1099 .. versionadded:: 2.9 

1100 """ 

1101 

1102 name = 'NestedText' 

1103 url = 'https://nestedtext.org' 

1104 aliases = ['nestedtext', 'nt'] 

1105 filenames = ['*.nt'] 

1106 

1107 _quoted_dict_item = r'^(\s*)({0})(.*?)({0}: ?)(.*?)(\s*)$' 

1108 

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 } 

1119 

1120 

1121class SingularityLexer(RegexLexer): 

1122 """ 

1123 Lexer for Singularity definition files. 

1124 

1125 .. versionadded:: 2.6 

1126 """ 

1127 

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 

1133 

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*)' 

1137 

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 } 

1152 

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 

1159 

1160 if re.search(SingularityLexer._section[1:], text): 

1161 result += 0.49 

1162 

1163 return result 

1164 

1165 

1166class UnixConfigLexer(RegexLexer): 

1167 """ 

1168 Lexer for Unix/Linux config files using colon-separated values, e.g. 

1169 

1170 * ``/etc/group`` 

1171 * ``/etc/passwd`` 

1172 * ``/etc/shadow`` 

1173 

1174 .. versionadded:: 2.12 

1175 """ 

1176 

1177 name = 'Unix/Linux config files' 

1178 aliases = ['unixconfig', 'linuxconfig'] 

1179 filenames = [] 

1180 

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 }