Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pygments/lexers/configs.py: 84%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

291 statements  

1""" 

2 pygments.lexers.configs 

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

4 

5 Lexers for configuration file formats. 

6 

7 :copyright: Copyright 2006-present 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, this, 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 'CaddyfileLexer'] 

27 

28 

29class IniLexer(RegexLexer): 

30 """ 

31 Lexer for configuration files in INI style. 

32 """ 

33 

34 name = 'INI' 

35 aliases = ['ini', 'cfg', 'dosini'] 

36 filenames = [ 

37 '*.ini', '*.cfg', '*.inf', '.editorconfig', 

38 ] 

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

40 url = 'https://en.wikipedia.org/wiki/INI_file' 

41 version_added = '' 

42 

43 tokens = { 

44 'root': [ 

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

46 (r'[;#].*', Comment.Single), 

47 (r'(\[.*?\])([ \t]*)$', bygroups(Keyword, Whitespace)), 

48 (r'''(.*?)([ \t]*)([=:])([ \t]*)(["'])''', 

49 bygroups(Name.Attribute, Whitespace, Operator, Whitespace, String), 

50 "quoted_value"), 

51 (r'(.*?)([ \t]*)([=:])([ \t]*)([^;#\n]*)(\\)(\s+)', 

52 bygroups(Name.Attribute, Whitespace, Operator, Whitespace, String, 

53 Text, Whitespace), 

54 "value"), 

55 (r'(.*?)([ \t]*)([=:])([ \t]*)([^ ;#\n]*(?: +[^ ;#\n]+)*)', 

56 bygroups(Name.Attribute, Whitespace, Operator, Whitespace, String)), 

57 # standalone option, supported by some INI parsers 

58 (r'(.+?)$', Name.Attribute), 

59 ], 

60 'quoted_value': [ 

61 (r'''([^"'\n]*)(["'])(\s*)''', 

62 bygroups(String, String, Whitespace), "#pop"), 

63 (r'[;#].*', Comment.Single), 

64 (r'$', String, "#pop"), 

65 ], 

66 'value': [ # line continuation 

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

68 (r'(\s*)(.*)(\\)([ \t]*)', 

69 bygroups(Whitespace, String, Text, Whitespace)), 

70 (r'.*$', String, "#pop"), 

71 ], 

72 } 

73 

74 def analyse_text(text): 

75 npos = text.find('\n') 

76 if npos < 3: 

77 return False 

78 if text[0] == '[' and text[npos-1] == ']': 

79 return 0.8 

80 return False 

81 

82 

83class DesktopLexer(RegexLexer): 

84 """ 

85 Lexer for .desktop files. 

86 """ 

87 

88 name = 'Desktop file' 

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

90 aliases = ['desktop'] 

91 filenames = ['*.desktop'] 

92 mimetypes = ['application/x-desktop'] 

93 version_added = '2.16' 

94 

95 tokens = { 

96 'root': [ 

97 (r'^[ \t]*\n', Whitespace), 

98 (r'^(#.*)(\n)', bygroups(Comment.Single, Whitespace)), 

99 (r'(\[[^\]\n]+\])(\n)', bygroups(Keyword, Whitespace)), 

100 (r'([-A-Za-z0-9]+)(\[[^\] \t=]+\])?([ \t]*)(=)([ \t]*)([^\n]*)([ \t\n]*\n)', 

101 bygroups(Name.Attribute, Name.Namespace, Whitespace, Operator, Whitespace, String, Whitespace)), 

102 ], 

103 } 

104 

105 def analyse_text(text): 

106 if text.startswith("[Desktop Entry]"): 

107 return 1.0 

108 if re.search(r"^\[Desktop Entry\][ \t]*$", text[:500], re.MULTILINE) is not None: 

109 return 0.9 

110 return 0.0 

111 

112 

113class SystemdLexer(RegexLexer): 

114 """ 

115 Lexer for systemd unit files. 

116 """ 

117 

118 name = 'Systemd' 

119 url = "https://www.freedesktop.org/software/systemd/man/systemd.syntax.html" 

120 aliases = ['systemd'] 

121 filenames = [ 

122 '*.service', '*.socket', '*.device', '*.mount', '*.automount', 

123 '*.swap', '*.target', '*.path', '*.timer', '*.slice', '*.scope', 

124 ] 

125 version_added = '2.16' 

126 

127 tokens = { 

128 'root': [ 

129 (r'^[ \t]*\n', Whitespace), 

130 (r'^([;#].*)(\n)', bygroups(Comment.Single, Whitespace)), 

131 (r'(\[[^\]\n]+\])(\n)', bygroups(Keyword, Whitespace)), 

132 (r'([^=]+)([ \t]*)(=)([ \t]*)([^\n]*)(\\)(\n)', 

133 bygroups(Name.Attribute, Whitespace, Operator, Whitespace, String, 

134 Text, Whitespace), 

135 "value"), 

136 (r'([^=]+)([ \t]*)(=)([ \t]*)([^\n]*)(\n)', 

137 bygroups(Name.Attribute, Whitespace, Operator, Whitespace, String, Whitespace)), 

138 ], 

139 'value': [ 

140 # line continuation 

141 (r'^([;#].*)(\n)', bygroups(Comment.Single, Whitespace)), 

142 (r'([ \t]*)([^\n]*)(\\)(\n)', 

143 bygroups(Whitespace, String, Text, Whitespace)), 

144 (r'([ \t]*)([^\n]*)(\n)', 

145 bygroups(Whitespace, String, Whitespace), "#pop"), 

146 ], 

147 } 

148 

149 def analyse_text(text): 

150 if text.startswith("[Unit]"): 

151 return 1.0 

152 if re.search(r"^\[Unit\][ \t]*$", text[:500], re.MULTILINE) is not None: 

153 return 0.9 

154 return 0.0 

155 

156 

157class RegeditLexer(RegexLexer): 

158 """ 

159 Lexer for Windows Registry files produced by regedit. 

160 """ 

161 

162 name = 'reg' 

163 url = 'http://en.wikipedia.org/wiki/Windows_Registry#.REG_files' 

164 aliases = ['registry'] 

165 filenames = ['*.reg'] 

166 mimetypes = ['text/x-windows-registry'] 

167 version_added = '1.6' 

168 

169 tokens = { 

170 'root': [ 

171 (r'Windows Registry Editor.*', Text), 

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

173 (r'[;#].*', Comment.Single), 

174 (r'(\[)(-?)(HKEY_[A-Z_]+)(.*?\])$', 

175 bygroups(Keyword, Operator, Name.Builtin, Keyword)), 

176 # String keys, which obey somewhat normal escaping 

177 (r'("(?:\\"|\\\\|[^"])+")([ \t]*)(=)([ \t]*)', 

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

179 'value'), 

180 # Bare keys (includes @) 

181 (r'(.*?)([ \t]*)(=)([ \t]*)', 

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

183 'value'), 

184 ], 

185 'value': [ 

186 (r'-', Operator, '#pop'), # delete value 

187 (r'(dword|hex(?:\([0-9a-fA-F]\))?)(:)([0-9a-fA-F,]+)', 

188 bygroups(Name.Variable, Punctuation, Number), '#pop'), 

189 # As far as I know, .reg files do not support line continuation. 

190 (r'.+', String, '#pop'), 

191 default('#pop'), 

192 ] 

193 } 

194 

195 def analyse_text(text): 

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

197 

198 

199class PropertiesLexer(RegexLexer): 

200 """ 

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

