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

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

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 ] 

38 mimetypes = ['text/x-ini', 'text/inf'] 

39 

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 } 

61 

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 

69 

70 

71class DesktopLexer(RegexLexer): 

72 """ 

73 Lexer for .desktop files. 

74 

75 .. versionadded:: 2.16 

76 """ 

77 

78 name = 'Desktop file' 

79 url = "https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html" 

80 aliases = ['desktop'] 

81 filenames = ['*.desktop'] 

82 

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 } 

92 

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 

99 

100 

101class SystemdLexer(RegexLexer): 

102 """ 

103 Lexer for systemd unit files. 

104 

105 .. versionadded:: 2.16 

106 """ 

107 

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 ] 

115 

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 } 

137 

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 

144 

145 

146class RegeditLexer(RegexLexer): 

147 """ 

148 Lexer for Windows Registry files produced by regedit. 

149 

150 .. versionadded:: 1.6 

151 """ 

152 

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

158 

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 } 

184 

185 def analyse_text(text): 

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

187 

188 

189class PropertiesLexer(RegexLexer): 

190 """ 

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

192 

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

194 

195 .. versionadded:: 1.4 

196 """ 

197 

198 name = 'Properties' 

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

200 filenames = ['*.properties'] 

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

202 

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 } 

243 

244 

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) 

263 

264 

265class KconfigLexer(RegexLexer): 

266 """ 

267 For Linux-style Kconfig files. 

268 

269 .. versionadded:: 1.6 

270 """ 

271 

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 

280 

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) 

284 

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 ] 

293 

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 } 

340 

341 

342class Cfengine3Lexer(RegexLexer): 

343 """ 

344 Lexer for CFEngine3 policy files. 

345 

346 .. versionadded:: 1.5 

347 """ 

348 

349 name = 'CFEngine3' 

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

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

352 filenames = ['*.cf'] 

353 mimetypes = [] 

354 

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 } 

402 

403 

404class ApacheConfLexer(RegexLexer): 

405 """ 

406 Lexer for configuration files following the Apache config file 

407 format. 

408 

409 .. versionadded:: 0.6 

410 """ 

411 

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 

417 

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 } 

445 

446 

447class SquidConfLexer(RegexLexer): 

448 """ 

449 Lexer for squid configuration files. 

450 

451 .. versionadded:: 0.9 

452 """ 

453 

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 

460 

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 ) 

519 

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 ) 

526 

527 actions = ( 

528 "shutdown", "info", "parameter", "server_list", "client_list", 

529 r'squid.conf', 

530 ) 

531 

532 actions_stats = ( 

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

534 "redirector", "io", "reply_headers", "filedescriptors", "netdb", 

535 ) 

536 

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

538 

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 ) 

544 

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 ) 

554 

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 } 

576 

577 

578class NginxConfLexer(RegexLexer): 

579 """ 

580 Lexer for Nginx configuration files. 

581 

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

589 

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 } 

623 

624 

625class LighttpdConfLexer(RegexLexer): 

626 """ 

627 Lexer for Lighttpd configuration files. 

628 

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

636 

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

650 

651 } 

652 

653 

654class DockerLexer(RegexLexer): 

655 """ 

656 Lexer for Docker configuration files. 

657 

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

665 

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 

670 

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 } 

688 

689 

690class TerraformLexer(ExtendedRegexLexer): 

691 """ 

692 Lexer for terraformi ``.tf`` files. 

693 

694 .. versionadded:: 2.1 

695 """ 

696 

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

702 

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

704 'provisioner', 'resource', 'variable') 

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

706 

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

708 

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

710 'mix', 'parseint', 'pow', 'signum') 

711 

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 ) 

717 

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 ) 

726 

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

728 'csvdecode', 'jsondecode', 'jsonencode', 'textdecodebase64', 

729 'textencodebase64', 'urlencode', 'yamldecode', 'yamlencode') 

730 

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

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

733 

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

735 

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

737 'filebase64sha512', 'filemd5', 'filesha1', 'filesha256', 'filesha512', 

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

739 

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

741 

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

743 'tonumber', 'toset', 'tostring', 'try') 

744 

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

749 

750 def heredoc_callback(self, match, ctx): 

751 # Parse a terraform heredoc 

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

753 

754 start = match.start(1) 

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

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

757 

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

762 

763 hdname = match.group(2) 

764 tolerant = True # leading whitespace is always accepted 

765 

766 lines = [] 

767 

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) 

786 

787 tokens = { 

788 'root': [ 

789 include('basic'), 

790 include('whitespace'), 

791 

792 # Strings 

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

794 

795 # Constants 

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

797 

798 # Types 

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

800 

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

809 

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

814 

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

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

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

818 

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

823 

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

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

826 

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

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

829 

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

834 

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 } 

858 

859 

860class TermcapLexer(RegexLexer): 

861 """ 

862 Lexer for termcap database source. 

863 

864 This is very simple and minimal. 

865 

866 .. versionadded:: 2.1 

867 """ 

868 name = 'Termcap' 

869 aliases = ['termcap'] 

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

871 mimetypes = [] 

872 

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 } 

905 

906 

907class TerminfoLexer(RegexLexer): 

908 """ 

909 Lexer for terminfo database source. 

910 

911 This is very simple and minimal. 

912 

913 .. versionadded:: 2.1 

914 """ 

915 name = 'Terminfo' 

916 aliases = ['terminfo'] 

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

918 mimetypes = [] 

919 

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 } 

952 

953 

954class PkgConfigLexer(RegexLexer): 

955 """ 

