eric6/ThirdParty/Pygments/pygments/lexers/python.py

changeset 6942
2602857055c5
parent 6651
e8f3b5568b21
child 7547
21b0534faebc
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2 """
3 pygments.lexers.python
4 ~~~~~~~~~~~~~~~~~~~~~~
5
6 Lexers for Python and related languages.
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, include, bygroups, using, \
15 default, words, combined, do_insertions
16 from pygments.util import get_bool_opt, shebang_matches
17 from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
18 Number, Punctuation, Generic, Other, Error
19 from pygments import unistring as uni
20
21 __all__ = ['PythonLexer', 'PythonConsoleLexer', 'PythonTracebackLexer',
22 'Python3Lexer', 'Python3TracebackLexer', 'CythonLexer',
23 'DgLexer', 'NumPyLexer']
24
25 line_re = re.compile('.*?\n')
26
27
28 class PythonLexer(RegexLexer):
29 """
30 For `Python <http://www.python.org>`_ source code.
31 """
32
33 name = 'Python'
34 aliases = ['python', 'py', 'sage']
35 filenames = ['*.py', '*.pyw', '*.sc', 'SConstruct', 'SConscript', '*.tac', '*.sage']
36 mimetypes = ['text/x-python', 'application/x-python']
37
38 def innerstring_rules(ttype):
39 return [
40 # the old style '%s' % (...) string formatting
41 (r'%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?'
42 '[hlL]?[E-GXc-giorsux%]', String.Interpol),
43 # backslashes, quotes and formatting signs must be parsed one at a time
44 (r'[^\\\'"%\n]+', ttype),
45 (r'[\'"\\]', ttype),
46 # unhandled string formatting sign
47 (r'%', ttype),
48 # newlines are an error (use "nl" state)
49 ]
50
51 tokens = {
52 'root': [
53 (r'\n', Text),
54 (r'^(\s*)([rRuUbB]{,2})("""(?:.|\n)*?""")',
55 bygroups(Text, String.Affix, String.Doc)),
56 (r"^(\s*)([rRuUbB]{,2})('''(?:.|\n)*?''')",
57 bygroups(Text, String.Affix, String.Doc)),
58 (r'[^\S\n]+', Text),
59 (r'\A#!.+$', Comment.Hashbang),
60 (r'#.*$', Comment.Single),
61 (r'[]{}:(),;[]', Punctuation),
62 (r'\\\n', Text),
63 (r'\\', Text),
64 (r'(in|is|and|or|not)\b', Operator.Word),
65 (r'!=|==|<<|>>|[-~+/*%=<>&^|.]', Operator),
66 include('keywords'),
67 (r'(def)((?:\s|\\\s)+)', bygroups(Keyword, Text), 'funcname'),
68 (r'(class)((?:\s|\\\s)+)', bygroups(Keyword, Text), 'classname'),
69 (r'(from)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Text),
70 'fromimport'),
71 (r'(import)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Text),
72 'import'),
73 include('builtins'),
74 include('magicfuncs'),
75 include('magicvars'),
76 include('backtick'),
77 ('([rR]|[uUbB][rR]|[rR][uUbB])(""")',
78 bygroups(String.Affix, String.Double), 'tdqs'),
79 ("([rR]|[uUbB][rR]|[rR][uUbB])(''')",
80 bygroups(String.Affix, String.Single), 'tsqs'),
81 ('([rR]|[uUbB][rR]|[rR][uUbB])(")',
82 bygroups(String.Affix, String.Double), 'dqs'),
83 ("([rR]|[uUbB][rR]|[rR][uUbB])(')",
84 bygroups(String.Affix, String.Single), 'sqs'),
85 ('([uUbB]?)(""")', bygroups(String.Affix, String.Double),
86 combined('stringescape', 'tdqs')),
87 ("([uUbB]?)(''')", bygroups(String.Affix, String.Single),
88 combined('stringescape', 'tsqs')),
89 ('([uUbB]?)(")', bygroups(String.Affix, String.Double),
90 combined('stringescape', 'dqs')),
91 ("([uUbB]?)(')", bygroups(String.Affix, String.Single),
92 combined('stringescape', 'sqs')),
93 include('name'),
94 include('numbers'),
95 ],
96 'keywords': [
97 (words((
98 'assert', 'break', 'continue', 'del', 'elif', 'else', 'except',
99 'exec', 'finally', 'for', 'global', 'if', 'lambda', 'pass',
100 'print', 'raise', 'return', 'try', 'while', 'yield',
101 'yield from', 'as', 'with'), suffix=r'\b'),
102 Keyword),
103 ],
104 'builtins': [
105 (words((
106 '__import__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin',
107 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod',
108 'cmp', 'coerce', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
109 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float',
110 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'hex', 'id',
111 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len',
112 'list', 'locals', 'long', 'map', 'max', 'min', 'next', 'object',
113 'oct', 'open', 'ord', 'pow', 'property', 'range', 'raw_input', 'reduce',
114 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
115 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type',
116 'unichr', 'unicode', 'vars', 'xrange', 'zip'),
117 prefix=r'(?<!\.)', suffix=r'\b'),
118 Name.Builtin),
119 (r'(?<!\.)(self|None|Ellipsis|NotImplemented|False|True|cls'
120 r')\b', Name.Builtin.Pseudo),
121 (words((
122 'ArithmeticError', 'AssertionError', 'AttributeError',
123 'BaseException', 'DeprecationWarning', 'EOFError', 'EnvironmentError',
124 'Exception', 'FloatingPointError', 'FutureWarning', 'GeneratorExit',
125 'IOError', 'ImportError', 'ImportWarning', 'IndentationError',
126 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
127 'MemoryError', 'ModuleNotFoundError', 'NameError', 'NotImplemented', 'NotImplementedError',
128 'OSError', 'OverflowError', 'OverflowWarning', 'PendingDeprecationWarning',
129 'RecursionError', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError',
130 'StopIteration', 'StopAsyncIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError',
131 'SystemExit', 'TabError', 'TypeError', 'UnboundLocalError',
132 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError',
133 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning',
134 'ValueError', 'VMSError', 'Warning', 'WindowsError',
135 'ZeroDivisionError'), prefix=r'(?<!\.)', suffix=r'\b'),
136 Name.Exception),
137 ],
138 'magicfuncs': [
139 (words((
140 '__abs__', '__add__', '__and__', '__call__', '__cmp__', '__coerce__',
141 '__complex__', '__contains__', '__del__', '__delattr__', '__delete__',
142 '__delitem__', '__delslice__', '__div__', '__divmod__', '__enter__',
143 '__eq__', '__exit__', '__float__', '__floordiv__', '__ge__', '__get__',
144 '__getattr__', '__getattribute__', '__getitem__', '__getslice__', '__gt__',
145 '__hash__', '__hex__', '__iadd__', '__iand__', '__idiv__', '__ifloordiv__',
146 '__ilshift__', '__imod__', '__imul__', '__index__', '__init__',
147 '__instancecheck__', '__int__', '__invert__', '__iop__', '__ior__',
148 '__ipow__', '__irshift__', '__isub__', '__iter__', '__itruediv__',
149 '__ixor__', '__le__', '__len__', '__long__', '__lshift__', '__lt__',
150 '__missing__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__',
151 '__nonzero__', '__oct__', '__op__', '__or__', '__pos__', '__pow__',
152 '__radd__', '__rand__', '__rcmp__', '__rdiv__', '__rdivmod__', '__repr__',
153 '__reversed__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__',
154 '__rop__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__',
155 '__rtruediv__', '__rxor__', '__set__', '__setattr__', '__setitem__',
156 '__setslice__', '__str__', '__sub__', '__subclasscheck__', '__truediv__',
157 '__unicode__', '__xor__'), suffix=r'\b'),
158 Name.Function.Magic),
159 ],
160 'magicvars': [
161 (words((
162 '__bases__', '__class__', '__closure__', '__code__', '__defaults__',
163 '__dict__', '__doc__', '__file__', '__func__', '__globals__',
164 '__metaclass__', '__module__', '__mro__', '__name__', '__self__',
165 '__slots__', '__weakref__'),
166 suffix=r'\b'),
167 Name.Variable.Magic),
168 ],
169 'numbers': [
170 (r'(\d+\.\d*|\d*\.\d+)([eE][+-]?[0-9]+)?j?', Number.Float),
171 (r'\d+[eE][+-]?[0-9]+j?', Number.Float),
172 (r'0[0-7]+j?', Number.Oct),
173 (r'0[bB][01]+', Number.Bin),
174 (r'0[xX][a-fA-F0-9]+', Number.Hex),
175 (r'\d+L', Number.Integer.Long),
176 (r'\d+j?', Number.Integer)
177 ],
178 'backtick': [
179 ('`.*?`', String.Backtick),
180 ],
181 'name': [
182 (r'@[\w.]+', Name.Decorator),
183 (r'[a-zA-Z_]\w*', Name),
184 ],
185 'funcname': [
186 include('magicfuncs'),
187 (r'[a-zA-Z_]\w*', Name.Function, '#pop'),
188 default('#pop'),
189 ],
190 'classname': [
191 (r'[a-zA-Z_]\w*', Name.Class, '#pop')
192 ],
193 'import': [
194 (r'(?:[ \t]|\\\n)+', Text),
195 (r'as\b', Keyword.Namespace),
196 (r',', Operator),
197 (r'[a-zA-Z_][\w.]*', Name.Namespace),
198 default('#pop') # all else: go back
199 ],
200 'fromimport': [
201 (r'(?:[ \t]|\\\n)+', Text),
202 (r'import\b', Keyword.Namespace, '#pop'),
203 # if None occurs here, it's "raise x from None", since None can
204 # never be a module name
205 (r'None\b', Name.Builtin.Pseudo, '#pop'),
206 # sadly, in "raise x from y" y will be highlighted as namespace too
207 (r'[a-zA-Z_.][\w.]*', Name.Namespace),
208 # anything else here also means "raise x from y" and is therefore
209 # not an error
210 default('#pop'),
211 ],
212 'stringescape': [
213 (r'\\([\\abfnrtv"\']|\n|N\{.*?\}|u[a-fA-F0-9]{4}|'
214 r'U[a-fA-F0-9]{8}|x[a-fA-F0-9]{2}|[0-7]{1,3})', String.Escape)
215 ],
216 'strings-single': innerstring_rules(String.Single),
217 'strings-double': innerstring_rules(String.Double),
218 'dqs': [
219 (r'"', String.Double, '#pop'),
220 (r'\\\\|\\"|\\\n', String.Escape), # included here for raw strings
221 include('strings-double')
222 ],
223 'sqs': [
224 (r"'", String.Single, '#pop'),
225 (r"\\\\|\\'|\\\n", String.Escape), # included here for raw strings
226 include('strings-single')
227 ],
228 'tdqs': [
229 (r'"""', String.Double, '#pop'),
230 include('strings-double'),
231 (r'\n', String.Double)
232 ],
233 'tsqs': [
234 (r"'''", String.Single, '#pop'),
235 include('strings-single'),
236 (r'\n', String.Single)
237 ],
238 }
239
240 def analyse_text(text):
241 return shebang_matches(text, r'pythonw?(2(\.\d)?)?') or \
242 'import ' in text[:1000]
243
244
245 class Python3Lexer(RegexLexer):
246 """
247 For `Python <http://www.python.org>`_ source code (version 3.0).
248
249 .. versionadded:: 0.10
250 """
251
252 name = 'Python 3'
253 aliases = ['python3', 'py3']
254 filenames = [] # Nothing until Python 3 gets widespread
255 mimetypes = ['text/x-python3', 'application/x-python3']
256
257 flags = re.MULTILINE | re.UNICODE
258
259 uni_name = "[%s][%s]*" % (uni.xid_start, uni.xid_continue)
260
261 def innerstring_rules(ttype):
262 return [
263 # the old style '%s' % (...) string formatting (still valid in Py3)
264 (r'%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?'
265 '[hlL]?[E-GXc-giorsaux%]', String.Interpol),
266 # the new style '{}'.format(...) string formatting
267 (r'\{'
268 r'((\w+)((\.\w+)|(\[[^\]]+\]))*)?' # field name
269 r'(\![sra])?' # conversion
270 r'(\:(.?[<>=\^])?[-+ ]?#?0?(\d+)?,?(\.\d+)?[E-GXb-gnosx%]?)?'
271 r'\}', String.Interpol),
272
273 # backslashes, quotes and formatting signs must be parsed one at a time
274 (r'[^\\\'"%{\n]+', ttype),
275 (r'[\'"\\]', ttype),
276 # unhandled string formatting sign
277 (r'%|(\{{1,2})', ttype)
278 # newlines are an error (use "nl" state)
279 ]
280
281 tokens = PythonLexer.tokens.copy()
282 tokens['keywords'] = [
283 (words((
284 'assert', 'async', 'await', 'break', 'continue', 'del', 'elif',
285 'else', 'except', 'finally', 'for', 'global', 'if', 'lambda', 'pass',
286 'raise', 'nonlocal', 'return', 'try', 'while', 'yield', 'yield from',
287 'as', 'with'), suffix=r'\b'),
288 Keyword),
289 (words((
290 'True', 'False', 'None'), suffix=r'\b'),
291 Keyword.Constant),
292 ]
293 tokens['builtins'] = [
294 (words((
295 '__import__', 'abs', 'all', 'any', 'bin', 'bool', 'bytearray', 'bytes',
296 'chr', 'classmethod', 'cmp', 'compile', 'complex', 'delattr', 'dict',
297 'dir', 'divmod', 'enumerate', 'eval', 'filter', 'float', 'format',
298 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'hex', 'id',
299 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'list',
300 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct',
301 'open', 'ord', 'pow', 'print', 'property', 'range', 'repr', 'reversed',
302 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str',
303 'sum', 'super', 'tuple', 'type', 'vars', 'zip'), prefix=r'(?<!\.)',
304 suffix=r'\b'),
305 Name.Builtin),
306 (r'(?<!\.)(self|Ellipsis|NotImplemented|cls)\b', Name.Builtin.Pseudo),
307 (words((
308 'ArithmeticError', 'AssertionError', 'AttributeError',
309 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning',
310 'EOFError', 'EnvironmentError', 'Exception', 'FloatingPointError',
311 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError',
312 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError',
313 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError',
314 'NotImplementedError', 'OSError', 'OverflowError',
315 'PendingDeprecationWarning', 'ReferenceError', 'ResourceWarning',
316 'RuntimeError', 'RuntimeWarning', 'StopIteration',
317 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError',
318 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError',
319 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError',
320 'UnicodeWarning', 'UserWarning', 'ValueError', 'VMSError', 'Warning',
321 'WindowsError', 'ZeroDivisionError',
322 # new builtin exceptions from PEP 3151
323 'BlockingIOError', 'ChildProcessError', 'ConnectionError',
324 'BrokenPipeError', 'ConnectionAbortedError', 'ConnectionRefusedError',
325 'ConnectionResetError', 'FileExistsError', 'FileNotFoundError',
326 'InterruptedError', 'IsADirectoryError', 'NotADirectoryError',
327 'PermissionError', 'ProcessLookupError', 'TimeoutError'),
328 prefix=r'(?<!\.)', suffix=r'\b'),
329 Name.Exception),
330 ]
331 tokens['magicfuncs'] = [
332 (words((
333 '__abs__', '__add__', '__aenter__', '__aexit__', '__aiter__', '__and__',
334 '__anext__', '__await__', '__bool__', '__bytes__', '__call__',
335 '__complex__', '__contains__', '__del__', '__delattr__', '__delete__',
336 '__delitem__', '__dir__', '__divmod__', '__enter__', '__eq__', '__exit__',
337 '__float__', '__floordiv__', '__format__', '__ge__', '__get__',
338 '__getattr__', '__getattribute__', '__getitem__', '__gt__', '__hash__',
339 '__iadd__', '__iand__', '__ifloordiv__', '__ilshift__', '__imatmul__',
340 '__imod__', '__import__', '__imul__', '__index__', '__init__',
341 '__instancecheck__', '__int__', '__invert__', '__ior__', '__ipow__',
342 '__irshift__', '__isub__', '__iter__', '__itruediv__', '__ixor__',
343 '__le__', '__len__', '__length_hint__', '__lshift__', '__lt__',
344 '__matmul__', '__missing__', '__mod__', '__mul__', '__ne__', '__neg__',
345 '__new__', '__next__', '__or__', '__pos__', '__pow__', '__prepare__',
346 '__radd__', '__rand__', '__rdivmod__', '__repr__', '__reversed__',
347 '__rfloordiv__', '__rlshift__', '__rmatmul__', '__rmod__', '__rmul__',
348 '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__',
349 '__rsub__', '__rtruediv__', '__rxor__', '__set__', '__setattr__',
350 '__setitem__', '__str__', '__sub__', '__subclasscheck__', '__truediv__',
351 '__xor__'), suffix=r'\b'),
352 Name.Function.Magic),
353 ]
354 tokens['magicvars'] = [
355 (words((
356 '__annotations__', '__bases__', '__class__', '__closure__', '__code__',
357 '__defaults__', '__dict__', '__doc__', '__file__', '__func__',
358 '__globals__', '__kwdefaults__', '__module__', '__mro__', '__name__',
359 '__objclass__', '__qualname__', '__self__', '__slots__', '__weakref__'),
360 suffix=r'\b'),
361 Name.Variable.Magic),
362 ]
363 tokens['numbers'] = [
364 (r'(\d(?:_?\d)*\.(?:\d(?:_?\d)*)?|(?:\d(?:_?\d)*)?\.\d(?:_?\d)*)([eE][+-]?\d(?:_?\d)*)?', Number.Float),
365 (r'\d(?:_?\d)*[eE][+-]?\d(?:_?\d)*j?', Number.Float),
366 (r'0[oO](?:_?[0-7])+', Number.Oct),
367 (r'0[bB](?:_?[01])+', Number.Bin),
368 (r'0[xX](?:_?[a-fA-F0-9])+', Number.Hex),
369 (r'\d(?:_?\d)*', Number.Integer)
370 ]
371 tokens['backtick'] = []
372 tokens['name'] = [
373 (r'@\w+', Name.Decorator),
374 (r'@', Operator), # new matrix multiplication operator
375 (uni_name, Name),
376 ]
377 tokens['funcname'] = [
378 (uni_name, Name.Function, '#pop')
379 ]
380 tokens['classname'] = [
381 (uni_name, Name.Class, '#pop')
382 ]
383 tokens['import'] = [
384 (r'(\s+)(as)(\s+)', bygroups(Text, Keyword, Text)),
385 (r'\.', Name.Namespace),
386 (uni_name, Name.Namespace),
387 (r'(\s*)(,)(\s*)', bygroups(Text, Operator, Text)),
388 default('#pop') # all else: go back
389 ]
390 tokens['fromimport'] = [
391 (r'(\s+)(import)\b', bygroups(Text, Keyword), '#pop'),
392 (r'\.', Name.Namespace),
393 (uni_name, Name.Namespace),
394 default('#pop'),
395 ]
396 tokens['strings-single'] = innerstring_rules(String.Single)
397 tokens['strings-double'] = innerstring_rules(String.Double)
398
399
400 def analyse_text(text):
401 return shebang_matches(text, r'pythonw?3(\.\d)?')
402
403
404 class PythonConsoleLexer(Lexer):
405 """
406 For Python console output or doctests, such as:
407
408 .. sourcecode:: pycon
409
410 >>> a = 'foo'
411 >>> print a
412 foo
413 >>> 1 / 0
414 Traceback (most recent call last):
415 File "<stdin>", line 1, in <module>
416 ZeroDivisionError: integer division or modulo by zero
417
418 Additional options:
419
420 `python3`
421 Use Python 3 lexer for code. Default is ``False``.
422
423 .. versionadded:: 1.0
424 """
425 name = 'Python console session'
426 aliases = ['pycon']
427 mimetypes = ['text/x-python-doctest']
428
429 def __init__(self, **options):
430 self.python3 = get_bool_opt(options, 'python3', False)
431 Lexer.__init__(self, **options)
432
433 def get_tokens_unprocessed(self, text):
434 if self.python3:
435 pylexer = Python3Lexer(**self.options)
436 tblexer = Python3TracebackLexer(**self.options)
437 else:
438 pylexer = PythonLexer(**self.options)
439 tblexer = PythonTracebackLexer(**self.options)
440
441 curcode = ''
442 insertions = []
443 curtb = ''
444 tbindex = 0
445 tb = 0
446 for match in line_re.finditer(text):
447 line = match.group()
448 if line.startswith(u'>>> ') or line.startswith(u'... '):
449 tb = 0
450 insertions.append((len(curcode),
451 [(0, Generic.Prompt, line[:4])]))
452 curcode += line[4:]
453 elif line.rstrip() == u'...' and not tb:
454 # only a new >>> prompt can end an exception block
455 # otherwise an ellipsis in place of the traceback frames
456 # will be mishandled
457 insertions.append((len(curcode),
458 [(0, Generic.Prompt, u'...')]))
459 curcode += line[3:]
460 else:
461 if curcode:
462 for item in do_insertions(
463 insertions, pylexer.get_tokens_unprocessed(curcode)):
464 yield item
465 curcode = ''
466 insertions = []
467 if (line.startswith(u'Traceback (most recent call last):') or
468 re.match(u' File "[^"]+", line \\d+\\n$', line)):
469 tb = 1
470 curtb = line
471 tbindex = match.start()
472 elif line == 'KeyboardInterrupt\n':
473 yield match.start(), Name.Class, line
474 elif tb:
475 curtb += line
476 if not (line.startswith(' ') or line.strip() == u'...'):
477 tb = 0
478 for i, t, v in tblexer.get_tokens_unprocessed(curtb):
479 yield tbindex+i, t, v
480 curtb = ''
481 else:
482 yield match.start(), Generic.Output, line
483 if curcode:
484 for item in do_insertions(insertions,
485 pylexer.get_tokens_unprocessed(curcode)):
486 yield item
487 if curtb:
488 for i, t, v in tblexer.get_tokens_unprocessed(curtb):
489 yield tbindex+i, t, v
490
491
492 class PythonTracebackLexer(RegexLexer):
493 """
494 For Python tracebacks.
495
496 .. versionadded:: 0.7
497 """
498
499 name = 'Python Traceback'
500 aliases = ['pytb']
501 filenames = ['*.pytb']
502 mimetypes = ['text/x-python-traceback']
503
504 tokens = {
505 'root': [
506 # Cover both (most recent call last) and (innermost last)
507 # The optional ^C allows us to catch keyboard interrupt signals.
508 (r'^(\^C)?(Traceback.*\n)',
509 bygroups(Text, Generic.Traceback), 'intb'),
510 # SyntaxError starts with this.
511 (r'^(?= File "[^"]+", line \d+)', Generic.Traceback, 'intb'),
512 (r'^.*\n', Other),
513 ],
514 'intb': [
515 (r'^( File )("[^"]+")(, line )(\d+)(, in )(.+)(\n)',
516 bygroups(Text, Name.Builtin, Text, Number, Text, Name, Text)),
517 (r'^( File )("[^"]+")(, line )(\d+)(\n)',
518 bygroups(Text, Name.Builtin, Text, Number, Text)),
519 (r'^( )(.+)(\n)',
520 bygroups(Text, using(PythonLexer), Text)),
521 (r'^([ \t]*)(\.\.\.)(\n)',
522 bygroups(Text, Comment, Text)), # for doctests...
523 (r'^([^:]+)(: )(.+)(\n)',
524 bygroups(Generic.Error, Text, Name, Text), '#pop'),
525 (r'^([a-zA-Z_]\w*)(:?\n)',
526 bygroups(Generic.Error, Text), '#pop')
527 ],
528 }
529
530
531 class Python3TracebackLexer(RegexLexer):
532 """
533 For Python 3.0 tracebacks, with support for chained exceptions.
534
535 .. versionadded:: 1.0
536 """
537
538 name = 'Python 3.0 Traceback'
539 aliases = ['py3tb']
540 filenames = ['*.py3tb']
541 mimetypes = ['text/x-python3-traceback']
542
543 tokens = {
544 'root': [
545 (r'\n', Text),
546 (r'^Traceback \(most recent call last\):\n', Generic.Traceback, 'intb'),
547 (r'^During handling of the above exception, another '
548 r'exception occurred:\n\n', Generic.Traceback),
549 (r'^The above exception was the direct cause of the '
550 r'following exception:\n\n', Generic.Traceback),
551 (r'^(?= File "[^"]+", line \d+)', Generic.Traceback, 'intb'),
552 ],
553 'intb': [
554 (r'^( File )("[^"]+")(, line )(\d+)(, in )(.+)(\n)',
555 bygroups(Text, Name.Builtin, Text, Number, Text, Name, Text)),
556 (r'^( File )("[^"]+")(, line )(\d+)(\n)',
557 bygroups(Text, Name.Builtin, Text, Number, Text)),
558 (r'^( )(.+)(\n)',
559 bygroups(Text, using(Python3Lexer), Text)),
560 (r'^([ \t]*)(\.\.\.)(\n)',
561 bygroups(Text, Comment, Text)), # for doctests...
562 (r'^([^:]+)(: )(.+)(\n)',
563 bygroups(Generic.Error, Text, Name, Text), '#pop'),
564 (r'^([a-zA-Z_]\w*)(:?\n)',
565 bygroups(Generic.Error, Text), '#pop')
566 ],
567 }
568
569
570 class CythonLexer(RegexLexer):
571 """
572 For Pyrex and `Cython <http://cython.org>`_ source code.
573
574 .. versionadded:: 1.1
575 """
576
577 name = 'Cython'
578 aliases = ['cython', 'pyx', 'pyrex']
579 filenames = ['*.pyx', '*.pxd', '*.pxi']
580 mimetypes = ['text/x-cython', 'application/x-cython']
581
582 tokens = {
583 'root': [
584 (r'\n', Text),
585 (r'^(\s*)("""(?:.|\n)*?""")', bygroups(Text, String.Doc)),
586 (r"^(\s*)('''(?:.|\n)*?''')", bygroups(Text, String.Doc)),
587 (r'[^\S\n]+', Text),
588 (r'#.*$', Comment),
589 (r'[]{}:(),;[]', Punctuation),
590 (r'\\\n', Text),
591 (r'\\', Text),
592 (r'(in|is|and|or|not)\b', Operator.Word),
593 (r'(<)([a-zA-Z0-9.?]+)(>)',
594 bygroups(Punctuation, Keyword.Type, Punctuation)),
595 (r'!=|==|<<|>>|[-~+/*%=<>&^|.?]', Operator),
596 (r'(from)(\d+)(<=)(\s+)(<)(\d+)(:)',
597 bygroups(Keyword, Number.Integer, Operator, Name, Operator,
598 Name, Punctuation)),
599 include('keywords'),
600 (r'(def|property)(\s+)', bygroups(Keyword, Text), 'funcname'),
601 (r'(cp?def)(\s+)', bygroups(Keyword, Text), 'cdef'),
602 # (should actually start a block with only cdefs)
603 (r'(cdef)(:)', bygroups(Keyword, Punctuation)),
604 (r'(class|struct)(\s+)', bygroups(Keyword, Text), 'classname'),
605 (r'(from)(\s+)', bygroups(Keyword, Text), 'fromimport'),
606 (r'(c?import)(\s+)', bygroups(Keyword, Text), 'import'),
607 include('builtins'),
608 include('backtick'),
609 ('(?:[rR]|[uU][rR]|[rR][uU])"""', String, 'tdqs'),
610 ("(?:[rR]|[uU][rR]|[rR][uU])'''", String, 'tsqs'),
611 ('(?:[rR]|[uU][rR]|[rR][uU])"', String, 'dqs'),
612 ("(?:[rR]|[uU][rR]|[rR][uU])'", String, 'sqs'),
613 ('[uU]?"""', String, combined('stringescape', 'tdqs')),
614 ("[uU]?'''", String, combined('stringescape', 'tsqs')),
615 ('[uU]?"', String, combined('stringescape', 'dqs')),
616 ("[uU]?'", String, combined('stringescape', 'sqs')),
617 include('name'),
618 include('numbers'),
619 ],
620 'keywords': [
621 (words((
622 'assert', 'break', 'by', 'continue', 'ctypedef', 'del', 'elif',
623 'else', 'except', 'except?', 'exec', 'finally', 'for', 'fused', 'gil',
624 'global', 'if', 'include', 'lambda', 'nogil', 'pass', 'print',
625 'raise', 'return', 'try', 'while', 'yield', 'as', 'with'), suffix=r'\b'),
626 Keyword),
627 (r'(DEF|IF|ELIF|ELSE)\b', Comment.Preproc),
628 ],
629 'builtins': [
630 (words((
631 '__import__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin',
632 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr',
633 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'delattr',
634 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit',
635 'file', 'filter', 'float', 'frozenset', 'getattr', 'globals',
636 'hasattr', 'hash', 'hex', 'id', 'input', 'int', 'intern', 'isinstance',
637 'issubclass', 'iter', 'len', 'list', 'locals', 'long', 'map', 'max',
638 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'property',
639 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed',
640 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod',
641 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'unsigned',
642 'vars', 'xrange', 'zip'), prefix=r'(?<!\.)', suffix=r'\b'),
643 Name.Builtin),
644 (r'(?<!\.)(self|None|Ellipsis|NotImplemented|False|True|NULL'
645 r')\b', Name.Builtin.Pseudo),
646 (words((
647 'ArithmeticError', 'AssertionError', 'AttributeError',
648 'BaseException', 'DeprecationWarning', 'EOFError', 'EnvironmentError',
649 'Exception', 'FloatingPointError', 'FutureWarning', 'GeneratorExit',
650 'IOError', 'ImportError', 'ImportWarning', 'IndentationError',
651 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
652 'MemoryError', 'NameError', 'NotImplemented', 'NotImplementedError',
653 'OSError', 'OverflowError', 'OverflowWarning',
654 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError',
655 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError',
656 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError',
657 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError',
658 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError',
659 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning',
660 'ZeroDivisionError'), prefix=r'(?<!\.)', suffix=r'\b'),
661 Name.Exception),
662 ],
663 'numbers': [
664 (r'(\d+\.?\d*|\d*\.\d+)([eE][+-]?[0-9]+)?', Number.Float),
665 (r'0\d+', Number.Oct),
666 (r'0[xX][a-fA-F0-9]+', Number.Hex),
667 (r'\d+L', Number.Integer.Long),
668 (r'\d+', Number.Integer)
669 ],
670 'backtick': [
671 ('`.*?`', String.Backtick),
672 ],
673 'name': [
674 (r'@\w+', Name.Decorator),
675 (r'[a-zA-Z_]\w*', Name),
676 ],
677 'funcname': [
678 (r'[a-zA-Z_]\w*', Name.Function, '#pop')
679 ],
680 'cdef': [
681 (r'(public|readonly|extern|api|inline)\b', Keyword.Reserved),
682 (r'(struct|enum|union|class)\b', Keyword),
683 (r'([a-zA-Z_]\w*)(\s*)(?=[(:#=]|$)',
684 bygroups(Name.Function, Text), '#pop'),
685 (r'([a-zA-Z_]\w*)(\s*)(,)',
686 bygroups(Name.Function, Text, Punctuation)),
687 (r'from\b', Keyword, '#pop'),
688 (r'as\b', Keyword),
689 (r':', Punctuation, '#pop'),
690 (r'(?=["\'])', Text, '#pop'),
691 (r'[a-zA-Z_]\w*', Keyword.Type),
692 (r'.', Text),
693 ],
694 'classname': [
695 (r'[a-zA-Z_]\w*', Name.Class, '#pop')
696 ],
697 'import': [
698 (r'(\s+)(as)(\s+)', bygroups(Text, Keyword, Text)),
699 (r'[a-zA-Z_][\w.]*', Name.Namespace),
700 (r'(\s*)(,)(\s*)', bygroups(Text, Operator, Text)),
701 default('#pop') # all else: go back
702 ],
703 'fromimport': [
704 (r'(\s+)(c?import)\b', bygroups(Text, Keyword), '#pop'),
705 (r'[a-zA-Z_.][\w.]*', Name.Namespace),
706 # ``cdef foo from "header"``, or ``for foo from 0 < i < 10``
707 default('#pop'),
708 ],
709 'stringescape': [
710 (r'\\([\\abfnrtv"\']|\n|N\{.*?\}|u[a-fA-F0-9]{4}|'
711 r'U[a-fA-F0-9]{8}|x[a-fA-F0-9]{2}|[0-7]{1,3})', String.Escape)
712 ],
713 'strings': [
714 (r'%(\([a-zA-Z0-9]+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?'
715 '[hlL]?[E-GXc-giorsux%]', String.Interpol),
716 (r'[^\\\'"%\n]+', String),
717 # quotes, percents and backslashes must be parsed one at a time
718 (r'[\'"\\]', String),
719 # unhandled string formatting sign
720 (r'%', String)
721 # newlines are an error (use "nl" state)
722 ],
723 'nl': [
724 (r'\n', String)
725 ],
726 'dqs': [
727 (r'"', String, '#pop'),
728 (r'\\\\|\\"|\\\n', String.Escape), # included here again for raw strings
729 include('strings')
730 ],
731 'sqs': [
732 (r"'", String, '#pop'),
733 (r"\\\\|\\'|\\\n", String.Escape), # included here again for raw strings
734 include('strings')
735 ],
736 'tdqs': [
737 (r'"""', String, '#pop'),
738 include('strings'),
739 include('nl')
740 ],
741 'tsqs': [
742 (r"'''", String, '#pop'),
743 include('strings'),
744 include('nl')
745 ],
746 }
747
748
749 class DgLexer(RegexLexer):
750 """
751 Lexer for `dg <http://pyos.github.com/dg>`_,
752 a functional and object-oriented programming language
753 running on the CPython 3 VM.
754
755 .. versionadded:: 1.6
756 """
757 name = 'dg'
758 aliases = ['dg']
759 filenames = ['*.dg']
760 mimetypes = ['text/x-dg']
761
762 tokens = {
763 'root': [
764 (r'\s+', Text),
765 (r'#.*?$', Comment.Single),
766
767 (r'(?i)0b[01]+', Number.Bin),
768 (r'(?i)0o[0-7]+', Number.Oct),
769 (r'(?i)0x[0-9a-f]+', Number.Hex),
770 (r'(?i)[+-]?[0-9]+\.[0-9]+(e[+-]?[0-9]+)?j?', Number.Float),
771 (r'(?i)[+-]?[0-9]+e[+-]?\d+j?', Number.Float),
772 (r'(?i)[+-]?[0-9]+j?', Number.Integer),
773
774 (r"(?i)(br|r?b?)'''", String, combined('stringescape', 'tsqs', 'string')),
775 (r'(?i)(br|r?b?)"""', String, combined('stringescape', 'tdqs', 'string')),
776 (r"(?i)(br|r?b?)'", String, combined('stringescape', 'sqs', 'string')),
777 (r'(?i)(br|r?b?)"', String, combined('stringescape', 'dqs', 'string')),
778
779 (r"`\w+'*`", Operator),
780 (r'\b(and|in|is|or|where)\b', Operator.Word),
781 (r'[!$%&*+\-./:<-@\\^|~;,]+', Operator),
782
783 (words((
784 'bool', 'bytearray', 'bytes', 'classmethod', 'complex', 'dict', 'dict\'',
785 'float', 'frozenset', 'int', 'list', 'list\'', 'memoryview', 'object',
786 'property', 'range', 'set', 'set\'', 'slice', 'staticmethod', 'str',
787 'super', 'tuple', 'tuple\'', 'type'),
788 prefix=r'(?<!\.)', suffix=r'(?![\'\w])'),
789 Name.Builtin),
790 (words((
791 '__import__', 'abs', 'all', 'any', 'bin', 'bind', 'chr', 'cmp', 'compile',
792 'complex', 'delattr', 'dir', 'divmod', 'drop', 'dropwhile', 'enumerate',
793 'eval', 'exhaust', 'filter', 'flip', 'foldl1?', 'format', 'fst',
794 'getattr', 'globals', 'hasattr', 'hash', 'head', 'hex', 'id', 'init',
795 'input', 'isinstance', 'issubclass', 'iter', 'iterate', 'last', 'len',
796 'locals', 'map', 'max', 'min', 'next', 'oct', 'open', 'ord', 'pow',
797 'print', 'repr', 'reversed', 'round', 'setattr', 'scanl1?', 'snd',
798 'sorted', 'sum', 'tail', 'take', 'takewhile', 'vars', 'zip'),
799 prefix=r'(?<!\.)', suffix=r'(?![\'\w])'),
800 Name.Builtin),
801 (r"(?<!\.)(self|Ellipsis|NotImplemented|None|True|False)(?!['\w])",
802 Name.Builtin.Pseudo),
803
804 (r"(?<!\.)[A-Z]\w*(Error|Exception|Warning)'*(?!['\w])",
805 Name.Exception),
806 (r"(?<!\.)(Exception|GeneratorExit|KeyboardInterrupt|StopIteration|"
807 r"SystemExit)(?!['\w])", Name.Exception),
808
809 (r"(?<![\w.])(except|finally|for|if|import|not|otherwise|raise|"
810 r"subclass|while|with|yield)(?!['\w])", Keyword.Reserved),
811
812 (r"[A-Z_]+'*(?!['\w])", Name),
813 (r"[A-Z]\w+'*(?!['\w])", Keyword.Type),
814 (r"\w+'*", Name),
815
816 (r'[()]', Punctuation),
817 (r'.', Error),
818 ],
819 'stringescape': [
820 (r'\\([\\abfnrtv"\']|\n|N\{.*?\}|u[a-fA-F0-9]{4}|'
821 r'U[a-fA-F0-9]{8}|x[a-fA-F0-9]{2}|[0-7]{1,3})', String.Escape)
822 ],
823 'string': [
824 (r'%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?'
825 '[hlL]?[E-GXc-giorsux%]', String.Interpol),
826 (r'[^\\\'"%\n]+', String),
827 # quotes, percents and backslashes must be parsed one at a time
828 (r'[\'"\\]', String),
829 # unhandled string formatting sign
830 (r'%', String),
831 (r'\n', String)
832 ],
833 'dqs': [
834 (r'"', String, '#pop')
835 ],
836 'sqs': [
837 (r"'", String, '#pop')
838 ],
839 'tdqs': [
840 (r'"""', String, '#pop')
841 ],
842 'tsqs': [
843 (r"'''", String, '#pop')
844 ],
845 }
846
847
848 class NumPyLexer(PythonLexer):
849 """
850 A Python lexer recognizing Numerical Python builtins.
851
852 .. versionadded:: 0.10
853 """
854
855 name = 'NumPy'
856 aliases = ['numpy']
857
858 # override the mimetypes to not inherit them from python
859 mimetypes = []
860 filenames = []
861
862 EXTRA_KEYWORDS = set((
863 'abs', 'absolute', 'accumulate', 'add', 'alen', 'all', 'allclose',
864 'alltrue', 'alterdot', 'amax', 'amin', 'angle', 'any', 'append',
865 'apply_along_axis', 'apply_over_axes', 'arange', 'arccos', 'arccosh',
866 'arcsin', 'arcsinh', 'arctan', 'arctan2', 'arctanh', 'argmax', 'argmin',
867 'argsort', 'argwhere', 'around', 'array', 'array2string', 'array_equal',
868 'array_equiv', 'array_repr', 'array_split', 'array_str', 'arrayrange',
869 'asanyarray', 'asarray', 'asarray_chkfinite', 'ascontiguousarray',
870 'asfarray', 'asfortranarray', 'asmatrix', 'asscalar', 'astype',
871 'atleast_1d', 'atleast_2d', 'atleast_3d', 'average', 'bartlett',
872 'base_repr', 'beta', 'binary_repr', 'bincount', 'binomial',
873 'bitwise_and', 'bitwise_not', 'bitwise_or', 'bitwise_xor', 'blackman',
874 'bmat', 'broadcast', 'byte_bounds', 'bytes', 'byteswap', 'c_',
875 'can_cast', 'ceil', 'choose', 'clip', 'column_stack', 'common_type',
876 'compare_chararrays', 'compress', 'concatenate', 'conj', 'conjugate',
877 'convolve', 'copy', 'corrcoef', 'correlate', 'cos', 'cosh', 'cov',
878 'cross', 'cumprod', 'cumproduct', 'cumsum', 'delete', 'deprecate',
879 'diag', 'diagflat', 'diagonal', 'diff', 'digitize', 'disp', 'divide',
880 'dot', 'dsplit', 'dstack', 'dtype', 'dump', 'dumps', 'ediff1d', 'empty',
881 'empty_like', 'equal', 'exp', 'expand_dims', 'expm1', 'extract', 'eye',
882 'fabs', 'fastCopyAndTranspose', 'fft', 'fftfreq', 'fftshift', 'fill',
883 'finfo', 'fix', 'flat', 'flatnonzero', 'flatten', 'fliplr', 'flipud',
884 'floor', 'floor_divide', 'fmod', 'frexp', 'fromarrays', 'frombuffer',
885 'fromfile', 'fromfunction', 'fromiter', 'frompyfunc', 'fromstring',
886 'generic', 'get_array_wrap', 'get_include', 'get_numarray_include',
887 'get_numpy_include', 'get_printoptions', 'getbuffer', 'getbufsize',
888 'geterr', 'geterrcall', 'geterrobj', 'getfield', 'gradient', 'greater',
889 'greater_equal', 'gumbel', 'hamming', 'hanning', 'histogram',
890 'histogram2d', 'histogramdd', 'hsplit', 'hstack', 'hypot', 'i0',
891 'identity', 'ifft', 'imag', 'index_exp', 'indices', 'inf', 'info',
892 'inner', 'insert', 'int_asbuffer', 'interp', 'intersect1d',
893 'intersect1d_nu', 'inv', 'invert', 'iscomplex', 'iscomplexobj',
894 'isfinite', 'isfortran', 'isinf', 'isnan', 'isneginf', 'isposinf',
895 'isreal', 'isrealobj', 'isscalar', 'issctype', 'issubclass_',
896 'issubdtype', 'issubsctype', 'item', 'itemset', 'iterable', 'ix_',
897 'kaiser', 'kron', 'ldexp', 'left_shift', 'less', 'less_equal', 'lexsort',
898 'linspace', 'load', 'loads', 'loadtxt', 'log', 'log10', 'log1p', 'log2',
899 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'logspace',
900 'lstsq', 'mat', 'matrix', 'max', 'maximum', 'maximum_sctype',
901 'may_share_memory', 'mean', 'median', 'meshgrid', 'mgrid', 'min',
902 'minimum', 'mintypecode', 'mod', 'modf', 'msort', 'multiply', 'nan',
903 'nan_to_num', 'nanargmax', 'nanargmin', 'nanmax', 'nanmin', 'nansum',
904 'ndenumerate', 'ndim', 'ndindex', 'negative', 'newaxis', 'newbuffer',
905 'newbyteorder', 'nonzero', 'not_equal', 'obj2sctype', 'ogrid', 'ones',
906 'ones_like', 'outer', 'permutation', 'piecewise', 'pinv', 'pkgload',
907 'place', 'poisson', 'poly', 'poly1d', 'polyadd', 'polyder', 'polydiv',
908 'polyfit', 'polyint', 'polymul', 'polysub', 'polyval', 'power', 'prod',
909 'product', 'ptp', 'put', 'putmask', 'r_', 'randint', 'random_integers',
910 'random_sample', 'ranf', 'rank', 'ravel', 'real', 'real_if_close',
911 'recarray', 'reciprocal', 'reduce', 'remainder', 'repeat', 'require',
912 'reshape', 'resize', 'restoredot', 'right_shift', 'rint', 'roll',
913 'rollaxis', 'roots', 'rot90', 'round', 'round_', 'row_stack', 's_',
914 'sample', 'savetxt', 'sctype2char', 'searchsorted', 'seed', 'select',
915 'set_numeric_ops', 'set_printoptions', 'set_string_function',
916 'setbufsize', 'setdiff1d', 'seterr', 'seterrcall', 'seterrobj',
917 'setfield', 'setflags', 'setmember1d', 'setxor1d', 'shape',
918 'show_config', 'shuffle', 'sign', 'signbit', 'sin', 'sinc', 'sinh',
919 'size', 'slice', 'solve', 'sometrue', 'sort', 'sort_complex', 'source',
920 'split', 'sqrt', 'square', 'squeeze', 'standard_normal', 'std',
921 'subtract', 'sum', 'svd', 'swapaxes', 'take', 'tan', 'tanh', 'tensordot',
922 'test', 'tile', 'tofile', 'tolist', 'tostring', 'trace', 'transpose',
923 'trapz', 'tri', 'tril', 'trim_zeros', 'triu', 'true_divide', 'typeDict',
924 'typename', 'uniform', 'union1d', 'unique', 'unique1d', 'unravel_index',
925 'unwrap', 'vander', 'var', 'vdot', 'vectorize', 'view', 'vonmises',
926 'vsplit', 'vstack', 'weibull', 'where', 'who', 'zeros', 'zeros_like'
927 ))
928
929 def get_tokens_unprocessed(self, text):
930 for index, token, value in \
931 PythonLexer.get_tokens_unprocessed(self, text):
932 if token is Name and value in self.EXTRA_KEYWORDS:
933 yield index, Keyword.Pseudo, value
934 else:
935 yield index, token, value
936
937 def analyse_text(text):
938 return (shebang_matches(text, r'pythonw?(2(\.\d)?)?') or
939 'import ' in text[:1000]) \
940 and ('import numpy' in text or 'from numpy import' in text)

eric ide

mercurial