202 

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

204 """ 

205 

206 name = 'Properties' 

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

208 filenames = ['*.properties'] 

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

210 url = 'https://en.wikipedia.org/wiki/.properties' 

211 version_added = '1.4' 

212 

213 tokens = { 

214 'root': [ 

215 # comments 

216 (r'[!#].*|/{2}.*', Comment.Single), 

217 # ending a comment or whitespace-only line 

218 (r'\n', Whitespace), 

219 # eat whitespace at the beginning of a line 

220 (r'^[^\S\n]+', Whitespace), 

221 # start lexing a key 

222 default('key'), 

223 ], 

224 'key': [ 

225 # non-escaped key characters 

226 (r'[^\\:=\s]+', Name.Attribute), 

227 # escapes 

228 include('escapes'), 

229 # separator is the first non-escaped whitespace or colon or '=' on the line; 

230 # if it's whitespace, = and : are gobbled after it 

231 (r'([^\S\n]*)([:=])([^\S\n]*)', 

232 bygroups(Whitespace, Operator, Whitespace), 

233 ('#pop', 'value')), 

234 (r'[^\S\n]+', Whitespace, ('#pop', 'value')), 

235 # maybe we got no value after all 

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

237 ], 

238 'value': [ 

239 # non-escaped value characters 

240 (r'[^\\\n]+', String), 

241 # escapes 

242 include('escapes'), 

243 # end the value on an unescaped newline 

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

245 ], 

246 'escapes': [ 

247 # line continuations; these gobble whitespace at the beginning of the next line 

248 (r'(\\\n)([^\S\n]*)', bygroups(String.Escape, Whitespace)), 

249 # other escapes 

250 (r'\\(.|\n)', String.Escape), 

251 ], 

252 } 

253 

254 

255def _rx_indent(level): 

256 # Kconfig *always* interprets a tab as 8 spaces, so this is the default. 

257 # Edit this if you are in an environment where KconfigLexer gets expanded 

258 # input (tabs expanded to spaces) and the expansion tab width is != 8, 

259 # e.g. in connection with Trac (trac.ini, [mimeviewer], tab_width). 

260 # Value range here is 2 <= {tab_width} <= 8. 

261 tab_width = 8 

262 # Regex matching a given indentation {level}, assuming that indentation is 

263 # a multiple of {tab_width}. In other cases there might be problems. 

264 if tab_width == 2: 

265 space_repeat = '+' 

266 else: 

267 space_repeat = '{1,%d}' % (tab_width - 1) 

268 if level == 1: 

269 level_repeat = '' 

270 else: 

271 level_repeat = f'{{{level}}}' 

272 return rf'(?:\t| {space_repeat}\t| {{{tab_width}}}){level_repeat}.*\n' 

273 

274 

275class KconfigLexer(RegexLexer): 

276 """ 

277 For Linux-style Kconfig files. 

278 """ 

279 

280 name = 'Kconfig' 

281 aliases = ['kconfig', 'menuconfig', 'linux-config', 'kernel-config'] 

282 version_added = '1.6' 

283 # Adjust this if new kconfig file names appear in your environment 

284 filenames = ['Kconfig*', '*Config.in*', 'external.in*', 

285 'standard-modules.in'] 

286 mimetypes = ['text/x-kconfig'] 

287 url = 'https://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html' 

288 

289 # No re.MULTILINE, indentation-aware help text needs line-by-line handling 

290 flags = 0 

291 

292 def call_indent(level): 

293 # If indentation >= {level} is detected, enter state 'indent{level}' 

294 return (_rx_indent(level), String.Doc, f'indent{level}') 

295 

296 def do_indent(level): 

297 # Print paragraphs of indentation level >= {level} as String.Doc, 

298 # ignoring blank lines. Then return to 'root' state. 

299 return [ 

300 (_rx_indent(level), String.Doc), 

301 (r'\s*\n', Text), 

302 default('#pop:2') 

303 ] 

304 

305 tokens = { 

306 'root': [ 

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

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

309 (words(( 

310 'mainmenu', 'config', 'menuconfig', 'choice', 'endchoice', 

311 'comment', 'menu', 'endmenu', 'visible if', 'if', 'endif', 

312 'source', 'prompt', 'select', 'depends on', 'default', 

313 'range', 'option'), suffix=r'\b'), 

314 Keyword), 

315 (r'(---help---|help)[\t ]*\n', Keyword, 'help'), 

316 (r'(bool|tristate|string|hex|int|defconfig_list|modules|env)\b', 

317 Name.Builtin), 

318 (r'[!=&|]', Operator), 

319 (r'[()]', Punctuation), 

320 (r'[0-9]+', Number.Integer), 

321 (r"'(''|[^'])*'", String.Single), 

322 (r'"(""|[^"])*"', String.Double), 

323 (r'\S+', Text), 

324 ], 

325 # Help text is indented, multi-line and ends when a lower indentation 

326 # level is detected. 

327 'help': [ 

328 # Skip blank lines after help token, if any 

329 (r'\s*\n', Text), 

330 # Determine the first help line's indentation level heuristically(!). 

331 # Attention: this is not perfect, but works for 99% of "normal" 

332 # indentation schemes up to a max. indentation level of 7. 

333 call_indent(7), 

334 call_indent(6), 

335 call_indent(5), 

336 call_indent(4), 

337 call_indent(3), 

338 call_indent(2), 

339 call_indent(1), 

340 default('#pop'), # for incomplete help sections without text 

341 ], 

342 # Handle text for indentation levels 7 to 1 

343 'indent7': do_indent(7), 

344 'indent6': do_indent(6), 

345 'indent5': do_indent(5), 

346 'indent4': do_indent(4), 

347 'indent3': do_indent(3), 

348 'indent2': do_indent(2), 

349 'indent1': do_indent(1), 

350 } 

351 

352 

353class Cfengine3Lexer(RegexLexer): 

354 """ 

355 Lexer for CFEngine3 policy files. 

356 """ 

357 

358 name = 'CFEngine3' 

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

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

361 filenames = ['*.cf'] 

362 mimetypes = [] 

363 version_added = '1.5' 

364 

365 tokens = { 

366 'root': [ 

367 (r'#.*?\n', Comment), 

368 (r'(body)(\s+)(\S+)(\s+)(control)', 

369 bygroups(Keyword, Whitespace, Keyword, Whitespace, Keyword)), 

370 (r'(body|bundle)(\s+)(\S+)(\s+)(\w+)(\()', 

371 bygroups(Keyword, Whitespace, Keyword, Whitespace, Name.Function, Punctuation), 

372 'arglist'), 

373 (r'(body|bundle)(\s+)(\S+)(\s+)(\w+)', 

374 bygroups(Keyword, Whitespace, Keyword, Whitespace, Name.Function)), 

375 (r'(")([^"]+)(")(\s+)(string|slist|int|real)(\s*)(=>)(\s*)', 

376 bygroups(Punctuation, Name.Variable, Punctuation, 

377 Whitespace, Keyword.Type, Whitespace, Operator, Whitespace)), 

378 (r'(\S+)(\s*)(=>)(\s*)', 

379 bygroups(Keyword.Reserved, Whitespace, Operator, Text)), 

380 (r'"', String, 'string'), 

381 (r'(\w+)(\()', bygroups(Name.Function, Punctuation)), 

382 (r'([\w.!&|()]+)(::)', bygroups(Name.Class, Punctuation)), 

383 (r'(\w+)(:)', bygroups(Keyword.Declaration, Punctuation)), 

384 (r'@[{(][^)}]+[})]', Name.Variable), 

385 (r'[(){},;]', Punctuation), 

386 (r'=>', Operator), 

387 (r'->', Operator), 

388 (r'\d+\.\d+', Number.Float), 

389 (r'\d+', Number.Integer), 

390 (r'\w+', Name.Function), 

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

392 ], 

393 'string': [ 

394 (r'\$[{(]', String.Interpol, 'interpol'), 

395 (r'\\.', String.Escape), 

396 (r'"', String, '#pop'), 

397 (r'\n', String), 

398 (r'.', String), 

399 ], 

400 'interpol': [ 

401 (r'\$[{(]', String.Interpol, '#push'), 

402 (r'[})]', String.Interpol, '#pop'), 

403 (r'[^${()}]+', String.Interpol), 

404 ], 

405 'arglist': [ 

406 (r'\)', Punctuation, '#pop'), 

407 (r',', Punctuation), 

408 (r'\w+', Name.Variable), 

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

410 ], 

411 } 

412 

413 

414class ApacheConfLexer(RegexLexer): 

415 """ 

