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