18 from pygments.util import shebang_matches |
18 from pygments.util import shebang_matches |
19 |
19 |
20 |
20 |
21 __all__ = ['BashLexer', 'BashSessionLexer', 'TcshLexer', 'BatchLexer', |
21 __all__ = ['BashLexer', 'BashSessionLexer', 'TcshLexer', 'BatchLexer', |
22 'SlurmBashLexer', 'MSDOSSessionLexer', 'PowerShellLexer', |
22 'SlurmBashLexer', 'MSDOSSessionLexer', 'PowerShellLexer', |
23 'PowerShellSessionLexer', 'TcshSessionLexer', 'FishShellLexer'] |
23 'PowerShellSessionLexer', 'TcshSessionLexer', 'FishShellLexer', |
|
24 'ExeclineLexer'] |
24 |
25 |
25 line_re = re.compile('.*?\n') |
26 line_re = re.compile('.*?\n') |
26 |
27 |
27 |
28 |
28 class BashLexer(RegexLexer): |
29 class BashLexer(RegexLexer): |
247 flags = re.MULTILINE | re.IGNORECASE |
248 flags = re.MULTILINE | re.IGNORECASE |
248 |
249 |
249 _nl = r'\n\x1a' |
250 _nl = r'\n\x1a' |
250 _punct = r'&<>|' |
251 _punct = r'&<>|' |
251 _ws = r'\t\v\f\r ,;=\xa0' |
252 _ws = r'\t\v\f\r ,;=\xa0' |
|
253 _nlws = r'\s\x1a\xa0,;=' |
252 _space = r'(?:(?:(?:\^[%s])?[%s])+)' % (_nl, _ws) |
254 _space = r'(?:(?:(?:\^[%s])?[%s])+)' % (_nl, _ws) |
253 _keyword_terminator = (r'(?=(?:\^[%s]?)?[%s+./:[\\\]]|[%s%s(])' % |
255 _keyword_terminator = (r'(?=(?:\^[%s]?)?[%s+./:[\\\]]|[%s%s(])' % |
254 (_nl, _ws, _nl, _punct)) |
256 (_nl, _ws, _nl, _punct)) |
255 _token_terminator = r'(?=\^?[%s]|[%s%s])' % (_ws, _punct, _nl) |
257 _token_terminator = r'(?=\^?[%s]|[%s%s])' % (_ws, _punct, _nl) |
256 _start_label = r'((?:(?<=^[^:])|^[^:]?)[%s]*)(:)' % _ws |
258 _start_label = r'((?:(?<=^[^:])|^[^:]?)[%s]*)(:)' % _ws |
257 _label = r'(?:(?:[^%s%s%s+:^]|\^[%s]?[\w\W])*)' % (_nl, _punct, _ws, _nl) |
259 _label = r'(?:(?:[^%s%s+:^]|\^[%s]?[\w\W])*)' % (_nlws, _punct, _nl) |
258 _label_compound = (r'(?:(?:[^%s%s%s+:^)]|\^[%s]?[^)])*)' % |
260 _label_compound = r'(?:(?:[^%s%s+:^)]|\^[%s]?[^)])*)' % (_nlws, _punct, _nl) |
259 (_nl, _punct, _ws, _nl)) |
|
260 _number = r'(?:-?(?:0[0-7]+|0x[\da-f]+|\d+)%s)' % _token_terminator |
261 _number = r'(?:-?(?:0[0-7]+|0x[\da-f]+|\d+)%s)' % _token_terminator |
261 _opword = r'(?:equ|geq|gtr|leq|lss|neq)' |
262 _opword = r'(?:equ|geq|gtr|leq|lss|neq)' |
262 _string = r'(?:"[^%s"]*(?:"|(?=[%s])))' % (_nl, _nl) |
263 _string = r'(?:"[^%s"]*(?:"|(?=[%s])))' % (_nl, _nl) |
263 _variable = (r'(?:(?:%%(?:\*|(?:~[a-z]*(?:\$[^:]+:)?)?\d|' |
264 _variable = (r'(?:(?:%%(?:\*|(?:~[a-z]*(?:\$[^:]+:)?)?\d|' |
264 r'[^%%:%s]+(?::(?:~(?:-?\d+)?(?:,(?:-?\d+)?)?|(?:[^%%%s^]|' |
265 r'[^%%:%s]+(?::(?:~(?:-?\d+)?(?:,(?:-?\d+)?)?|(?:[^%%%s^]|' |
265 r'\^[^%%%s])[^=%s]*=(?:[^%%%s^]|\^[^%%%s])*)?)?%%))|' |
266 r'\^[^%%%s])[^=%s]*=(?:[^%%%s^]|\^[^%%%s])*)?)?%%))|' |
266 r'(?:\^?![^!:%s]+(?::(?:~(?:-?\d+)?(?:,(?:-?\d+)?)?|(?:' |
267 r'(?:\^?![^!:%s]+(?::(?:~(?:-?\d+)?(?:,(?:-?\d+)?)?|(?:' |
267 r'[^!%s^]|\^[^!%s])[^=%s]*=(?:[^!%s^]|\^[^!%s])*)?)?\^?!))' % |
268 r'[^!%s^]|\^[^!%s])[^=%s]*=(?:[^!%s^]|\^[^!%s])*)?)?\^?!))' % |
268 (_nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl)) |
269 (_nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl, _nl)) |
269 _core_token = r'(?:(?:(?:\^[%s]?)?[^"%s%s%s])+)' % (_nl, _nl, _punct, _ws) |
270 _core_token = r'(?:(?:(?:\^[%s]?)?[^"%s%s])+)' % (_nl, _nlws, _punct) |
270 _core_token_compound = r'(?:(?:(?:\^[%s]?)?[^"%s%s%s)])+)' % (_nl, _nl, |
271 _core_token_compound = r'(?:(?:(?:\^[%s]?)?[^"%s%s)])+)' % (_nl, _nlws, _punct) |
271 _punct, _ws) |
|
272 _token = r'(?:[%s]+|%s)' % (_punct, _core_token) |
272 _token = r'(?:[%s]+|%s)' % (_punct, _core_token) |
273 _token_compound = r'(?:[%s]+|%s)' % (_punct, _core_token_compound) |
273 _token_compound = r'(?:[%s]+|%s)' % (_punct, _core_token_compound) |
274 _stoken = (r'(?:[%s]+|(?:%s|%s|%s)+)' % |
274 _stoken = (r'(?:[%s]+|(?:%s|%s|%s)+)' % |
275 (_punct, _string, _variable, _core_token)) |
275 (_punct, _string, _variable, _core_token)) |
276 |
276 |
377 include('text') |
377 include('text') |
378 ] |
378 ] |
379 return state |
379 return state |
380 |
380 |
381 def _make_arithmetic_state(compound, _nl=_nl, _punct=_punct, |
381 def _make_arithmetic_state(compound, _nl=_nl, _punct=_punct, |
382 _string=_string, _variable=_variable, _ws=_ws): |
382 _string=_string, _variable=_variable, |
|
383 _ws=_ws, _nlws=_nlws): |
383 op = r'=+\-*/!~' |
384 op = r'=+\-*/!~' |
384 state = [] |
385 state = [] |
385 if compound: |
386 if compound: |
386 state.append((r'(?=\))', Text, '#pop')) |
387 state.append((r'(?=\))', Text, '#pop')) |
387 state += [ |
388 state += [ |
388 (r'0[0-7]+', Number.Oct), |
389 (r'0[0-7]+', Number.Oct), |
389 (r'0x[\da-f]+', Number.Hex), |
390 (r'0x[\da-f]+', Number.Hex), |
390 (r'\d+', Number.Integer), |
391 (r'\d+', Number.Integer), |
391 (r'[(),]+', Punctuation), |
392 (r'[(),]+', Punctuation), |
392 (r'([%s]|%%|\^\^)+' % op, Operator), |
393 (r'([%s]|%%|\^\^)+' % op, Operator), |
393 (r'(%s|%s|(\^[%s]?)?[^()%s%%^"%s%s%s]|\^[%s%s]?%s)+' % |
394 (r'(%s|%s|(\^[%s]?)?[^()%s%%\^"%s%s]|\^[%s]?%s)+' % |
394 (_string, _variable, _nl, op, _nl, _punct, _ws, _nl, _ws, |
395 (_string, _variable, _nl, op, _nlws, _punct, _nlws, |
395 r'[^)]' if compound else r'[\w\W]'), |
396 r'[^)]' if compound else r'[\w\W]'), |
396 using(this, state='variable')), |
397 using(this, state='variable')), |
397 (r'(?=[\x00|&])', Text, '#pop'), |
398 (r'(?=[\x00|&])', Text, '#pop'), |
398 include('follow') |
399 include('follow') |
399 ] |
400 ] |
423 |
424 |
424 def _make_redirect_state(compound, |
425 def _make_redirect_state(compound, |
425 _core_token_compound=_core_token_compound, |
426 _core_token_compound=_core_token_compound, |
426 _nl=_nl, _punct=_punct, _stoken=_stoken, |
427 _nl=_nl, _punct=_punct, _stoken=_stoken, |
427 _string=_string, _space=_space, |
428 _string=_string, _space=_space, |
428 _variable=_variable, _ws=_ws): |
429 _variable=_variable, _nlws=_nlws): |
429 stoken_compound = (r'(?:[%s]+|(?:%s|%s|%s)+)' % |
430 stoken_compound = (r'(?:[%s]+|(?:%s|%s|%s)+)' % |
430 (_punct, _string, _variable, _core_token_compound)) |
431 (_punct, _string, _variable, _core_token_compound)) |
431 return [ |
432 return [ |
432 (r'((?:(?<=[%s%s])\d)?)(>>?&|<&)([%s%s]*)(\d)' % |
433 (r'((?:(?<=[%s])\d)?)(>>?&|<&)([%s]*)(\d)' % |
433 (_nl, _ws, _nl, _ws), |
434 (_nlws, _nlws), |
434 bygroups(Number.Integer, Punctuation, Text, Number.Integer)), |
435 bygroups(Number.Integer, Punctuation, Text, Number.Integer)), |
435 (r'((?:(?<=[%s%s])(?<!\^[%s])\d)?)(>>?|<)(%s?%s)' % |
436 (r'((?:(?<=[%s])(?<!\^[%s])\d)?)(>>?|<)(%s?%s)' % |
436 (_nl, _ws, _nl, _space, stoken_compound if compound else _stoken), |
437 (_nlws, _nl, _space, stoken_compound if compound else _stoken), |
437 bygroups(Number.Integer, Punctuation, using(this, state='text'))) |
438 bygroups(Number.Integer, Punctuation, using(this, state='text'))) |
438 ] |
439 ] |
439 |
440 |
440 tokens = { |
441 tokens = { |
441 'root': _make_begin_state(False), |
442 'root': _make_begin_state(False), |
470 (r'[^%]+|%', String.Backtick) |
471 (r'[^%]+|%', String.Backtick) |
471 ], |
472 ], |
472 'text': [ |
473 'text': [ |
473 (r'"', String.Double, 'string'), |
474 (r'"', String.Double, 'string'), |
474 include('variable-or-escape'), |
475 include('variable-or-escape'), |
475 (r'[^"%%^%s%s%s\d)]+|.' % (_nl, _punct, _ws), Text) |
476 (r'[^"%%^%s%s\d)]+|.' % (_nlws, _punct), Text) |
476 ], |
477 ], |
477 'variable': [ |
478 'variable': [ |
478 (r'"', String.Double, 'string'), |
479 (r'"', String.Double, 'string'), |
479 include('variable-or-escape'), |
480 include('variable-or-escape'), |
480 (r'[^"%%^%s]+|.' % _nl, Name.Variable) |
481 (r'[^"%%^%s]+|.' % _nl, Name.Variable) |
491 bygroups(using(this, state='text'), Keyword), '#pop'), |
492 bygroups(using(this, state='text'), Keyword), '#pop'), |
492 (r'[%s]+' % _nl, Text), |
493 (r'[%s]+' % _nl, Text), |
493 include('follow') |
494 include('follow') |
494 ], |
495 ], |
495 'for/f': [ |
496 'for/f': [ |
496 (r'(")((?:%s|[^"])*?")([%s%s]*)(\))' % (_variable, _nl, _ws), |
497 (r'(")((?:%s|[^"])*?")([%s]*)(\))' % (_variable, _nlws), |
497 bygroups(String.Double, using(this, state='string'), Text, |
498 bygroups(String.Double, using(this, state='string'), Text, |
498 Punctuation)), |
499 Punctuation)), |
499 (r'"', String.Double, ('#pop', 'for2', 'string')), |
500 (r'"', String.Double, ('#pop', 'for2', 'string')), |
500 (r"('(?:%%%%|%s|[\w\W])*?')([%s%s]*)(\))" % (_variable, _nl, _ws), |
501 (r"('(?:%%%%|%s|[\w\W])*?')([%s]*)(\))" % (_variable, _nlws), |
501 bygroups(using(this, state='sqstring'), Text, Punctuation)), |
502 bygroups(using(this, state='sqstring'), Text, Punctuation)), |
502 (r'(`(?:%%%%|%s|[\w\W])*?`)([%s%s]*)(\))' % (_variable, _nl, _ws), |
503 (r'(`(?:%%%%|%s|[\w\W])*?`)([%s]*)(\))' % (_variable, _nlws), |
503 bygroups(using(this, state='bqstring'), Text, Punctuation)), |
504 bygroups(using(this, state='bqstring'), Text, Punctuation)), |
504 include('for2') |
505 include('for2') |
505 ], |
506 ], |
506 'for/l': [ |
507 'for/l': [ |
507 (r'-?\d+', Number.Integer), |
508 (r'-?\d+', Number.Integer), |
845 (r'\d+#(?! )', Number), |
846 (r'\d+#(?! )', Number), |
846 (r'\d+', Number), |
847 (r'\d+', Number), |
847 include('root'), |
848 include('root'), |
848 ], |
849 ], |
849 } |
850 } |
|
851 |
|
852 class 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 |