416 Lexer for configuration files following the Apache config file 

417 format. 

418 """ 

419 

420 name = 'ApacheConf' 

421 aliases = ['apacheconf', 'aconf', 'apache'] 

422 filenames = ['.htaccess', 'apache.conf', 'apache2.conf'] 

423 mimetypes = ['text/x-apacheconf'] 

424 url = 'https://httpd.apache.org/docs/current/configuring.html' 

425 version_added = '0.6' 

426 flags = re.MULTILINE | re.IGNORECASE 

427 

428 tokens = { 

429 'root': [ 

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

431 (r'#(.*\\\n)+.*$|(#.*?)$', Comment), 

432 (r'(<[^\s>/][^\s>]*)(?:(\s+)(.*))?(>)', 

433 bygroups(Name.Tag, Whitespace, String, Name.Tag)), 

434 (r'(</[^\s>]+)(>)', 

435 bygroups(Name.Tag, Name.Tag)), 

436 (r'[a-z]\w*', Name.Builtin, 'value'), 

437 (r'\.+', Text), 

438 ], 

439 'value': [ 

440 (r'\\\n', Text), 

441 (r'\n+', Whitespace, '#pop'), 

442 (r'\\', Text), 

443 (r'[^\S\n]+', Whitespace), 

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

445 (r'\d+', Number), 

446 (r'/([*a-z0-9][*\w./-]+)', String.Other), 

447 (r'(on|off|none|any|all|double|email|dns|min|minimal|' 

448 r'os|productonly|full|emerg|alert|crit|error|warn|' 

449 r'notice|info|debug|registry|script|inetd|standalone|' 

450 r'user|group)\b', Keyword), 

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

452 (r'[^\s"\\]+', Text) 

453 ], 

454 } 

455 

456 

457class SquidConfLexer(RegexLexer): 

458 """ 

459 Lexer for squid configuration files. 

460 """ 

461 

462 name = 'SquidConf' 

463 url = 'http://www.squid-cache.org/' 

464 aliases = ['squidconf', 'squid.conf', 'squid'] 

465 filenames = ['squid.conf'] 

466 mimetypes = ['text/x-squidconf'] 

467 version_added = '0.9' 

468 flags = re.IGNORECASE 

469 

470 keywords = ( 

471 "access_log", "acl", "always_direct", "announce_host", 

472 "announce_period", "announce_port", "announce_to", "anonymize_headers", 

473 "append_domain", "as_whois_server", "auth_param_basic", 

474 "authenticate_children", "authenticate_program", "authenticate_ttl", 

475 "broken_posts", "buffered_logs", "cache_access_log", "cache_announce", 

476 "cache_dir", "cache_dns_program", "cache_effective_group", 

477 "cache_effective_user", "cache_host", "cache_host_acl", 

478 "cache_host_domain", "cache_log", "cache_mem", "cache_mem_high", 

479 "cache_mem_low", "cache_mgr", "cachemgr_passwd", "cache_peer", 

480 "cache_peer_access", "cache_replacement_policy", "cache_stoplist", 

481 "cache_stoplist_pattern", "cache_store_log", "cache_swap", 

482 "cache_swap_high", "cache_swap_log", "cache_swap_low", "client_db", 

483 "client_lifetime", "client_netmask", "connect_timeout", "coredump_dir", 

484 "dead_peer_timeout", "debug_options", "delay_access", "delay_class", 

485 "delay_initial_bucket_level", "delay_parameters", "delay_pools", 

486 "deny_info", "dns_children", "dns_defnames", "dns_nameservers", 

487 "dns_testnames", "emulate_httpd_log", "err_html_text", 

488 "fake_user_agent", "firewall_ip", "forwarded_for", "forward_snmpd_port", 

489 "fqdncache_size", "ftpget_options", "ftpget_program", "ftp_list_width", 

490 "ftp_passive", "ftp_user", "half_closed_clients", "header_access", 

491 "header_replace", "hierarchy_stoplist", "high_response_time_warning", 

492 "high_page_fault_warning", "hosts_file", "htcp_port", "http_access", 

493 "http_anonymizer", "httpd_accel", "httpd_accel_host", 

494 "httpd_accel_port", "httpd_accel_uses_host_header", 

495 "httpd_accel_with_proxy", "http_port", "http_reply_access", 

496 "icp_access", "icp_hit_stale", "icp_port", "icp_query_timeout", 

497 "ident_lookup", "ident_lookup_access", "ident_timeout", 

498 "incoming_http_average", "incoming_icp_average", "inside_firewall", 

499 "ipcache_high", "ipcache_low", "ipcache_size", "local_domain", 

500 "local_ip", "logfile_rotate", "log_fqdn", "log_icp_queries", 

501 "log_mime_hdrs", "maximum_object_size", "maximum_single_addr_tries", 

502 "mcast_groups", "mcast_icp_query_timeout", "mcast_miss_addr", 

503 "mcast_miss_encode_key", "mcast_miss_port", "memory_pools", 

504 "memory_pools_limit", "memory_replacement_policy", "mime_table", 

505 "min_http_poll_cnt", "min_icp_poll_cnt", "minimum_direct_hops", 

506 "minimum_object_size", "minimum_retry_timeout", "miss_access", 

507 "negative_dns_ttl", "negative_ttl", "neighbor_timeout", 

508 "neighbor_type_domain", "netdb_high", "netdb_low", "netdb_ping_period", 

509 "netdb_ping_rate", "never_direct", "no_cache", "passthrough_proxy", 

510 "pconn_timeout", "pid_filename", "pinger_program", "positive_dns_ttl", 

511 "prefer_direct", "proxy_auth", "proxy_auth_realm", "query_icmp", 

512 "quick_abort", "quick_abort_max", "quick_abort_min", 

513 "quick_abort_pct", "range_offset_limit", "read_timeout", 

514 "redirect_children", "redirect_program", 

515 "redirect_rewrites_host_header", "reference_age", 

516 "refresh_pattern", "reload_into_ims", "request_body_max_size", 

517 "request_size", "request_timeout", "shutdown_lifetime", 

518 "single_parent_bypass", "siteselect_timeout", "snmp_access", 

519 "snmp_incoming_address", "snmp_port", "source_ping", "ssl_proxy", 

520 "store_avg_object_size", "store_objects_per_bucket", 

521 "strip_query_terms", "swap_level1_dirs", "swap_level2_dirs", 

522 "tcp_incoming_address", "tcp_outgoing_address", "tcp_recv_bufsize", 

523 "test_reachability", "udp_hit_obj", "udp_hit_obj_size", 

524 "udp_incoming_address", "udp_outgoing_address", "unique_hostname", 

525 "unlinkd_program", "uri_whitespace", "useragent_log", 

526 "visible_hostname", "wais_relay", "wais_relay_host", "wais_relay_port", 

527 ) 

528 

529 opts = ( 

530 "proxy-only", "weight", "ttl", "no-query", "default", "round-robin", 

531 "multicast-responder", "on", "off", "all", "deny", "allow", "via", 

532 "parent", "no-digest", "heap", "lru", "realm", "children", "q1", "q2", 

533 "credentialsttl", "none", "disable", "offline_toggle", "diskd", 

534 ) 

535 

536 actions = ( 

537 "shutdown", "info", "parameter", "server_list", "client_list", 

538 r'squid.conf', 

539 ) 

540 

541 actions_stats = ( 

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

543 "redirector", "io", "reply_headers", "filedescriptors", "netdb", 

544 ) 

545 

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

547 

548 acls = ( 

549 "url_regex", "urlpath_regex", "referer_regex", "port", "proto", 

550 "req_mime_type", "rep_mime_type", "method", "browser", "user", "src", 

551 "dst", "time", "dstdomain", "ident", "snmp_community", 

552 ) 

553 

554 ipv4_group = r'(\d+|0x[0-9a-f]+)' 

555 ipv4 = rf'({ipv4_group}(\.{ipv4_group}){{3}})' 

556 ipv6_group = r'([0-9a-f]{0,4})' 

557 ipv6 = rf'({ipv6_group}(:{ipv6_group}){{1,7}})' 

558 bare_ip = rf'({ipv4}|{ipv6})' 

559 # XXX: /integer is a subnet mark, but what is /IP ? 

560 # There is no test where it is used. 

561 ip = rf'{bare_ip}(/({bare_ip}|\d+))?' 

562 

563 tokens = { 

564 'root': [ 

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

566 (r'#', Comment, 'comment'), 

567 (words(keywords, prefix=r'\b', suffix=r'\b'), Keyword), 

568 (words(opts, prefix=r'\b', suffix=r'\b'), Name.Constant), 

569 # Actions 

570 (words(actions, prefix=r'\b', suffix=r'\b'), String), 

571 (words(actions_stats, prefix=r'stats/', suffix=r'\b'), String), 

572 (words(actions_log, prefix=r'log/', suffix=r'='), String), 

573 (words(acls, prefix=r'\b', suffix=r'\b'), Keyword), 

574 (ip, Number.Float), 

575 (r'(?:\b\d+\b(?:-\b\d+|%)?)', Number), 

576 (r'\S+', Text), 

577 ], 

578 'comment': [ 

579 (r'\s*TAG:.*', String.Escape, '#pop'), 

580 (r'.+', Comment, '#pop'), 

581 default('#pop'), 

582 ], 

583 } 

584 

585 

586class NginxConfLexer(RegexLexer): 

587 """ 

