Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pygments/lexers/shell.py: 83%
205 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-01 06:54 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-01 06:54 +0000
1"""
2 pygments.lexers.shell
3 ~~~~~~~~~~~~~~~~~~~~~
5 Lexers for various shells.
7 :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
8 :license: BSD, see LICENSE for details.
9"""
11import re
13from pygments.lexer import Lexer, RegexLexer, do_insertions, bygroups, \
14 include, default, this, using, words, line_re
15from pygments.token import Punctuation, Whitespace, \
16 Text, Comment, Operator, Keyword, Name, String, Number, Generic
17from pygments.util import shebang_matches
19__all__ = ['BashLexer', 'BashSessionLexer', 'TcshLexer', 'BatchLexer',
20 'SlurmBashLexer', 'MSDOSSessionLexer', 'PowerShellLexer',
21 'PowerShellSessionLexer', 'TcshSessionLexer', 'FishShellLexer',
22 'ExeclineLexer']
25class BashLexer(RegexLexer):
26 """
27 Lexer for (ba|k|z|)sh shell scripts.
29 .. versionadded:: 0.6
30 """
32 name = 'Bash'
33 aliases = ['bash', 'sh', 'ksh', 'zsh', 'shell']
34 filenames = ['*.sh', '*.ksh', '*.bash', '*.ebuild', '*.eclass',
35 '*.exheres-0', '*.exlib', '*.zsh',
36 '.bashrc', 'bashrc', '.bash_*', 'bash_*', 'zshrc', '.zshrc',
37 '.kshrc', 'kshrc',
38 'PKGBUILD']
39 mimetypes = ['application/x-sh', 'application/x-shellscript', 'text/x-shellscript']
41 tokens = {
42 'root': [
43 include('basic'),
44 (r'`', String.Backtick, 'backticks'),
45 include('data'),
46 include('interp'),
47 ],
48 'interp': [
49 (r'\$\(\(', Keyword, 'math'),
50 (r'\$\(', Keyword, 'paren'),
51 (r'\$\{#?', String.Interpol, 'curly'),
52 (r'\$[a-zA-Z_]\w*', Name.Variable), # user variable
53 (r'\$(?:\d+|[#$?!_*@-])', Name.Variable), # builtin
54 (r'\$', Text),
55 ],
56 'basic': [
57 (r'\b(if|fi|else|while|in|do|done|for|then|return|function|case|'
58 r'select|break|continue|until|esac|elif)(\s*)\b',
59 bygroups(Keyword, Whitespace)),
60 (r'\b(alias|bg|bind|builtin|caller|cd|command|compgen|'
61 r'complete|declare|dirs|disown|echo|enable|eval|exec|exit|'
62 r'export|false|fc|fg|getopts|hash|help|history|jobs|kill|let|'
63 r'local|logout|popd|printf|pushd|pwd|read|readonly|set|shift|'
64 r'shopt|source|suspend|test|time|times|trap|true|type|typeset|'
65 r'ulimit|umask|unalias|unset|wait)(?=[\s)`])',
66 Name.Builtin),
67 (r'\A#!.+\n', Comment.Hashbang),
68 (r'#.*\n', Comment.Single),
69 (r'\\[\w\W]', String.Escape),
70 (r'(\b\w+)(\s*)(\+?=)', bygroups(Name.Variable, Whitespace, Operator)),
71 (r'[\[\]{}()=]', Operator),
72 (r'<<<', Operator), # here-string
73 (r'<<-?\s*(\'?)\\?(\w+)[\w\W]+?\2', String),
74 (r'&&|\|\|', Operator),
75 ],
76 'data': [
77 (r'(?s)\$?"(\\.|[^"\\$])*"', String.Double),
78 (r'"', String.Double, 'string'),
79 (r"(?s)\$'(\\\\|\\[0-7]+|\\.|[^'\\])*'", String.Single),
80 (r"(?s)'.*?'", String.Single),
81 (r';', Punctuation),
82 (r'&', Punctuation),
83 (r'\|', Punctuation),
84 (r'\s+', Whitespace),
85 (r'\d+\b', Number),
86 (r'[^=\s\[\]{}()$"\'`\\<&|;]+', Text),
87 (r'<', Text),
88 ],
89 'string': [
90 (r'"', String.Double, '#pop'),
91 (r'(?s)(\\\\|\\[0-7]+|\\.|[^"\\$])+', String.Double),
92 include('interp'),
93 ],
94 'curly': [
95 (r'\}', String.Interpol, '#pop'),
96 (r':-', Keyword),
97 (r'\w+', Name.Variable),
98 (r'[^}:"\'`$\\]+', Punctuation),
99 (r':', Punctuation),
100 include('root'),
101 ],
102 'paren': [
103 (r'\)', Keyword, '#pop'),
104 include('root'),
105 ],
106 'math': [
107 (r'\)\)', Keyword, '#pop'),
108 (r'\*\*|\|\||<<|>>|[-+*/%^|&<>]', Operator),
109 (r'\d+#[\da-zA-Z]+', Number),
110 (r'\d+#(?! )', Number),
111 (r'0[xX][\da-fA-F]+', Number),
112 (r'\d+', Number),
113 (r'[a-zA-Z_]\w*', Name.Variable), # user variable
114 include('root'),
115 ],
116 'backticks': [
117 (r'`', String.Backtick, '#pop'),
118 include('root'),
119 ],
120 }
122 def analyse_text(text):
123 if shebang_matches(text, r'(ba|z|)sh'):
124 return 1
125 if text.startswith('$ '):
126 return 0.2
129class SlurmBashLexer(BashLexer):
130 """
131 Lexer for (ba|k|z|)sh Slurm scripts.
133 .. versionadded:: 2.4
134 """
136 name = 'Slurm'
137 aliases = ['slurm', 'sbatch']
138 filenames = ['*.sl']
139 mimetypes = []
140 EXTRA_KEYWORDS = {'srun'}
142 def get_tokens_unprocessed(self, text):
143 for index, token, value in BashLexer.get_tokens_unprocessed(self, text):
144 if token is Text and value in self.EXTRA_KEYWORDS:
145 yield index, Name.Builtin, value
146 elif token is Comment.Single and 'SBATCH' in value:
147 yield index, Keyword.Pseudo, value
148 else:
149 yield index, token, value
152class ShellSessionBaseLexer(Lexer):
153 """
154 Base lexer for shell sessions.
156 .. versionadded:: 2.1
157 """
159 _bare_continuation = False
160 _venv = re.compile(r'^(\([^)]*\))(\s*)')
162 def get_tokens_unprocessed(self, text):
163 innerlexer = self._innerLexerCls(**self.options)
165 pos = 0
166 curcode = ''
167 insertions = []
168 backslash_continuation = False
170 for match in line_re.finditer(text):
171 line = match.group()
173 venv_match = self._venv.match(line)
174 if venv_match:
175 venv = venv_match.group(1)
176 venv_whitespace = venv_match.group(2)
177 insertions.append((len(curcode),
178 [(0, Generic.Prompt.VirtualEnv, venv)]))
179 if venv_whitespace:
180 insertions.append((len(curcode),
181 [(0, Text, venv_whitespace)]))
182 line = line[venv_match.end():]
184 m = self._ps1rgx.match(line)
185 if m:
186 # To support output lexers (say diff output), the output
187 # needs to be broken by prompts whenever the output lexer
188 # changes.
189 if not insertions:
190 pos = match.start()
192 insertions.append((len(curcode),
193 [(0, Generic.Prompt, m.group(1))]))
194 curcode += m.group(2)
195 backslash_continuation = curcode.endswith('\\\n')
196 elif backslash_continuation:
197 if line.startswith(self._ps2):
198 insertions.append((len(curcode),
199 [(0, Generic.Prompt,
200 line[:len(self._ps2)])]))
201 curcode += line[len(self._ps2):]
202 else:
203 curcode += line
204 backslash_continuation = curcode.endswith('\\\n')
205 elif self._bare_continuation and line.startswith(self._ps2):
206 insertions.append((len(curcode),
207 [(0, Generic.Prompt,
208 line[:len(self._ps2)])]))
209 curcode += line[len(self._ps2):]
210 else:
211 if insertions:
212 toks = innerlexer.get_tokens_unprocessed(curcode)
213 for i, t, v in do_insertions(insertions, toks):
214 yield pos+i, t, v
215 yield match.start(), Generic.Output, line
216 insertions = []
217 curcode = ''
218 if insertions:
219 for i, t, v in do_insertions(insertions,
220 innerlexer.get_tokens_unprocessed(curcode)):
221 yield pos+i, t, v
224class BashSessionLexer(ShellSessionBaseLexer):
225 """
226 Lexer for Bash shell sessions, i.e. command lines, including a
227 prompt, interspersed with output.
229 .. versionadded:: 1.1
230 """
232 name = 'Bash Session'
233 aliases = ['console', 'shell-session']
234 filenames = ['*.sh-session', '*.shell-session']
235 mimetypes = ['application/x-shell-session', 'application/x-sh-session']
237 _innerLexerCls = BashLexer
238 _ps1rgx = re.compile(
239 r'^((?:(?:\[.*?\])|(?:\(\S+\))?(?:| |sh\S*?|\w+\S+[@:]\S+(?:\s+\S+)' \
240 r'?|\[\S+[@:][^\n]+\].+))\s*[$#%]\s*)(.*\n?)')
241 _ps2 = '> '
244class BatchLexer(RegexLexer):
245 """
246 Lexer for the DOS/Windows Batch file format.
248 .. versionadded:: 0.7
249 """
250 name = 'Batchfile'
251 aliases = ['batch', 'bat', 'dosbatch', 'winbatch']
252 filenames = ['*.bat', '*.cmd']
253 mimetypes = ['application/x-dos-batch']
255 flags = re.MULTILINE | re.IGNORECASE
257 _nl = r'\n\x1a'
258 _punct = r'&<>|'
259 _ws = r'\t\v\f\r ,;=\xa0'
260 _nlws = r'\s\x1a\xa0,;='
261 _space = r'(?:(?:(?:\^[%s])?[%s])+)' % (_nl, _ws)
262 _keyword_terminator = (r'(?=(?:\^[%s]?)?[%s+./:[\\\]]|[%s%s(])' %
263 (_nl, _ws, _nl, _punct))
264 _token_terminator = r'(?=\^?[%s]|[%s%s])' % (_ws, _punct, _nl)
265 _start_label = r'((?:(?<=^[^:])|^[^:]?)[%s]*)(:)' % _ws
266 _label = r'(?:(?:[^%s%s+:^]|\^[%s]?[\w\W])*)' % (_nlws, _punct, _nl)
267 _label_compound = r'(?:(?:[^%s%s+:^)]|\^[%s]?[^)])*)' % (_nlws, _punct, _nl)
268 _number = r'(?:-?(?:0[0-7]+|0x[\da-f]+|\d+)%s)' % _token_terminator
269 _opword = r'(?:equ|geq|gtr|leq|lss|neq)'
270 _string = r'(?:"[^%s"]*(?:"|(?=[%s])))' % (_nl, _nl)
271 _variable = (r'(?:(?:%%(?:\*|(?:~[a-z]*(?:\$[^:]+:)?)?\d|'
272 r'[^%%:%s]+(?::(?:~(?:-?\d+)?(?:,(?:-?\d+)?)?|(?:[^%%%s^]|'
273 r'\^[^%%%s])[^=%s]*=(?:[^%%%s^]|\^[^%%%s])*)?)?%%))|'
274 r'(?:\^?![^!:%s]+(?::(?:~(?:-?\d+)?(?:,(?:-?\d+)?)?|(?:'
275 r'[^!%s^]|\^[^!%s])[^=%s]*=(?:[^!%s^]|\^[^!%s])*)?)?\^?!))' %
276 (_nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl))
277 _core_token = r'(?:(?:(?:\^[%s]?)?[^"%s%s])+)' % (_nl, _nlws, _punct)
278 _core_token_compound = r'(?:(?:(?:\^[%s]?)?[^"%s%s)])+)' % (_nl, _nlws, _punct)
279 _token = r'(?:[%s]+|%s)' % (_punct, _core_token)
280 _token_compound = r'(?:[%s]+|%s)' % (_punct, _core_token_compound)
281 _stoken = (r'(?:[%s]+|(?:%s|%s|%s)+)' %
282 (_punct, _string, _variable, _core_token))
284 def _make_begin_state(compound, _core_token=_core_token,
285 _core_token_compound=_core_token_compound,
286 _keyword_terminator=_keyword_terminator,
287 _nl=_nl, _punct=_punct, _string=_string,
288 _space=_space, _start_label=_start_label,
289 _stoken=_stoken, _token_terminator=_token_terminator,
290 _variable=_variable, _ws=_ws):
291 rest = '(?:%s|%s|[^"%%%s%s%s])*' % (_string, _variable, _nl, _punct,
292 ')' if compound else '')
293 rest_of_line = r'(?:(?:[^%s^]|\^[%s]?[\w\W])*)' % (_nl, _nl)
294 rest_of_line_compound = r'(?:(?:[^%s^)]|\^[%s]?[^)])*)' % (_nl, _nl)
295 set_space = r'((?:(?:\^[%s]?)?[^\S\n])*)' % _nl
296 suffix = ''
297 if compound:
298 _keyword_terminator = r'(?:(?=\))|%s)' % _keyword_terminator
299 _token_terminator = r'(?:(?=\))|%s)' % _token_terminator
300 suffix = '/compound'
301 return [
302 ((r'\)', Punctuation, '#pop') if compound else
303 (r'\)((?=\()|%s)%s' % (_token_terminator, rest_of_line),
304 Comment.Single)),
305 (r'(?=%s)' % _start_label, Text, 'follow%s' % suffix),
306 (_space, using(this, state='text')),
307 include('redirect%s' % suffix),
308 (r'[%s]+' % _nl, Text),
309 (r'\(', Punctuation, 'root/compound'),
310 (r'@+', Punctuation),
311 (r'((?:for|if|rem)(?:(?=(?:\^[%s]?)?/)|(?:(?!\^)|'
312 r'(?<=m))(?:(?=\()|%s)))(%s?%s?(?:\^[%s]?)?/(?:\^[%s]?)?\?)' %
313 (_nl, _token_terminator, _space,
314 _core_token_compound if compound else _core_token, _nl, _nl),
315 bygroups(Keyword, using(this, state='text')),
316 'follow%s' % suffix),
317 (r'(goto%s)(%s(?:\^[%s]?)?/(?:\^[%s]?)?\?%s)' %
318 (_keyword_terminator, rest, _nl, _nl, rest),
319 bygroups(Keyword, using(this, state='text')),
320 'follow%s' % suffix),
321 (words(('assoc', 'break', 'cd', 'chdir', 'cls', 'color', 'copy',
322 'date', 'del', 'dir', 'dpath', 'echo', 'endlocal', 'erase',
323 'exit', 'ftype', 'keys', 'md', 'mkdir', 'mklink', 'move',
324 'path', 'pause', 'popd', 'prompt', 'pushd', 'rd', 'ren',
325 'rename', 'rmdir', 'setlocal', 'shift', 'start', 'time',
326 'title', 'type', 'ver', 'verify', 'vol'),
327 suffix=_keyword_terminator), Keyword, 'follow%s' % suffix),
328 (r'(call)(%s?)(:)' % _space,
329 bygroups(Keyword, using(this, state='text'), Punctuation),
330 'call%s' % suffix),
331 (r'call%s' % _keyword_terminator, Keyword),
332 (r'(for%s(?!\^))(%s)(/f%s)' %
333 (_token_terminator, _space, _token_terminator),
334 bygroups(Keyword, using(this, state='text'), Keyword),
335 ('for/f', 'for')),
336 (r'(for%s(?!\^))(%s)(/l%s)' %
337 (_token_terminator, _space, _token_terminator),
338 bygroups(Keyword, using(this, state='text'), Keyword),
339 ('for/l', 'for')),
340 (r'for%s(?!\^)' % _token_terminator, Keyword, ('for2', 'for')),
341 (r'(goto%s)(%s?)(:?)' % (_keyword_terminator, _space),
342 bygroups(Keyword, using(this, state='text'), Punctuation),
343 'label%s' % suffix),
344 (r'(if(?:(?=\()|%s)(?!\^))(%s?)((?:/i%s)?)(%s?)((?:not%s)?)(%s?)' %
345 (_token_terminator, _space, _token_terminator, _space,
346 _token_terminator, _space),
347 bygroups(Keyword, using(this, state='text'), Keyword,
348 using(this, state='text'), Keyword,
349 using(this, state='text')), ('(?', 'if')),
350 (r'rem(((?=\()|%s)%s?%s?.*|%s%s)' %
351 (_token_terminator, _space, _stoken, _keyword_terminator,
352 rest_of_line_compound if compound else rest_of_line),
353 Comment.Single, 'follow%s' % suffix),
354 (r'(set%s)%s(/a)' % (_keyword_terminator, set_space),
355 bygroups(Keyword, using(this, state='text'), Keyword),
356 'arithmetic%s' % suffix),
357 (r'(set%s)%s((?:/p)?)%s((?:(?:(?:\^[%s]?)?[^"%s%s^=%s]|'
358 r'\^[%s]?[^"=])+)?)((?:(?:\^[%s]?)?=)?)' %
359 (_keyword_terminator, set_space, set_space, _nl, _nl, _punct,
360 ')' if compound else '', _nl, _nl),
361 bygroups(Keyword, using(this, state='text'), Keyword,
362 using(this, state='text'), using(this, state='variable'),
363 Punctuation),
364 'follow%s' % suffix),
365 default('follow%s' % suffix)
366 ]
368 def _make_follow_state(compound, _label=_label,
369 _label_compound=_label_compound, _nl=_nl,
370 _space=_space, _start_label=_start_label,
371 _token=_token, _token_compound=_token_compound,
372 _ws=_ws):
373 suffix = '/compound' if compound else ''
374 state = []
375 if compound:
376 state.append((r'(?=\))', Text, '#pop'))
377 state += [
378 (r'%s([%s]*)(%s)(.*)' %
379 (_start_label, _ws, _label_compound if compound else _label),
380 bygroups(Text, Punctuation, Text, Name.Label, Comment.Single)),
381 include('redirect%s' % suffix),
382 (r'(?=[%s])' % _nl, Text, '#pop'),
383 (r'\|\|?|&&?', Punctuation, '#pop'),
384 include('text')
385 ]
386 return state
388 def _make_arithmetic_state(compound, _nl=_nl, _punct=_punct,
389 _string=_string, _variable=_variable,
390 _ws=_ws, _nlws=_nlws):
391 op = r'=+\-*/!~'
392 state = []
393 if compound:
394 state.append((r'(?=\))', Text, '#pop'))
395 state += [
396 (r'0[0-7]+', Number.Oct),
397 (r'0x[\da-f]+', Number.Hex),
398 (r'\d+', Number.Integer),
399 (r'[(),]+', Punctuation),
400 (r'([%s]|%%|\^\^)+' % op, Operator),
401 (r'(%s|%s|(\^[%s]?)?[^()%s%%\^"%s%s]|\^[%s]?%s)+' %
402 (_string, _variable, _nl, op, _nlws, _punct, _nlws,
403 r'[^)]' if compound else r'[\w\W]'),
404 using(this, state='variable')),
405 (r'(?=[\x00|&])', Text, '#pop'),
406 include('follow')
407 ]
408 return state
410 def _make_call_state(compound, _label=_label,
411 _label_compound=_label_compound):
412 state = []
413 if compound:
414 state.append((r'(?=\))', Text, '#pop'))
415 state.append((r'(:?)(%s)' % (_label_compound if compound else _label),
416 bygroups(Punctuation, Name.Label), '#pop'))
417 return state
419 def _make_label_state(compound, _label=_label,
420 _label_compound=_label_compound, _nl=_nl,
421 _punct=_punct, _string=_string, _variable=_variable):
422 state = []
423 if compound:
424 state.append((r'(?=\))', Text, '#pop'))
425 state.append((r'(%s?)((?:%s|%s|\^[%s]?%s|[^"%%^%s%s%s])*)' %
426 (_label_compound if compound else _label, _string,
427 _variable, _nl, r'[^)]' if compound else r'[\w\W]', _nl,
428 _punct, r')' if compound else ''),
429 bygroups(Name.Label, Comment.Single), '#pop'))
430 return state
432 def _make_redirect_state(compound,
433 _core_token_compound=_core_token_compound,
434 _nl=_nl, _punct=_punct, _stoken=_stoken,
435 _string=_string, _space=_space,
436 _variable=_variable, _nlws=_nlws):
437 stoken_compound = (r'(?:[%s]+|(?:%s|%s|%s)+)' %
438 (_punct, _string, _variable, _core_token_compound))
439 return [
440 (r'((?:(?<=[%s])\d)?)(>>?&|<&)([%s]*)(\d)' %
441 (_nlws, _nlws),
442 bygroups(Number.Integer, Punctuation, Text, Number.Integer)),
443 (r'((?:(?<=[%s])(?<!\^[%s])\d)?)(>>?|<)(%s?%s)' %
444 (_nlws, _nl, _space, stoken_compound if compound else _stoken),
445 bygroups(Number.Integer, Punctuation, using(this, state='text')))
446 ]
448 tokens = {
449 'root': _make_begin_state(False),
450 'follow': _make_follow_state(False),
451 'arithmetic': _make_arithmetic_state(False),
452 'call': _make_call_state(False),
453 'label': _make_label_state(False),
454 'redirect': _make_redirect_state(False),
455 'root/compound': _make_begin_state(True),
456 'follow/compound': _make_follow_state(True),
457 'arithmetic/compound': _make_arithmetic_state(True),
458 'call/compound': _make_call_state(True),
459 'label/compound': _make_label_state(True),
460 'redirect/compound': _make_redirect_state(True),
461 'variable-or-escape': [
462 (_variable, Name.Variable),
463 (r'%%%%|\^[%s]?(\^!|[\w\W])' % _nl, String.Escape)
464 ],
465 'string': [
466 (r'"', String.Double, '#pop'),
467 (_variable, Name.Variable),
468 (r'\^!|%%', String.Escape),
469 (r'[^"%%^%s]+|[%%^]' % _nl, String.Double),
470 default('#pop')
471 ],
472 'sqstring': [
473 include('variable-or-escape'),
474 (r'[^%]+|%', String.Single)
475 ],
476 'bqstring': [
477 include('variable-or-escape'),
478 (r'[^%]+|%', String.Backtick)
479 ],
480 'text': [
481 (r'"', String.Double, 'string'),
482 include('variable-or-escape'),
483 (r'[^"%%^%s%s\d)]+|.' % (_nlws, _punct), Text)
484 ],
485 'variable': [
486 (r'"', String.Double, 'string'),
487 include('variable-or-escape'),
488 (r'[^"%%^%s]+|.' % _nl, Name.Variable)
489 ],
490 'for': [
491 (r'(%s)(in)(%s)(\()' % (_space, _space),
492 bygroups(using(this, state='text'), Keyword,
493 using(this, state='text'), Punctuation), '#pop'),
494 include('follow')
495 ],
496 'for2': [
497 (r'\)', Punctuation),
498 (r'(%s)(do%s)' % (_space, _token_terminator),
499 bygroups(using(this, state='text'), Keyword), '#pop'),
500 (r'[%s]+' % _nl, Text),
501 include('follow')
502 ],
503 'for/f': [
504 (r'(")((?:%s|[^"])*?")([%s]*)(\))' % (_variable, _nlws),
505 bygroups(String.Double, using(this, state='string'), Text,
506 Punctuation)),
507 (r'"', String.Double, ('#pop', 'for2', 'string')),
508 (r"('(?:%%%%|%s|[\w\W])*?')([%s]*)(\))" % (_variable, _nlws),
509 bygroups(using(this, state='sqstring'), Text, Punctuation)),
510 (r'(`(?:%%%%|%s|[\w\W])*?`)([%s]*)(\))' % (_variable, _nlws),
511 bygroups(using(this, state='bqstring'), Text, Punctuation)),
512 include('for2')
513 ],
514 'for/l': [
515 (r'-?\d+', Number.Integer),
516 include('for2')
517 ],
518 'if': [
519 (r'((?:cmdextversion|errorlevel)%s)(%s)(\d+)' %
520 (_token_terminator, _space),
521 bygroups(Keyword, using(this, state='text'),
522 Number.Integer), '#pop'),
523 (r'(defined%s)(%s)(%s)' % (_token_terminator, _space, _stoken),
524 bygroups(Keyword, using(this, state='text'),
525 using(this, state='variable')), '#pop'),
526 (r'(exist%s)(%s%s)' % (_token_terminator, _space, _stoken),
527 bygroups(Keyword, using(this, state='text')), '#pop'),
528 (r'(%s%s)(%s)(%s%s)' % (_number, _space, _opword, _space, _number),
529 bygroups(using(this, state='arithmetic'), Operator.Word,
530 using(this, state='arithmetic')), '#pop'),
531 (_stoken, using(this, state='text'), ('#pop', 'if2')),
532 ],
533 'if2': [
534 (r'(%s?)(==)(%s?%s)' % (_space, _space, _stoken),
535 bygroups(using(this, state='text'), Operator,
536 using(this, state='text')), '#pop'),
537 (r'(%s)(%s)(%s%s)' % (_space, _opword, _space, _stoken),
538 bygroups(using(this, state='text'), Operator.Word,
539 using(this, state='text')), '#pop')
540 ],
541 '(?': [
542 (_space, using(this, state='text')),
543 (r'\(', Punctuation, ('#pop', 'else?', 'root/compound')),
544 default('#pop')
545 ],
546 'else?': [
547 (_space, using(this, state='text')),
548 (r'else%s' % _token_terminator, Keyword, '#pop'),
549 default('#pop')
550 ]
551 }
554class MSDOSSessionLexer(ShellSessionBaseLexer):
555 """
556 Lexer for MS DOS shell sessions, i.e. command lines, including a
557 prompt, interspersed with output.
559 .. versionadded:: 2.1
560 """
562 name = 'MSDOS Session'
563 aliases = ['doscon']
564 filenames = []
565 mimetypes = []
567 _innerLexerCls = BatchLexer
568 _ps1rgx = re.compile(r'^([^>]*>)(.*\n?)')
569 _ps2 = 'More? '
572class TcshLexer(RegexLexer):
573 """
574 Lexer for tcsh scripts.
576 .. versionadded:: 0.10
577 """
579 name = 'Tcsh'
580 aliases = ['tcsh', 'csh']
581 filenames = ['*.tcsh', '*.csh']
582 mimetypes = ['application/x-csh']
584 tokens = {
585 'root': [
586 include('basic'),
587 (r'\$\(', Keyword, 'paren'),
588 (r'\$\{#?', Keyword, 'curly'),
589 (r'`', String.Backtick, 'backticks'),
590 include('data'),
591 ],
592 'basic': [
593 (r'\b(if|endif|else|while|then|foreach|case|default|'
594 r'break|continue|goto|breaksw|end|switch|endsw)\s*\b',
595 Keyword),
596 (r'\b(alias|alloc|bg|bindkey|builtins|bye|caller|cd|chdir|'
597 r'complete|dirs|echo|echotc|eval|exec|exit|fg|filetest|getxvers|'
598 r'glob|getspath|hashstat|history|hup|inlib|jobs|kill|'
599 r'limit|log|login|logout|ls-F|migrate|newgrp|nice|nohup|notify|'
600 r'onintr|popd|printenv|pushd|rehash|repeat|rootnode|popd|pushd|'
601 r'set|shift|sched|setenv|setpath|settc|setty|setxvers|shift|'
602 r'source|stop|suspend|source|suspend|telltc|time|'
603 r'umask|unalias|uncomplete|unhash|universe|unlimit|unset|unsetenv|'
604 r'ver|wait|warp|watchlog|where|which)\s*\b',
605 Name.Builtin),
606 (r'#.*', Comment),
607 (r'\\[\w\W]', String.Escape),
608 (r'(\b\w+)(\s*)(=)', bygroups(Name.Variable, Text, Operator)),
609 (r'[\[\]{}()=]+', Operator),
610 (r'<<\s*(\'?)\\?(\w+)[\w\W]+?\2', String),
611 (r';', Punctuation),
612 ],
613 'data': [
614 (r'(?s)"(\\\\|\\[0-7]+|\\.|[^"\\])*"', String.Double),
615 (r"(?s)'(\\\\|\\[0-7]+|\\.|[^'\\])*'", String.Single),
616 (r'\s+', Text),
617 (r'[^=\s\[\]{}()$"\'`\\;#]+', Text),
618 (r'\d+(?= |\Z)', Number),
619 (r'\$#?(\w+|.)', Name.Variable),
620 ],
621 'curly': [
622 (r'\}', Keyword, '#pop'),
623 (r':-', Keyword),
624 (r'\w+', Name.Variable),
625 (r'[^}:"\'`$]+', Punctuation),
626 (r':', Punctuation),
627 include('root'),
628 ],
629 'paren': [
630 (r'\)', Keyword, '#pop'),
631 include('root'),
632 ],
633 'backticks': [
634 (r'`', String.Backtick, '#pop'),
635 include('root'),
636 ],
637 }
640class TcshSessionLexer(ShellSessionBaseLexer):
641 """
642 Lexer for Tcsh sessions, i.e. command lines, including a
643 prompt, interspersed with output.
645 .. versionadded:: 2.1
646 """
648 name = 'Tcsh Session'
649 aliases = ['tcshcon']
650 filenames = []
651 mimetypes = []
653 _innerLexerCls = TcshLexer
654 _ps1rgx = re.compile(r'^([^>]+>)(.*\n?)')
655 _ps2 = '? '
658class PowerShellLexer(RegexLexer):
659 """
660 For Windows PowerShell code.
662 .. versionadded:: 1.5
663 """
664 name = 'PowerShell'
665 aliases = ['powershell', 'pwsh', 'posh', 'ps1', 'psm1']
666 filenames = ['*.ps1', '*.psm1']
667 mimetypes = ['text/x-powershell']
669 flags = re.DOTALL | re.IGNORECASE | re.MULTILINE
671 keywords = (
672 'while validateset validaterange validatepattern validatelength '
673 'validatecount until trap switch return ref process param parameter in '
674 'if global: local: function foreach for finally filter end elseif else '
675 'dynamicparam do default continue cmdletbinding break begin alias \\? '
676 '% #script #private #local #global mandatory parametersetname position '
677 'valuefrompipeline valuefrompipelinebypropertyname '
678 'valuefromremainingarguments helpmessage try catch throw').split()
680 operators = (
681 'and as band bnot bor bxor casesensitive ccontains ceq cge cgt cle '
682 'clike clt cmatch cne cnotcontains cnotlike cnotmatch contains '
683 'creplace eq exact f file ge gt icontains ieq ige igt ile ilike ilt '
684 'imatch ine inotcontains inotlike inotmatch ireplace is isnot le like '
685 'lt match ne not notcontains notlike notmatch or regex replace '
686 'wildcard').split()
688 verbs = (
689 'write where watch wait use update unregister unpublish unprotect '
690 'unlock uninstall undo unblock trace test tee take sync switch '
691 'suspend submit stop step start split sort skip show set send select '
692 'search scroll save revoke resume restore restart resolve resize '
693 'reset request repair rename remove register redo receive read push '
694 'publish protect pop ping out optimize open new move mount merge '
695 'measure lock limit join invoke install initialize import hide group '
696 'grant get format foreach find export expand exit enter enable edit '
697 'dismount disconnect disable deny debug cxnew copy convertto '
698 'convertfrom convert connect confirm compress complete compare close '
699 'clear checkpoint block backup assert approve aggregate add').split()
701 aliases_ = (
702 'ac asnp cat cd cfs chdir clc clear clhy cli clp cls clv cnsn '
703 'compare copy cp cpi cpp curl cvpa dbp del diff dir dnsn ebp echo epal '
704 'epcsv epsn erase etsn exsn fc fhx fl foreach ft fw gal gbp gc gci gcm '
705 'gcs gdr ghy gi gjb gl gm gmo gp gps gpv group gsn gsnp gsv gu gv gwmi '
706 'h history icm iex ihy ii ipal ipcsv ipmo ipsn irm ise iwmi iwr kill lp '
707 'ls man md measure mi mount move mp mv nal ndr ni nmo npssc nsn nv ogv '
708 'oh popd ps pushd pwd r rbp rcjb rcsn rd rdr ren ri rjb rm rmdir rmo '
709 'rni rnp rp rsn rsnp rujb rv rvpa rwmi sajb sal saps sasv sbp sc select '
710 'set shcm si sl sleep sls sort sp spjb spps spsv start sujb sv swmi tee '
711 'trcm type wget where wjb write').split()
713 commenthelp = (
714 'component description example externalhelp forwardhelpcategory '
715 'forwardhelptargetname functionality inputs link '
716 'notes outputs parameter remotehelprunspace role synopsis').split()
718 tokens = {
719 'root': [
720 # we need to count pairs of parentheses for correct highlight
721 # of '$(...)' blocks in strings
722 (r'\(', Punctuation, 'child'),
723 (r'\s+', Text),
724 (r'^(\s*#[#\s]*)(\.(?:%s))([^\n]*$)' % '|'.join(commenthelp),
725 bygroups(Comment, String.Doc, Comment)),
726 (r'#[^\n]*?$', Comment),
727 (r'(<|<)#', Comment.Multiline, 'multline'),
728 (r'@"\n', String.Heredoc, 'heredoc-double'),
729 (r"@'\n.*?\n'@", String.Heredoc),
730 # escaped syntax
731 (r'`[\'"$@-]', Punctuation),
732 (r'"', String.Double, 'string'),
733 (r"'([^']|'')*'", String.Single),
734 (r'(\$|@@|@)((global|script|private|env):)?\w+',
735 Name.Variable),
736 (r'(%s)\b' % '|'.join(keywords), Keyword),
737 (r'-(%s)\b' % '|'.join(operators), Operator),
738 (r'(%s)-[a-z_]\w*\b' % '|'.join(verbs), Name.Builtin),
739 (r'(%s)\s' % '|'.join(aliases_), Name.Builtin),
740 (r'\[[a-z_\[][\w. `,\[\]]*\]', Name.Constant), # .net [type]s
741 (r'-[a-z_]\w*', Name),
742 (r'\w+', Name),
743 (r'[.,;:@{}\[\]$()=+*/\\&%!~?^`|<>-]', Punctuation),
744 ],
745 'child': [
746 (r'\)', Punctuation, '#pop'),
747 include('root'),
748 ],
749 'multline': [
750 (r'[^#&.]+', Comment.Multiline),
751 (r'#(>|>)', Comment.Multiline, '#pop'),
752 (r'\.(%s)' % '|'.join(commenthelp), String.Doc),
753 (r'[#&.]', Comment.Multiline),
754 ],
755 'string': [
756 (r"`[0abfnrtv'\"$`]", String.Escape),
757 (r'[^$`"]+', String.Double),
758 (r'\$\(', Punctuation, 'child'),
759 (r'""', String.Double),
760 (r'[`$]', String.Double),
761 (r'"', String.Double, '#pop'),
762 ],
763 'heredoc-double': [
764 (r'\n"@', String.Heredoc, '#pop'),
765 (r'\$\(', Punctuation, 'child'),
766 (r'[^@\n]+"]', String.Heredoc),
767 (r".", String.Heredoc),
768 ]
769 }
772class PowerShellSessionLexer(ShellSessionBaseLexer):
773 """
774 Lexer for PowerShell sessions, i.e. command lines, including a
775 prompt, interspersed with output.
777 .. versionadded:: 2.1
778 """
780 name = 'PowerShell Session'
781 aliases = ['pwsh-session', 'ps1con']
782 filenames = []
783 mimetypes = []
785 _innerLexerCls = PowerShellLexer
786 _bare_continuation = True
787 _ps1rgx = re.compile(r'^((?:\[[^]]+\]: )?PS[^>]*> ?)(.*\n?)')
788 _ps2 = '> '
791class FishShellLexer(RegexLexer):
792 """
793 Lexer for Fish shell scripts.
795 .. versionadded:: 2.1
796 """
798 name = 'Fish'
799 aliases = ['fish', 'fishshell']
800 filenames = ['*.fish', '*.load']
801 mimetypes = ['application/x-fish']
803 tokens = {
804 'root': [
805 include('basic'),
806 include('data'),
807 include('interp'),
808 ],
809 'interp': [
810 (r'\$\(\(', Keyword, 'math'),
811 (r'\(', Keyword, 'paren'),
812 (r'\$#?(\w+|.)', Name.Variable),
813 ],
814 'basic': [
815 (r'\b(begin|end|if|else|while|break|for|in|return|function|block|'
816 r'case|continue|switch|not|and|or|set|echo|exit|pwd|true|false|'
817 r'cd|count|test)(\s*)\b',
818 bygroups(Keyword, Text)),
819 (r'\b(alias|bg|bind|breakpoint|builtin|command|commandline|'
820 r'complete|contains|dirh|dirs|emit|eval|exec|fg|fish|fish_config|'
821 r'fish_indent|fish_pager|fish_prompt|fish_right_prompt|'
822 r'fish_update_completions|fishd|funced|funcsave|functions|help|'
823 r'history|isatty|jobs|math|mimedb|nextd|open|popd|prevd|psub|'
824 r'pushd|random|read|set_color|source|status|trap|type|ulimit|'
825 r'umask|vared|fc|getopts|hash|kill|printf|time|wait)\s*\b(?!\.)',
826 Name.Builtin),
827 (r'#.*\n', Comment),
828 (r'\\[\w\W]', String.Escape),
829 (r'(\b\w+)(\s*)(=)', bygroups(Name.Variable, Whitespace, Operator)),
830 (r'[\[\]()=]', Operator),
831 (r'<<-?\s*(\'?)\\?(\w+)[\w\W]+?\2', String),
832 ],
833 'data': [
834 (r'(?s)\$?"(\\\\|\\[0-7]+|\\.|[^"\\$])*"', String.Double),
835 (r'"', String.Double, 'string'),
836 (r"(?s)\$'(\\\\|\\[0-7]+|\\.|[^'\\])*'", String.Single),
837 (r"(?s)'.*?'", String.Single),
838 (r';', Punctuation),
839 (r'&|\||\^|<|>', Operator),
840 (r'\s+', Text),
841 (r'\d+(?= |\Z)', Number),
842 (r'[^=\s\[\]{}()$"\'`\\<&|;]+', Text),
843 ],
844 'string': [
845 (r'"', String.Double, '#pop'),
846 (r'(?s)(\\\\|\\[0-7]+|\\.|[^"\\$])+', String.Double),
847 include('interp'),
848 ],
849 'paren': [
850 (r'\)', Keyword, '#pop'),
851 include('root'),
852 ],
853 'math': [
854 (r'\)\)', Keyword, '#pop'),
855 (r'[-+*/%^|&]|\*\*|\|\|', Operator),
856 (r'\d+#\d+', Number),
857 (r'\d+#(?! )', Number),
858 (r'\d+', Number),
859 include('root'),
860 ],
861 }
863class ExeclineLexer(RegexLexer):
864 """
865 Lexer for Laurent Bercot's execline language
866 (https://skarnet.org/software/execline).
868 .. versionadded:: 2.7
869 """
871 name = 'execline'
872 aliases = ['execline']
873 filenames = ['*.exec']
875 tokens = {
876 'root': [
877 include('basic'),
878 include('data'),
879 include('interp')
880 ],
881 'interp': [
882 (r'\$\{', String.Interpol, 'curly'),
883 (r'\$[\w@#]+', Name.Variable), # user variable
884 (r'\$', Text),
885 ],
886 'basic': [
887 (r'\b(background|backtick|cd|define|dollarat|elgetopt|'
888 r'elgetpositionals|elglob|emptyenv|envfile|exec|execlineb|'
889 r'exit|export|fdblock|fdclose|fdmove|fdreserve|fdswap|'
890 r'forbacktickx|foreground|forstdin|forx|getcwd|getpid|heredoc|'
891 r'homeof|if|ifelse|ifte|ifthenelse|importas|loopwhilex|'
892 r'multidefine|multisubstitute|pipeline|piperw|posix-cd|'
893 r'redirfd|runblock|shift|trap|tryexec|umask|unexport|wait|'
894 r'withstdinas)\b', Name.Builtin),
895 (r'\A#!.+\n', Comment.Hashbang),
896 (r'#.*\n', Comment.Single),
897 (r'[{}]', Operator)
898 ],
899 'data': [
900 (r'(?s)"(\\.|[^"\\$])*"', String.Double),
901 (r'"', String.Double, 'string'),
902 (r'\s+', Text),
903 (r'[^\s{}$"\\]+', Text)
904 ],
905 'string': [
906 (r'"', String.Double, '#pop'),
907 (r'(?s)(\\\\|\\.|[^"\\$])+', String.Double),
908 include('interp'),
909 ],
910 'curly': [
911 (r'\}', String.Interpol, '#pop'),
912 (r'[\w#@]+', Name.Variable),
913 include('root')
914 ]
916 }
918 def analyse_text(text):
919 if shebang_matches(text, r'execlineb'):
920 return 1