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