588 Lexer for Nginx configuration files. 

589 """ 

590 name = 'Nginx configuration file' 

591 url = 'http://nginx.net/' 

592 aliases = ['nginx'] 

593 filenames = ['nginx.conf'] 

594 mimetypes = ['text/x-nginx-conf'] 

595 version_added = '0.11' 

596 

597 tokens = { 

598 'root': [ 

599 (r'(include)(\s+)([^\s;]+)', bygroups(Keyword, Whitespace, Name)), 

600 (r'[^\s;#]+', Keyword, 'stmt'), 

601 include('base'), 

602 ], 

603 'block': [ 

604 (r'\}', Punctuation, '#pop:2'), 

605 (r'[^\s;#]+', Keyword.Namespace, 'stmt'), 

606 include('base'), 

607 ], 

608 'stmt': [ 

609 (r'\{', Punctuation, 'block'), 

610 (r';', Punctuation, '#pop'), 

611 include('base'), 

612 ], 

613 'base': [ 

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

615 (r'on|off', Name.Constant), 

616 (r'\$[^\s;#()]+', Name.Variable), 

617 (r'([a-z0-9.-]+)(:)([0-9]+)', 

618 bygroups(Name, Punctuation, Number.Integer)), 

619 (r'[a-z-]+/[a-z-+]+', String), # mimetype 

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

621 (r'[0-9]+[km]?\b', Number.Integer), 

622 (r'(~)(\s*)([^\s{]+)', bygroups(Punctuation, Whitespace, String.Regex)), 

623 (r'[:=~]', Punctuation), 

624 (r'[^\s;#{}$]+', String), # catch all 

625 (r'/[^\s;#]*', Name), # pathname 

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

627 (r'[$;]', Text), # leftover characters 

628 ], 

629 } 

630 

631 

632class LighttpdConfLexer(RegexLexer): 

633 """ 

634 Lexer for Lighttpd configuration files. 

635 """ 

636 name = 'Lighttpd configuration file' 

637 url = 'http://lighttpd.net/' 

638 aliases = ['lighttpd', 'lighty'] 

639 filenames = ['lighttpd.conf'] 

640 mimetypes = ['text/x-lighttpd-conf'] 

641 version_added = '0.11' 

642 

643 tokens = { 

644 'root': [ 

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

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

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

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

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

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

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

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

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

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

655 ], 

656 

657 } 

658 

659 

660class DockerLexer(RegexLexer): 

661 """ 

662 Lexer for Docker configuration files. 

663 """ 

664 name = 'Docker' 

665 url = 'http://docker.io' 

666 aliases = ['docker', 'dockerfile'] 

667 filenames = ['Dockerfile', '*.docker'] 

668 mimetypes = ['text/x-dockerfile-config'] 

669 version_added = '2.0' 

670 

671 _keywords = (r'(?:MAINTAINER|EXPOSE|WORKDIR|USER|STOPSIGNAL)') 

672 _bash_keywords = (r'(?:RUN|CMD|ENTRYPOINT|ENV|ARG|LABEL|ADD|COPY)') 

673 _lb = r'(?:\s*\\?\s*)' # dockerfile line break regex 

674 flags = re.IGNORECASE | re.MULTILINE 

675 

676 tokens = { 

677 'root': [ 

678 (r'#.*', Comment), 

679 (r'(FROM)([ \t]*)(\S*)([ \t]*)(?:(AS)([ \t]*)(\S*))?', 

680 bygroups(Keyword, Whitespace, String, Whitespace, Keyword, Whitespace, String)), 

681 (rf'(ONBUILD)(\s+)({_lb})', bygroups(Keyword, Whitespace, using(BashLexer))), 

682 (rf'(HEALTHCHECK)(\s+)(({_lb}--\w+=\w+{_lb})*)', 

683 bygroups(Keyword, Whitespace, using(BashLexer))), 

684 (rf'(VOLUME|ENTRYPOINT|CMD|SHELL)(\s+)({_lb})(\[.*?\])', 

685 bygroups(Keyword, Whitespace, using(BashLexer), using(JsonLexer))), 

686 (rf'(LABEL|ENV|ARG)(\s+)(({_lb}\w+=\w+{_lb})*)', 

687 bygroups(Keyword, Whitespace, using(BashLexer))), 

688 (rf'({_keywords}|VOLUME)\b(\s+)(.*)', bygroups(Keyword, Whitespace, String)), 

689 (rf'({_bash_keywords})(\s+)', bygroups(Keyword, Whitespace)), 

690 (r'(.*\\\n)*.+', using(BashLexer)), 

691 ] 

692 } 

693 

694 

695class TerraformLexer(ExtendedRegexLexer): 

696 """ 