956 Lexer for pkg-config 

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

958 

959 .. versionadded:: 2.1 

960 """ 

961 

962 name = 'PkgConfig' 

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

964 aliases = ['pkgconfig'] 

965 filenames = ['*.pc'] 

966 mimetypes = [] 

967 

968 tokens = { 

969 'root': [ 

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

971 

972 # variable definitions 

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

974 

975 # keyword lines 

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

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

978 

979 # variable references 

980 include('interp'), 

981 

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

990 

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

1000 

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

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

1003 

1004 # fallback 

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

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

1007 (r'.', Text), 

1008 ], 

1009 } 

1010 

1011 

1012class PacmanConfLexer(RegexLexer): 

1013 """ 

1014 Lexer for pacman.conf. 

1015 

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: 

1019 

1020 UseSyslog 

1021 Color 

1022 TotalDownload 

1023 CheckSpace 

1024 VerbosePkgLists 

1025 

1026 These are flags to switch on. 

1027 

1028 .. versionadded:: 2.1 

1029 """ 

1030 

1031 name = 'PacmanConf' 

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

1033 aliases = ['pacmanconf'] 

1034 filenames = ['pacman.conf'] 

1035 mimetypes = [] 

1036 

1037 tokens = { 

1038 'root': [ 

1039 # comment 

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

1041 

1042 # section header 

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

1044 

1045 # variable definitions 

1046 # (Leading space is allowed...) 

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

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

1049 

1050 # flags to on 

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

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

1053 

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

1062 

1063 # fallback 

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

1065 (r'.', Text), 

1066 ], 

1067 } 

1068 

1069 

1070class AugeasLexer(RegexLexer): 

1071 """ 

1072 Lexer for Augeas. 

1073 

1074 .. versionadded:: 2.4 

1075 """ 

1076 name = 'Augeas' 

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

1078 aliases = ['augeas'] 

1079 filenames = ['*.aug'] 

1080 

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 } 

1113 

1114 

1115class TOMLLexer(RegexLexer): 

1116 """ 

1117 Lexer for TOML, a simple language 

1118 for config files. 

1119 

1120 .. versionadded:: 2.4 

1121 """ 

1122 

1123 name = 'TOML' 

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

1125 aliases = ['toml'] 

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

1127 

1128 tokens = { 

1129 'root': [ 

1130 # Table 

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

1132 

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

1144 

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

1149 

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

1156 

1157 # Punctuation 

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

1159 (r'\.', Punctuation), 

1160 

1161 # Operators 

1162 (r'=', Operator) 

1163 

1164 ] 

1165 } 

1166 

1167class NestedTextLexer(RegexLexer): 

1168 """ 

1169 Lexer for *NextedText*, a human-friendly data format. 

1170 

1171 .. versionadded:: 2.9 

1172 

1173 .. versionchanged:: 2.16 

1174 Added support for *NextedText* v3.0. 

1175 """ 

1176 

1177 name = 'NestedText' 

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

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

1180 filenames = ['*.nt'] 

1181 

1182 tokens = { 

1183 'root': [ 

1184 # Comment: # ... 

1185 (r'^([ ]*)(#.*)$', bygroups(Whitespace, Comment)), 

1186 

1187 # Inline dictionary: {...} 

1188 (r'^([ ]*)(\{)', bygroups(Whitespace, Punctuation), 'inline_dict'), 

1189 

1190 # Inline list: [...] 

1191 (r'^([ ]*)(\[)', bygroups(Whitespace, Punctuation), 'inline_list'), 

1192 

1193 # empty multiline string item: > 

1194 (r'^([ ]*)(>)$', bygroups(Whitespace, Punctuation)), 

1195 

1196 # multiline string item: > ... 

1197 (r'^([ ]*)(>)( )(.*?)([ \t]*)$', bygroups(Whitespace, Punctuation, Whitespace, Text, Whitespace)), 

1198 

1199 # empty list item: - 

1200 (r'^([ ]*)(-)$', bygroups(Whitespace, Punctuation)), 

1201 

1202 # list item: - ... 

1203 (r'^([ ]*)(-)( )(.*?)([ \t]*)$', bygroups(Whitespace, Punctuation, Whitespace, Text, Whitespace)), 

1204 

1205 # empty multiline key item: : 

1206 (r'^([ ]*)(:)$', bygroups(Whitespace, Punctuation)), 

1207 

1208 # multiline key item: : ... 

1209 (r'^([ ]*)(:)( )([^\n]*?)([ \t]*)$', bygroups(Whitespace, Punctuation, Whitespace, Name.Tag, Whitespace)), 

1210 

1211 # empty dict key item: ...: 

1212 (r'^([ ]*)([^\{\[\s].*?)(:)$', bygroups(Whitespace, Name.Tag, Punctuation)), 

1213 

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 } 

1248 

1249 

1250class SingularityLexer(RegexLexer): 

1251 """ 

1252 Lexer for Singularity definition files. 

1253 

1254 .. versionadded:: 2.6 

1255 """ 

1256 

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 

1262 

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

1266 

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 } 

1281 

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 

1288 

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

1290 result += 0.49 

1291 

1292 return result 

1293 

1294 

1295class UnixConfigLexer(RegexLexer): 

1296 """ 

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

1298 

1299 * ``/etc/group`` 

1300 * ``/etc/passwd`` 

1301 * ``/etc/shadow`` 

1302 

1303 .. versionadded:: 2.12 

1304 """ 

1305 

1306 name = 'Unix/Linux config files' 

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

1308 filenames = [] 

1309 

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 }