697 Lexer for terraformi ``.tf`` files. 

698 """ 

699 

700 name = 'Terraform' 

701 url = 'https://www.terraform.io/' 

702 aliases = ['terraform', 'tf', 'hcl'] 

703 filenames = ['*.tf', '*.hcl'] 

704 mimetypes = ['application/x-tf', 'application/x-terraform'] 

705 version_added = '2.1' 

706 

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

708 'provisioner', 'resource', 'variable') 

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

710 

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

712 

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

714 'mix', 'parseint', 'pow', 'signum') 

715 

716 string_functions = ('chomp', 'format', 'formatlist', 'indent', 

717 'join', 'lower', 'regex', 'regexall', 'replace', 

718 'split', 'strrev', 'substr', 'title', 'trim', 

719 'trimprefix', 'trimsuffix', 'trimspace', 'upper' 

720 ) 

721 

722 collection_functions = ('alltrue', 'anytrue', 'chunklist', 'coalesce', 

723 'coalescelist', 'compact', 'concat', 'contains', 

724 'distinct', 'element', 'flatten', 'index', 'keys', 

725 'length', 'list', 'lookup', 'map', 'matchkeys', 

726 'merge', 'range', 'reverse', 'setintersection', 

727 'setproduct', 'setsubtract', 'setunion', 'slice', 

728 'sort', 'sum', 'transpose', 'values', 'zipmap' 

729 ) 

730 

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

732 'csvdecode', 'jsondecode', 'jsonencode', 'textdecodebase64', 

733 'textencodebase64', 'urlencode', 'yamldecode', 'yamlencode') 

734 

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

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

737 

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

739 

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

741 'filebase64sha512', 'filemd5', 'filesha1', 'filesha256', 'filesha512', 

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

743 

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

745 

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

747 'tonumber', 'toset', 'tostring', 'try') 

748 

749 builtins = numeric_functions + string_functions + collection_functions + encoding_functions +\ 

750 filesystem_functions + date_time_functions + hash_crypto_functions + ip_network_functions +\ 

751 type_conversion_functions 

752 builtins_re = "({})".format(('|').join(builtins)) 

753 

754 def heredoc_callback(self, match, ctx): 

755 # Parse a terraform heredoc 

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

757 

758 start = match.start(1) 

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

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

761 

762 ctx.pos = match.start(3) 

763 ctx.end = match.end(3) 

764 yield ctx.pos, String.Heredoc, match.group(3) 

765 ctx.pos = match.end() 

766 

767 hdname = match.group(2) 

768 tolerant = True # leading whitespace is always accepted 

769 

770 lines = [] 

771 

772 for match in line_re.finditer(ctx.text, ctx.pos): 

773 if tolerant: 

774 check = match.group().strip() 

775 else: 

776 check = match.group().rstrip() 

777 if check == hdname: 

778 for amatch in lines: 

779 yield amatch.start(), String.Heredoc, amatch.group() 

780 yield match.start(), String.Delimiter, match.group() 

781 ctx.pos = match.end() 

782 break 

783 else: 

784 lines.append(match) 

785 else: 

786 # end of heredoc not found -- error! 

787 for amatch in lines: 

788 yield amatch.start(), Error, amatch.group() 

789 ctx.end = len(ctx.text) 

790 

791 tokens = { 

792 'root': [ 

793 include('basic'), 

794 include('whitespace'), 

795 

796 # Strings 

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

798 

799 # Constants 

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

801 

802 # Types 

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

804 

805 include('identifier'), 

806 include('punctuation'), 

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

808 ], 

809 'basic': [ 

810 (r'\s*/\*', Comment.Multiline, 'comment'), 

811 (r'\s*(#|//).*\n', Comment.Single), 

812 include('whitespace'), 

813 

814 # e.g. terraform { 

815 # e.g. egress { 

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

817 bygroups(Whitespace, Name.Builtin, Whitespace, Operator, Whitespace, Punctuation)), 

818 

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

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

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

822 

823 # Assignment with environment variables and similar, e.g. "something" = ... 

824 # or key value assignment, e.g. "SlotName" : ... 

825 (r'(\s*)("\S+")(\s*)([=:])(\s*)', 

826 bygroups(Whitespace, Literal.String.Double, Whitespace, Operator, Whitespace)), 

827 

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

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

830 

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

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

833 

834 # e.g. resource "aws_security_group" "allow_tls" { 

835 # e.g. backend "consul" { 

836 (classes_re + r'(\s+)("[0-9a-zA-Z-_]+")?(\s*)("[0-9a-zA-Z-_]+")(\s+)(\{)', 

837 bygroups(Keyword.Reserved, Whitespace, Name.Class, Whitespace, Name.Variable, Whitespace, Punctuation)), 

838 

839 # here-doc style delimited strings 

840 (r'(<<-?)\s*([a-zA-Z_]\w*)(.*?\n)', heredoc_callback), 

841 ], 

842 'identifier': [ 

843 (r'\b(var\.[0-9a-zA-Z-_\.\[\]]+)\b', bygroups(Name.Variable)), 

844 (r'\b([0-9a-zA-Z-_\[\]]+\.[0-9a-zA-Z-_\.\[\]]+)\b', 

845 bygroups(Name.Variable)), 

846 ], 

847 'punctuation': [ 

848 (r'[\[\]()\{\},.?:!=]', Punctuation), 

849 ], 

850 'comment': [ 

851 (r'[^*/]', Comment.Multiline), 

852 (r'/\*', Comment.Multiline, '#push'), 

853 (r'\*/', Comment.Multiline, '#pop'), 

854 (r'[*/]', Comment.Multiline) 

855 ], 

856 'whitespace': [ 

857 (r'\n', Whitespace), 

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

859 (r'(\\)(\n)', bygroups(Text, Whitespace)), 

860 ], 

861 } 

862 

863 

864class TermcapLexer(RegexLexer): 

865 """ 

866 Lexer for termcap database source. 

867 

868 This is very simple and minimal. 

869 """ 

870 name = 'Termcap' 

871 aliases = ['termcap'] 

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

873 mimetypes = [] 

874 url = 'https://en.wikipedia.org/wiki/Termcap' 

875 version_added = '2.1' 

876 

877 # NOTE: 

878 # * multiline with trailing backslash 

879 # * separator is ':' 

880 # * to embed colon as data, we must use \072 

881 # * space after separator is not allowed (mayve) 

882 tokens = { 

883 'root': [ 

884 (r'^#.*', Comment), 

885 (r'^[^\s#:|]+', Name.Tag, 'names'), 

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

887 ], 

888 'names': [ 

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

890 (r':', Punctuation, 'defs'), 

891 (r'\|', Punctuation), 

892 (r'[^:|]+', Name.Attribute), 

893 ], 

894 'defs': [ 

895 (r'(\\)(\n[ \t]*)', bygroups(Text, Whitespace)), 

896 (r'\n[ \t]*', Whitespace, '#pop:2'), 

897 (r'(#)([0-9]+)', bygroups(Operator, Number)), 

898 (r'=', Operator, 'data'), 

899 (r':', Punctuation), 

900 (r'[^\s:=#]+', Name.Class), 

901 ], 

902 'data': [ 

903 (r'\\072', Literal), 

904 (r':', Punctuation, '#pop'), 

905 (r'[^:\\]+', Literal), # for performance 

906 (r'.', Literal), 

907 ], 

908 } 

909 

910 

911class TerminfoLexer(RegexLexer): 

912 """ 

913 Lexer for terminfo database source. 

914 

915 This is very simple and minimal. 

916 """ 

917 name = 'Terminfo' 

918 aliases = ['terminfo'] 

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

920 mimetypes = [] 

921 url = 'https://en.wikipedia.org/wiki/Terminfo' 

922 version_added = '2.1' 

923 

924 # NOTE: 

925 # * multiline with leading whitespace 

926 # * separator is ',' 

927 # * to embed comma as data, we can use \, 

928 # * space after separator is allowed 

929 tokens = { 

930 'root': [ 

931 (r'^#.*$', Comment), 

932 (r'^[^\s#,|]+', Name.Tag, 'names'), 

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

934 ], 

935 'names': [ 

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

937 (r'(,)([ \t]*)', bygroups(Punctuation, Whitespace), 'defs'), 

938 (r'\|', Punctuation), 

939 (r'[^,|]+', Name.Attribute), 

940 ], 

941 'defs': [ 

942 (r'\n[ \t]+', Whitespace), 

943 (r'\n', Whitespace, '#pop:2'), 

944 (r'(#)([0-9]+)', bygroups(Operator, Number)), 

945 (r'=', Operator, 'data'), 

946 (r'(,)([ \t]*)', bygroups(Punctuation, Whitespace)), 

947 (r'[^\s,=#]+', Name.Class), 

948 ], 

949 'data': [ 

950 (r'\\[,\\]', Literal), 

951 (r'(,)([ \t]*)', bygroups(Punctuation, Whitespace), '#pop'), 

952 (r'[^\\,]+', Literal), # for performance 

953 (r'.', Literal), 

954 ], 

955 } 

956 

957 

958class PkgConfigLexer(RegexLexer): 

959 """ 

960 Lexer for pkg-config 

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

962 """ 

963 

964 name = 'PkgConfig' 

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

966 aliases = ['pkgconfig'] 

967 filenames = ['*.pc'] 

968 mimetypes = [] 

969 version_added = '2.1' 

970 

971 tokens = { 

972 'root': [ 

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

974 

975 # variable definitions 

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

977 

978 # keyword lines 

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

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

981 

982 # variable references 

983 include('interp'), 

984 

985 # fallback 

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

987 (r'[^${}#=:\n.]+', Text), 

988 (r'.', Text), 

989 ], 

990 'interp': [ 

991 # you can escape literal "$" as "$$" 

992 (r'\$\$', Text), 

993 

994 # variable references 

995 (r'\$\{', String.Interpol, 'curly'), 

996 ], 

997 'curly': [ 

998 (r'\}', String.Interpol, '#pop'), 

999 (r'\w+', Name.Attribute), 

1000 ], 

1001 'spvalue': [ 

1002 include('interp'), 

1003 

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

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

1006 

1007 # fallback 

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

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

1010 (r'.', Text), 

1011 ], 

1012 } 

1013 

1014 

1015class PacmanConfLexer(RegexLexer): 

1016 """ 

1017 Lexer for pacman.conf. 

1018 

1019 Actually, IniLexer works almost fine for this format, 

1020 but it yield error token. It is because pacman.conf has 

1021 a form without assignment like: 

1022 

1023 UseSyslog 

1024 Color 

1025 TotalDownload 

1026 CheckSpace 

1027 VerbosePkgLists 

1028 

1029 These are flags to switch on. 

1030 """ 

1031 

1032 name = 'PacmanConf' 

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

1034 aliases = ['pacmanconf'] 

1035 filenames = ['pacman.conf'] 

1036 mimetypes = [] 

1037 version_added = '2.1' 

1038 

1039 tokens = { 

1040 'root': [ 

1041 # comment 

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

1043 

1044 # section header 

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

1046 

1047 # variable definitions 

1048 # (Leading space is allowed...) 

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

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

1051 

1052 # flags to on 

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

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

1055 

1056 # built-in special values 

1057 (words(( 

1058 '$repo', # repository 

1059 '$arch', # architecture 

1060 '%o', # outfile 

1061 '%u', # url 

1062 ), suffix=r'\b'), 

1063 Name.Variable), 

1064 

1065 # fallback 

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

1067 (r'.', Text), 

1068 ], 

1069 } 

1070 

1071 

1072class AugeasLexer(RegexLexer): 

1073 """ 

1074 Lexer for Augeas. 

1075 """ 

1076 name = 'Augeas' 

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

1078 aliases = ['augeas'] 

1079 filenames = ['*.aug'] 

1080 version_added = '2.4' 

1081 

1082 tokens = { 

1083 'root': [ 

1084 (r'(module)(\s*)([^\s=]+)', bygroups(Keyword.Namespace, Whitespace, Name.Namespace)), 

1085 (r'(let)(\s*)([^\s=]+)', bygroups(Keyword.Declaration, Whitespace, Name.Variable)), 

1086 (r'(del|store|value|counter|seq|key|label|autoload|incl|excl|transform|test|get|put)(\s+)', bygroups(Name.Builtin, Whitespace)), 

1087 (r'(\()([^:]+)(\:)(unit|string|regexp|lens|tree|filter)(\))', bygroups(Punctuation, Name.Variable, Punctuation, Keyword.Type, Punctuation)), 

1088 (r'\(\*', Comment.Multiline, 'comment'), 

1089 (r'[*+\-.;=?|]', Operator), 

1090 (r'[()\[\]{}]', Operator), 

1091 (r'"', String.Double, 'string'), 

1092 (r'\/', String.Regex, 'regex'), 

1093 (r'([A-Z]\w*)(\.)(\w+)', bygroups(Name.Namespace, Punctuation, Name.Variable)), 

1094 (r'.', Name.Variable), 

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

1096 ], 

1097 'string': [ 

1098 (r'\\.', String.Escape), 

1099 (r'[^"]', String.Double), 

1100 (r'"', String.Double, '#pop'), 

1101 ], 

1102 'regex': [ 

1103 (r'\\.', String.Escape), 

1104 (r'[^/]', String.Regex), 

1105 (r'\/', String.Regex, '#pop'), 

1106 ], 

1107 'comment': [ 

1108 (r'[^*)]', Comment.Multiline), 

1109 (r'\(\*', Comment.Multiline, '#push'), 

1110 (r'\*\)', Comment.Multiline, '#pop'), 

1111 (r'[)*]', Comment.Multiline) 

1112 ], 

1113 } 

1114 

1115 

1116class TOMLLexer(RegexLexer): 

1117 """ 

1118 Lexer for TOML, a simple language for config files. 

1119 """ 

1120 

1121 name = 'TOML' 

1122 aliases = ['toml'] 

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

1124 mimetypes = ['application/toml'] 

1125 url = 'https://toml.io' 

1126 version_added = '2.4' 

1127 

1128 # Based on the TOML spec: https://toml.io/en/v1.0.0 

1129 

1130 # The following is adapted from CPython's tomllib: 

1131 _time = r"\d\d:\d\d(:\d\d(\.\d+)?)?" 

1132 _datetime = rf"""(?x) 

1133 \d\d\d\d-\d\d-\d\d # date, e.g., 1988-10-27 

1134 ( 

1135 [Tt ] {_time} # optional time 

1136 ( 

1137 [Zz]|[+-]\d\d:\d\d # optional time offset 

1138 )? 

1139 )? 

1140 """ 

1141 

1142 tokens = { 

1143 'root': [ 

1144 # Note that we make an effort in order to distinguish 

1145 # moments at which we're parsing a key and moments at 

1146 # which we're parsing a value. In the TOML code 

1147 # 

1148 # 1234 = 1234 

1149 # 

1150 # the first "1234" should be Name, the second Integer. 

1151 

1152 # Whitespace 

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

1154 

1155 # Comment 

1156 (r'#.*', Comment.Single), 

1157 

1158 # Assignment keys 

1159 include('key'), 

1160 

1161 # After "=", find a value 

1162 (r'(=)(\s*)', bygroups(Operator, Whitespace), 'value'), 

1163 

1164 # Table header 

1165 (r'\[\[?', Keyword, 'table-key'), 

1166 ], 

1167 'key': [ 

1168 # Start of bare key (only ASCII is allowed here). 

1169 (r'[A-Za-z0-9_-]+', Name), 

1170 # Quoted key 

1171 (r'"', String.Double, 'basic-string'), 

1172 (r"'", String.Single, 'literal-string'), 

1173 # Dots act as separators in keys 

1174 (r'\.', Punctuation), 

1175 ], 

1176 'table-key': [ 

1177 # This is like 'key', but highlights the name components 

1178 # and separating dots as Keyword because it looks better 

1179 # when the whole table header is Keyword. We do highlight 

1180 # strings as strings though. 

1181 # Start of bare key (only ASCII is allowed here). 

1182 (r'[A-Za-z0-9_-]+', Keyword), 

1183 (r'"', String.Double, 'basic-string'), 

1184 (r"'", String.Single, 'literal-string'), 

1185 (r'\.', Keyword), 

1186 (r'\]\]?', Keyword, '#pop'), 

1187 

1188 # Inline whitespace allowed 

1189 (r'[ \t]+', Whitespace), 

1190 ], 

1191 'value': [ 

1192 # Datetime, baretime 

1193 (_datetime, Literal.Date, '#pop'), 

1194 (_time, Literal.Date, '#pop'), 

1195 

1196 # Recognize as float if there is a fractional part 

1197 # and/or an exponent. 

1198 (r'[+-]?\d[0-9_]*[eE][+-]?\d[0-9_]*', Number.Float, '#pop'), 

1199 (r'[+-]?\d[0-9_]*\.\d[0-9_]*([eE][+-]?\d[0-9_]*)?', 

1200 Number.Float, '#pop'), 

1201 

1202 # Infinities and NaN 

1203 (r'[+-]?(inf|nan)', Number.Float, '#pop'), 

1204 

1205 # Integers 

1206 (r'-?0b[01_]+', Number.Bin, '#pop'), 

1207 (r'-?0o[0-7_]+', Number.Oct, '#pop'), 

1208 (r'-?0x[0-9a-fA-F_]+', Number.Hex, '#pop'), 

1209 (r'[+-]?[0-9_]+', Number.Integer, '#pop'), 

1210 

1211 # Strings 

1212 (r'"""', String.Double, ('#pop', 'multiline-basic-string')), 

1213 (r'"', String.Double, ('#pop', 'basic-string')), 

1214 (r"'''", String.Single, ('#pop', 'multiline-literal-string')), 

1215 (r"'", String.Single, ('#pop', 'literal-string')), 

1216 

1217 # Booleans 

1218 (r'true|false', Keyword.Constant, '#pop'), 

1219 

1220 # Start of array 

1221 (r'\[', Punctuation, ('#pop', 'array')), 

1222 

1223 # Start of inline table 

1224 (r'\{', Punctuation, ('#pop', 'inline-table')), 

1225 ], 

1226 'array': [ 

1227 # Whitespace, including newlines, is ignored inside arrays, 

1228 # and comments are allowed. 

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

1230 (r'#.*', Comment.Single), 

1231 

1232 # Delimiters 

1233 (r',', Punctuation), 

1234 

1235 # End of array 

1236 (r'\]', Punctuation, '#pop'), 

1237 

1238 # Parse a value and come back 

1239 default('value'), 

1240 ], 

1241 'inline-table': [ 

1242 # Whitespace (since TOML 1.1.0, same as in array) 

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

1244 (r'#.*', Comment.Single), 

1245 

1246 # Keys 

1247 include('key'), 

1248 

1249 # Values 

1250 (r'(=)(\s*)', bygroups(Punctuation, Whitespace), 'value'), 

1251 

1252 # Delimiters 

1253 (r',', Punctuation), 

1254 

1255 # End of inline table 

1256 (r'\}', Punctuation, '#pop'), 

1257 ], 

1258 'basic-string': [ 

1259 (r'"', String.Double, '#pop'), 

1260 include('escapes'), 

1261 (r'[^"\\]+', String.Double), 

1262 ], 

1263 'literal-string': [ 

1264 (r".*?'", String.Single, '#pop'), 

1265 ], 

1266 'multiline-basic-string': [ 

1267 (r'"""', String.Double, '#pop'), 

1268 (r'(\\)(\n)', bygroups(String.Escape, Whitespace)), 

1269 include('escapes'), 

1270 (r'[^"\\]+', String.Double), 

1271 (r'"', String.Double), 

1272 ], 

1273 'multiline-literal-string': [ 

1274 (r"'''", String.Single, '#pop'), 

1275 (r"[^']+", String.Single), 

1276 (r"'", String.Single), 

1277 ], 

1278 'escapes': [ 

1279 (r'\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}|\\U[0-9a-fA-F]{8}', String.Escape), 

1280 (r'\\.', String.Escape), 

1281 ], 

1282 } 

1283 

1284class NestedTextLexer(RegexLexer): 

1285 """ 

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

1287 

1288 .. versionchanged:: 2.16 

1289 Added support for *NextedText* v3.0. 

1290 """ 

1291 

1292 name = 'NestedText' 

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

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

1295 filenames = ['*.nt'] 

1296 version_added = '2.9' 

1297 

1298 tokens = { 

1299 'root': [ 

1300 # Comment: # ... 

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

1302 

1303 # Inline dictionary: {...} 

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

1305 

1306 # Inline list: [...] 

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

1308 

1309 # empty multiline string item: > 

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

1311 

1312 # multiline string item: > ... 

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

1314 

1315 # empty list item: - 

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

1317 

1318 # list item: - ... 

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

1320 

1321 # empty multiline key item: : 

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

1323 

1324 # multiline key item: : ... 

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

1326 

1327 # empty dict key item: ...: 

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

1329 

1330 # dict key item: ...: ... 

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

1332 ], 

1333 'inline_list': [ 

1334 include('whitespace'), 

1335 (r'[^\{\}\[\],\s]+', Text), 

1336 include('inline_value'), 

1337 (r',', Punctuation), 

1338 (r'\]', Punctuation, '#pop'), 

1339 (r'\n', Error, '#pop'), 

1340 ], 

1341 'inline_dict': [ 

1342 include('whitespace'), 

1343 (r'[^\{\}\[\],:\s]+', Name.Tag), 

1344 (r':', Punctuation, 'inline_dict_value'), 

1345 (r'\}', Punctuation, '#pop'), 

1346 (r'\n', Error, '#pop'), 

1347 ], 

1348 'inline_dict_value': [ 

1349 include('whitespace'), 

1350 (r'[^\{\}\[\],:\s]+', Text), 

1351 include('inline_value'), 

1352 (r',', Punctuation, '#pop'), 

1353 (r'\}', Punctuation, '#pop:2'), 

1354 ], 

1355 'inline_value': [ 

1356 include('whitespace'), 

1357 (r'\{', Punctuation, 'inline_dict'), 

1358 (r'\[', Punctuation, 'inline_list'), 

1359 ], 

1360 'whitespace': [ 

1361 (r'[ \t]+', Whitespace), 

1362 ], 

1363 } 

1364 

1365 

1366class SingularityLexer(RegexLexer): 

1367 """ 

1368 Lexer for Singularity definition files. 

1369 """ 

1370 

1371 name = 'Singularity' 

1372 url = 'https://www.sylabs.io/guides/3.0/user-guide/definition_files.html' 

1373 aliases = ['singularity'] 

1374 filenames = ['*.def', 'Singularity'] 

1375 version_added = '2.6' 

1376 flags = re.IGNORECASE | re.MULTILINE | re.DOTALL 

1377 

1378 _headers = r'^(\s*)(bootstrap|from|osversion|mirrorurl|include|registry|namespace|includecmd)(:)' 

1379 _section = r'^(%(?:pre|post|setup|environment|help|labels|test|runscript|files|startscript))(\s*)' 

1380 _appsect = r'^(%app(?:install|help|run|labels|env|test|files))(\s*)' 

1381 

1382 tokens = { 

1383 'root': [ 

1384 (_section, bygroups(Generic.Heading, Whitespace), 'script'), 

1385 (_appsect, bygroups(Generic.Heading, Whitespace), 'script'), 

1386 (_headers, bygroups(Whitespace, Keyword, Text)), 

1387 (r'\s*#.*?\n', Comment), 

1388 (r'\b(([0-9]+\.?[0-9]*)|(\.[0-9]+))\b', Number), 

1389 (r'[ \t]+', Whitespace), 

1390 (r'(?!^\s*%).', Text), 

1391 ], 

1392 'script': [ 

1393 (r'(.+?(?=^\s*%))|(.*)', using(BashLexer), '#pop'), 

1394 ], 

1395 } 

1396 

1397 def analyse_text(text): 

1398 """This is a quite simple script file, but there are a few keywords 

1399 which seem unique to this language.""" 

1400 result = 0 

1401 if re.search(r'\b(?:osversion|includecmd|mirrorurl)\b', text, re.IGNORECASE): 

1402 result += 0.5 

1403 

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

1405 result += 0.49 

1406 

1407 return result 

1408 

1409 

1410class UnixConfigLexer(RegexLexer): 

1411 """ 

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

1413 

1414 * ``/etc/group`` 

1415 * ``/etc/passwd`` 

1416 * ``/etc/shadow`` 

1417 """ 

1418 

1419 name = 'Unix/Linux config files' 

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

1421 filenames = [] 

1422 url = 'https://en.wikipedia.org/wiki/Configuration_file#Unix_and_Unix-like_operating_systems' 

1423 version_added = '2.12' 

1424 

1425 tokens = { 

1426 'root': [ 

1427 (r'^#.*', Comment), 

1428 (r'\n', Whitespace), 

1429 (r':', Punctuation), 

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

1431 (r'((?!\n)[a-zA-Z0-9\_\-\s\(\),]){2,}', Text), 

1432 (r'[^:\n]+', String), 

1433 ], 

1434 } 

1435 

1436 

1437class CaddyfileLexer(RegexLexer): 

1438 """ 

1439 Lexer for Caddyfile, the configuration file format of the Caddy web server. 

1440 """ 

1441 

1442 name = 'Caddyfile' 

1443 url = 'https://caddyserver.com/docs/caddyfile' 

1444 aliases = ['caddyfile', 'caddy'] 

1445 filenames = ['Caddyfile'] 

1446 version_added = '2.21' 

1447 

1448 # The standard HTTP directives shipped with Caddy. 

1449 directives = ( 

1450 'abort', 'acme_server', 'basic_auth', 'bind', 'encode', 'error', 

1451 'file_server', 'forward_auth', 'handle', 'handle_errors', 

1452 'handle_path', 'header', 'import', 'invoke', 'log', 'map', 'metrics', 

1453 'php_fastcgi', 'push', 'redir', 'request_body', 'request_header', 

1454 'respond', 'reverse_proxy', 'rewrite', 'root', 'route', 'templates', 

1455 'tls', 'tracing', 'try_files', 'uri', 'vars', 

1456 ) 

1457 

1458 tokens = { 

1459 'root': [ 

1460 # Directives are only keywords as the first token on a line, so 

1461 # anchor them to the start of the (possibly indented) line. This 

1462 # consumes the preceding newline(s)/indentation itself, otherwise 

1463 # the generic whitespace rule below would swallow it first. 

1464 (r'((?:\A|\s*\n)[ \t]*)(' + '|'.join(directives) + r')\b', 

1465 bygroups(Whitespace, Keyword)), 

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

1467 (r'#.*', Comment.Single), 

1468 # Heredoc: <<LABEL <args> ... LABEL. The remainder of the opening 

1469 # line (e.g. a status code) is not part of the body, so re-lex it; 

1470 # the closing label must stand alone on its line. 

1471 (r'(<<)([a-zA-Z_]\w*)(.*\n)((?:.*\n)*?)([ \t]*)(\2)(?=[ \t]*$)', 

1472 bygroups(Operator, String.Delimiter, using(this), 

1473 String.Heredoc, Whitespace, String.Delimiter)), 

1474 # Placeholders: {path}, {http.request.uri}, {$ENV}, {args[0]}, ... 

1475 (r'\{[^{}\s]+\}', Name.Variable), 

1476 # Blocks and snippet parentheses 

1477 (r'[(){}]', Punctuation), 

1478 # Named matcher, e.g. @api 

1479 (r'@[\w.-]+', Name.Decorator), 

1480 (r'"', String.Double, 'string'), 

1481 (r'`', String.Backtick, 'backtick'), 

1482 # Numbers, durations and sizes (443, 200, 30s, 1.5m, 10MB); a 

1483 # trailing dot or more digits/letters means it is an address or 

1484 # hostname, which must stay Text. 

1485 (r'\d+(?:\.\d+)?[a-zA-Z]*(?=[\s#{}()"`]|$)', Number), 

1486 (r'[^\s#{}()"`]+', Text), 

1487 ], 

1488 'string': [ 

1489 (r'\\.', String.Escape), 

1490 (r'\{[^{}\s]+\}', Name.Variable), 

1491 (r'[^"\\{]+', String.Double), 

1492 (r'"', String.Double, '#pop'), 

1493 (r'.', String.Double), 

1494 ], 

1495 'backtick': [ 

1496 (r'[^`]+', String.Backtick), 

1497 (r'`', String.Backtick, '#pop'), 

1498 ], 

1499 }