Index: Misc/Vim/vim_syntax.py =================================================================== --- Misc/Vim/vim_syntax.py (revision 77235) +++ Misc/Vim/vim_syntax.py (working copy) @@ -1,23 +1,51 @@ -from __future__ import with_statement -# XXX(nnorwitz): what versions of python is this file supposed to work with? -# It uses the old print statement not in py3k. - import keyword -import exceptions import builtins -from string import Template from sys import subversion -comment_header = '''" Auto-generated Vim syntax file for Python (%s: r%s). +import functools + +_comment = """\ +" Auto-generated Vim syntax file for Python ({1}: r{2}). " -" To use: copy or symlink to ~/.vim/syntax/python.vim''' +" To use: copy or symlink to ~/.vim/syntax/python.vim +" +" Options to control Python syntax highlighting: +" +" For highlighted numbers: +" +" let python_highlight_numbers = 1 +" +" For highlighted builtin functions: +" +" let python_highlight_builtins = 1 +" +" Highlight erroneous whitespace: +" +" let python_highlight_space_errors = 1 +" +" If you want all possible Python highlighting (the same as setting the +" preceding options): +" +" let python_highlight_all = 1 +" +""".format(*subversion) -statement_header = """ -if exists("b:current_syntax") +_if_exists = """\ +if exists("{0}") +{1}endif +""" + +_finish = """\ finish -endif""" +""" -statement_footer = ''' +_let_all = """\ + let python_highlight_numbers = 1 + let python_highlight_builtins = 1 + let python_highlight_space_errors = 1 +""" + +_post_scriptum = """ " Uncomment the 'minlines' statement line and comment out the 'maxlines' " statement line; changes behaviour to look at least 2000 lines previously for " syntax matches instead of at most 200 lines @@ -25,205 +53,395 @@ syn sync maxlines=200 "syn sync minlines=2000 -let b:current_syntax = "python"''' +let b:current_syntax = "python" -looping = ('for', 'while') -conditionals = ('if', 'elif', 'else') -boolean_ops = ('and', 'in', 'is', 'not', 'or') -import_stmts = ('import', 'from') -object_defs = ('def', 'class') +""" -exception_names = sorted(exc for exc in dir(exceptions) - if not exc.startswith('__')) +keywords = { + 'pythonConditional' : ('if', 'elif', 'else'), + 'pythonLooping' : ('for', 'while'), + 'pythonException' : ('try', 'except', 'finally', 'raise'), + 'pythonContext' : ('with',), + 'pythonDefinition' : ('def', 'class'), + 'pythonBoolean' : ('and', 'in', 'is', 'not', 'or'), + 'pythonImport' : ('from', 'import',), + 'pythonConstant' : ('True', 'False', 'None', '__debug__'), + 'other': ('as',), # handled separetely +} -# Need to include functions that start with '__' (e.g., __import__), but -# nothing that comes with modules (e.g., __name__), so just exclude anything in -# the 'exceptions' module since we want to ignore exceptions *and* what any -# module would have -builtin_names = sorted(builtin for builtin in dir(builtins) - if builtin not in dir(exceptions)) +keywords['pythonStatement'] = sorted( + set(keyword.kwlist).difference(*keywords.values()) +) -escapes = (r'+\\[abfnrtv\'"\\]+', r'"\\\o\{1,3}"', r'"\\x\x\{2}"', - r'"\(\\u\x\{4}\|\\U\x\{8}\)"', r'"\\$"') +keywords['pythonTodo'] = ('TODO', 'FIXME', 'XXX') -todos = ("TODO", "FIXME", "XXX") +# Need to include builtin functions that start with '__' (e.g., __import__), +# but nothing that comes with modules (e.g., __name__), so just exclude +# anything in the 'keyword' module since we want to ignore what any module +# would have. Also True, False and None should be excluded, by excluding +# 'keywords.values()'. +# Exceptions also count as builtins. +builtin_names = sorted( + set(dir(builtins)).difference( + dir(keyword), + *keywords.values() + ) +) -# XXX codify? -numbers = (r'"\<0x\x\+[Ll]\=\>"', r'"\<\d\+[LljJ]\=\>"', - '"\.\d\+\([eE][+-]\=\d\+\)\=[jJ]\=\>"', - '"\<\d\+\.\([eE][+-]\=\d\+\)\=[jJ]\=\>"', - '"\<\d\+\.\d\+\([eE][+-]\=\d\+\)\=[jJ]\=\>"') +line_join = r'"\\$"' -contained = lambda x: "%s contained" % x +escapes = ( + r'"\\[\\\'\"abfnrtv]"', # \\ \' \" \a \b \f \n \r \t \v + r'"\\[0-7]\{1,3}"', # \ooo + r'"\\x\x\{2}"', # \xhh +) -def str_regexes(): - """Generator to yield various combinations of strings regexes""" - regex_template = Template('matchgroup=Normal ' + - 'start=+[uU]\=${raw}${sep}+ ' + - 'end=+${sep}+ ' + - '${skip} ' + - '${contains}') - skip_regex = Template(r'skip=+\\\\\|\\${sep}+') - for raw in ('', '[rR]'): - for separator in ("'", '"', '"""', "'''"): - if len(separator) == 1: - skip = skip_regex.substitute(sep=separator) +# XXX: I do not know, what can and what can not be a 'name' in the Unicode +# database. '\N{name}' pattern should be corrected, so .. +str_escapes = ( + r'"\\N{\w\{-1,}}"', # \N{name} + r'"\\u\x\{4}"', # \uxxxx + r'"\\U\x\{8}"', # \Uxxxxxxxx +) + +identifier = r'[a-zA-Z_][a-zA-Z0-9_]*' + +# Numbers. + +# nonzerodigit digit* +decimalinteger = r'"\<[1-9][0-9]*\>"' + +# "0"+ +zerointeger = r'"\<0\+\>"' + +# "0" ("o" | "O") octdigit+ +octinteger = r'"\<0[oO][0-7]\+\>"' + +# "0" ("x" | "X") hexdigit+ +hexinteger = r'"\<0[xX]\x\+\>"' + +# "0" ("b" | "B") bindigit+ +bininteger = r'"\<0[bB][01]\+\>"' + +integers = (decimalinteger, zerointeger, octinteger, hexinteger, bininteger) + +# digit+ ("j" | "J") +imaginteger = r'"\<[0-9]\+[jJ]\>"' + +# Dot at the beginning (or at the end) of a number was a problem, because we +# can not use '\<' (or '\>') pattern here. + +# digit+ "." +float_end_dot = r'"\<[0-9]\+\.\ze\_W"' + +# "." digit+ [exponent] ["j" | "J"] +float_begin_dot = r'"\(\W\|^\)\zs\.[0-9]\+\([eE][+-]\=[0-9]\+\)\=[jJ]\=\>"' + +# digit+ "." ("j" | "J") +float0 = r'"\<[0-9]\+\.[jJ]\>"' + +# digit+ ["."] exponent ["j" | "J"] +float1 = r'"\<[0-9]\+\.\=[eE][+-]\=[0-9]\+[jJ]\=\>"' + +# digit+ "." digit+ [exponent] ["j" | "J"] +float2 = r'"\<[0-9]\+\.[0-9]\+\([eE][+-]\=[0-9]\+\)\=[jJ]\=\>"' + +# digit* "." digit+ [exponent] +# exponentfloat1 = r'"\_W[0-9]*\.[0-9]\+\([eE][+-]\=[0-9]\+\)\=[jJ]\=\_W"' + +floating = float0, float1, float2, float_end_dot, float_begin_dot, + +numbers = (imaginteger,) + integers + floating + +space_errors = ( + r'excludenl "\S\@<=\s\+$"', + r'" \+\t"', + r'"\t\+ "' +) + +def fineformat(prefix, body_list, postfix, limit=80): + """""" + assert postfix.endswith('\n') + body_limit = limit - len(prefix) - len(postfix) + 1 + while True: + length = 0 + i = -1 + for i, s in enumerate(body_list): + if length == 0 or (len(s) + length < body_limit): + length += len(s) + 1 else: - skip = '' - contains = 'contains=pythonEscape' if not raw else '' - yield regex_template.substitute(raw=raw, sep=separator, skip=skip, - contains = contains) + break + else: + i += 1 + if i == 0: + return + yield prefix + ' '.join(body_list[:i]) + postfix + body_list = body_list[i:] -space_errors = (r'excludenl "\S\s\+$"ms=s+1', r'" \+\t"', r'"\t\+ "') +def syn(*, + stype, + name, + pattern, + offset, + **kwargs +): + """ + Return 'syn' command string. -statements = ( - ('', - # XXX Might need to change pythonStatement since have - # specific Repeat, Conditional, Operator, etc. for 'while', - # etc. - [("Statement", "pythonStatement", "keyword", - (kw for kw in keyword.kwlist - if kw not in (looping + conditionals + boolean_ops + - import_stmts + object_defs)) - ), - ("Statement", "pythonStatement", "keyword", - (' '.join(object_defs) + - ' nextgroup=pythonFunction skipwhite')), - ("Function","pythonFunction", "match", - contained('"[a-zA-Z_][a-zA-Z0-9_]*"')), - ("Repeat", "pythonRepeat", "keyword", looping), - ("Conditional", "pythonConditional", "keyword", - conditionals), - ("Operator", "pythonOperator", "keyword", boolean_ops), - ("PreCondit", "pythonPreCondit", "keyword", import_stmts), - ("Comment", "pythonComment", "match", - '"#.*$" contains=pythonTodo'), - ("Todo", "pythonTodo", "keyword", - contained(' '.join(todos))), - ("String", "pythonString", "region", str_regexes()), - ("Special", "pythonEscape", "match", - (contained(esc) for esc in escapes - if not '$' in esc)), - ("Special", "pythonEscape", "match", r'"\\$"'), - ] + >>> syn( + stype='a', + name='b', + pattern='c', + offset=' :', + d='e', + f=None, + g=True + ) + " :syn a b c d=e g" + + """ + prefix = '{}syn {} {} '.format(offset, stype, name) + postfix = '' + for key, value in kwargs.items(): + if value is None: + pass + elif value is True: + postfix += ' {}'.format(key) + else: + postfix += ' {}={}'.format(key, value) + postfix += '\n' + + # Convert 'pattern' to list + if isinstance(pattern, str): + pattern = [pattern] + return ''.join(fineformat(prefix, pattern, postfix)) + +def if_exists(condition, block): + if isinstance(block, str): + return _if_exists.format(condition, block) + else: + return [_if_exists.format(condition, b) for b in block] + +def hi(py_syn_name, vim_syn_name): + def wrapper(function): + @functools.wraps(function) + def wrapped(*args, offset='', **kwargs): + return function(*args, offset=offset, **kwargs) + [ + '{}hi def link {} {}\n'.format( + offset, + py_syn_name, + vim_syn_name + ) + ] + return wrapped + return wrapper + +@hi('pythonString', 'String') +def syn_strings(offset=''): + return [''.join( + syn( + stype='region', + name='pythonString', + pattern='matchgroup=Normal', + start='"{bytes}{raw}{separator}"'.format( + bytes='[bB]' if bytes_str else '', + raw='[rR]' if raw_str else '', + separator=separator, ), - ("python_highlight_numbers", - [("Number", "pythonNumber", "match", numbers)] + skip=r'"\\\\\|\\\"\|\\\'"' if raw_str else None, + end='"{}"'.format(separator), + contains= + None + if raw_str else 'pythonLineJoin,pythonStringEscape' + ( + ''if bytes_str else ',pythonUnicodeEscape' ), - ("python_highlight_builtins", - [("Function", "pythonBuiltin", "keyword", builtin_names)] - ), - ("python_highlight_exceptions", - [("Exception", "pythonException", "keyword", - exception_names)] - ), - ("python_highlight_space_errors", - [("Error", "pythonSpaceError", "match", - ("display " + err for err in space_errors))] - ) - ) + offset=offset, + ) + for raw_str in (True, False) + for bytes_str in (True, False) + for separator in (r'\"', r'\'', r'\"\"\"', r'\'\'\'') + )] -def syn_prefix(type_, kind): - return 'syn %s %s ' % (type_, kind) +@hi('pythonStringEscape', 'Special') +@hi('pythonUnicodeEscape', 'Special') +@hi('pythonLineJoin', 'Special') +def syn_escapes(offset=''): + stringescapes = ''.join( + syn( + stype='match', + name='pythonStringEscape', + pattern=pattern, + contained=True, + offset=offset, + ) + for pattern in escapes + ) + unicodeescapes = ''.join( + syn( + stype='match', + name='pythonUnicodeEscape', + pattern=pattern, + contained=True, + offset=offset, + ) + for pattern in str_escapes + ) + linejoin = syn( + stype='match', + name='pythonLineJoin', + pattern=r'"\\$"', + offset=offset, + ) + return ['\n'.join((stringescapes, unicodeescapes, linejoin))] -def fill_stmt(iterable, fill_len): - """Yield a string that fills at most fill_len characters with strings - returned by 'iterable' and separated by a space""" - # Deal with trailing char to handle ' '.join() calculation - fill_len += 1 - overflow = None - it = iter(iterable) - while True: - buffer_ = [] - total_len = 0 - if overflow: - buffer_.append(overflow) - total_len += len(overflow) + 1 - overflow = None - while total_len < fill_len: - try: - new_item = next(it) - buffer_.append(new_item) - total_len += len(new_item) + 1 - except StopIteration: - if buffer_: - break - if overflow: - yield overflow - return - if total_len > fill_len: - overflow = buffer_.pop() - total_len -= len(overflow) - 1 - ret = ' '.join(buffer_) - assert len(ret) <= fill_len - yield ret +@hi('pythonTodo', 'Todo') +@hi('pythonStatement', 'Keyword') +@hi('pythonConstant', 'Constant') +@hi('pythonImport', 'Include') +@hi('pythonBoolean', 'Operator') +@hi('pythonDefinition', 'Keyword') +@hi('pythonContext', 'Keyword') +@hi('pythonException', 'Exception') +@hi('pythonLooping', 'Repeat') +@hi('pythonConditional', 'Conditional') +def syn_keywords(offset=''): + """Return definitions for keywords.""" + return ['\n'.join( + syn( + stype='keyword', + name=name, + pattern=wordlist, + nextgroup='pythonFuncName' if name == 'pythonDefinition' else None, + skipwhite=True if name == 'pythonDefinition' else None, + contained=True if name == 'pythonTodo' else None, + offset=offset, + ) + for name, wordlist in keywords.items() + if name.startswith('python') + )] -FILL = 80 +def syn_askeyword(offset=''): + """ + Return definitions for 'as' keyword. -def main(file_path): - with open(file_path, 'w') as FILE: - # Comment for file - print>>FILE, comment_header % subversion[1:] - print>>FILE, '' - # Statements at start of file - print>>FILE, statement_header - print>>FILE, '' - # Generate case for python_highlight_all - print>>FILE, 'if exists("python_highlight_all")' - for statement_var, statement_parts in statements: - if statement_var: - print>>FILE, ' let %s = 1' % statement_var - else: - print>>FILE, 'endif' - print>>FILE, '' - # Generate Python groups - for statement_var, statement_parts in statements: - if statement_var: - print>>FILE, 'if exists("%s")' % statement_var - indent = ' ' - else: - indent = '' - for colour_group, group, type_, arguments in statement_parts: - if not isinstance(arguments, basestring): - prefix = syn_prefix(type_, group) - if type_ == 'keyword': - stmt_iter = fill_stmt(arguments, - FILL - len(prefix) - len(indent)) - try: - while True: - print>>FILE, indent + prefix + next(stmt_iter) - except StopIteration: - print>>FILE, '' - else: - for argument in arguments: - print>>FILE, indent + prefix + argument - else: - print>>FILE, '' + The problem is that 'as' can be either the part of 'import' + statement, or the part of 'with' statement. - else: - print>>FILE, indent + syn_prefix(type_, group) + arguments - print>>FILE, '' - else: - if statement_var: - print>>FILE, 'endif' - print>>FILE, '' - print>>FILE, '' - # Associating Python group with Vim colour group - for statement_var, statement_parts in statements: - if statement_var: - print>>FILE, ' if exists("%s")' % statement_var - indent = ' ' - else: - indent = ' ' - for colour_group, group, type_, arguments in statement_parts: - print>>FILE, (indent + "hi def link %s %s" % - (group, colour_group)) - else: - if statement_var: - print>>FILE, ' endif' - print>>FILE, '' - # Statements at the end of the file - print>>FILE, statement_footer + The solution comes out of the fact, that somewhere before 'as' + there should be one of keywords 'import' or 'with'. + Due to the Vim implementation, 'with' (or 'import') can be + detected only on the same line as 'as', and on the preceding line. + """ + with_as = syn( + stype='match', + name='pythonContext', + pattern=r'"\(\\(\(\\)\@!\&\_.\{-}\)\)\@<=\"', + offset=offset, + ) + import_as = syn( + stype='match', + name='pythonImport', + pattern=r'"\(\\(\(\\)\@!\&\_.\{-}\)\)\@<=\"', + offset=offset, + ) + # 'unknown_as' is match, not keyword, because it should not override + # 'with_as' and 'import_as'. + unknown_as = syn( + stype='match', + name='pythonStatement', + pattern=r'"\"', + offset=offset, + ) + return [''.join((unknown_as, with_as, import_as))] + +@hi('pythonFuncName', 'Function') +def syn_funcname(offset=''): + return [syn( + stype='match', + name='pythonFuncName', + pattern='"{}"'.format(identifier), + contained=True, + offset=offset, + )] + +@hi('pythonComment', 'Comment') +def syn_comment(offset=''): + return [syn( + stype='match', + name='pythonComment', + pattern='"#.*$"', + contains='pythonTodo', + offset=offset, + )] + +@hi('pythonNumber', 'Number') +def syn_numbers(offset=''): + return [''.join(( + syn( + stype='match', + name='pythonNumber', + pattern=pattern, + offset=offset, + ) + for pattern in numbers + ))] + +@hi('pythonBuiltin', 'Constant') +def syn_builtins(offset=''): + return [syn( + stype='keyword', + name='pythonBuiltin', + pattern=builtin_names, + offset=offset, + )] + +@hi('pythonSpaceError', 'Error') +def syn_spaceerror(offset=''): + return [''.join( + syn( + stype='match', + name='pythonSpaceError', + pattern=pattern, + offset=offset, + ) + for pattern in space_errors + )] + +@hi('pythonDecorator', 'Function') +def syn_decorator(offset=''): + return [syn( + stype='match', + name='pythonDecorator', + pattern='"^\s*\zs@\ze{0}\(\.{0}\)*\((.*)\)\=$"'.format(identifier), + offset=offset, + )] + +def main(): + pre_out = [ + syn_strings(), + syn_escapes(), + syn_keywords(), + syn_askeyword(), + syn_funcname(), + syn_decorator(), + syn_comment(), + if_exists('python_highlight_numbers', syn_numbers(offset=' ')), + if_exists('python_highlight_builtins', syn_builtins(offset=' ')), + if_exists('python_highlight_space_errors', syn_spaceerror(offset=' ')), + ] + definitions = '\n'.join(d for d, *b in pre_out) + bindings = '\n'.join(''.join(b) for d, *b in pre_out) + return '\n'.join(( + _comment, + if_exists('b:current_syntax', _finish), + if_exists('python_highlight_all', _let_all), + definitions, + bindings, + _post_scriptum, + )) + if __name__ == '__main__': - main("python.vim") + with open('python.vim', 'w') as f: + f.write(main()) + Index: Misc/Vim/python.vim =================================================================== --- Misc/Vim/python.vim (revision 77235) +++ Misc/Vim/python.vim (working copy) @@ -1,8 +1,27 @@ -" Auto-generated Vim syntax file for Python (trunk: r60376M). +" Auto-generated Vim syntax file for Python (branches/py3k: r77229M). " " To use: copy or symlink to ~/.vim/syntax/python.vim +" +" Options to control Python syntax highlighting: +" +" For highlighted numbers: +" +" let python_highlight_numbers = 1 +" +" For highlighted builtin functions: +" +" let python_highlight_builtins = 1 +" +" Highlight erroneous whitespace: +" +" let python_highlight_space_errors = 1 +" +" If you want all possible Python highlighting (the same as setting the +" preceding options): +" +" let python_highlight_all = 1 +" - if exists("b:current_syntax") finish endif @@ -10,134 +29,153 @@ if exists("python_highlight_all") let python_highlight_numbers = 1 let python_highlight_builtins = 1 - let python_highlight_exceptions = 1 let python_highlight_space_errors = 1 endif -syn keyword pythonStatement as assert break continue del except exec finally -syn keyword pythonStatement global lambda pass print raise return try with -syn keyword pythonStatement yield +syn region pythonString matchgroup=Normal start="[bB][rR]\"" end="\"" skip="\\\\\|\\\"\|\\\'" +syn region pythonString matchgroup=Normal start="[bB][rR]\'" end="\'" skip="\\\\\|\\\"\|\\\'" +syn region pythonString matchgroup=Normal start="[bB][rR]\"\"\"" end="\"\"\"" skip="\\\\\|\\\"\|\\\'" +syn region pythonString matchgroup=Normal start="[bB][rR]\'\'\'" end="\'\'\'" skip="\\\\\|\\\"\|\\\'" +syn region pythonString matchgroup=Normal start="[rR]\"" end="\"" skip="\\\\\|\\\"\|\\\'" +syn region pythonString matchgroup=Normal start="[rR]\'" end="\'" skip="\\\\\|\\\"\|\\\'" +syn region pythonString matchgroup=Normal start="[rR]\"\"\"" end="\"\"\"" skip="\\\\\|\\\"\|\\\'" +syn region pythonString matchgroup=Normal start="[rR]\'\'\'" end="\'\'\'" skip="\\\\\|\\\"\|\\\'" +syn region pythonString matchgroup=Normal start="[bB]\"" contains=pythonLineJoin,pythonStringEscape end="\"" +syn region pythonString matchgroup=Normal start="[bB]\'" contains=pythonLineJoin,pythonStringEscape end="\'" +syn region pythonString matchgroup=Normal start="[bB]\"\"\"" contains=pythonLineJoin,pythonStringEscape end="\"\"\"" +syn region pythonString matchgroup=Normal start="[bB]\'\'\'" contains=pythonLineJoin,pythonStringEscape end="\'\'\'" +syn region pythonString matchgroup=Normal start="\"" contains=pythonLineJoin,pythonStringEscape,pythonUnicodeEscape end="\"" +syn region pythonString matchgroup=Normal start="\'" contains=pythonLineJoin,pythonStringEscape,pythonUnicodeEscape end="\'" +syn region pythonString matchgroup=Normal start="\"\"\"" contains=pythonLineJoin,pythonStringEscape,pythonUnicodeEscape end="\"\"\"" +syn region pythonString matchgroup=Normal start="\'\'\'" contains=pythonLineJoin,pythonStringEscape,pythonUnicodeEscape end="\'\'\'" -syn keyword pythonStatement def class nextgroup=pythonFunction skipwhite +syn match pythonStringEscape "\\[\\\'\"abfnrtv]" contained +syn match pythonStringEscape "\\[0-7]\{1,3}" contained +syn match pythonStringEscape "\\x\x\{2}" contained -syn match pythonFunction "[a-zA-Z_][a-zA-Z0-9_]*" contained +syn match pythonUnicodeEscape "\\N{\w\{-1,}}" contained +syn match pythonUnicodeEscape "\\u\x\{4}" contained +syn match pythonUnicodeEscape "\\U\x\{8}" contained -syn keyword pythonRepeat for while +syn match pythonLineJoin "\\$" -syn keyword pythonConditional if elif else +syn keyword pythonContext with -syn keyword pythonOperator and in is not or +syn keyword pythonLooping for while -syn keyword pythonPreCondit import from +syn keyword pythonImport from import -syn match pythonComment "#.*$" contains=pythonTodo +syn keyword pythonConditional if elif else -syn keyword pythonTodo TODO FIXME XXX contained +syn keyword pythonDefinition def class nextgroup=pythonFuncName skipwhite -syn region pythonString matchgroup=Normal start=+[uU]\='+ end=+'+ skip=+\\\\\|\\'+ contains=pythonEscape -syn region pythonString matchgroup=Normal start=+[uU]\="+ end=+"+ skip=+\\\\\|\\"+ contains=pythonEscape -syn region pythonString matchgroup=Normal start=+[uU]\="""+ end=+"""+ contains=pythonEscape -syn region pythonString matchgroup=Normal start=+[uU]\='''+ end=+'''+ contains=pythonEscape -syn region pythonString matchgroup=Normal start=+[uU]\=[rR]'+ end=+'+ skip=+\\\\\|\\'+ -syn region pythonString matchgroup=Normal start=+[uU]\=[rR]"+ end=+"+ skip=+\\\\\|\\"+ -syn region pythonString matchgroup=Normal start=+[uU]\=[rR]"""+ end=+"""+ -syn region pythonString matchgroup=Normal start=+[uU]\=[rR]'''+ end=+'''+ +syn keyword pythonConstant True False None __debug__ -syn match pythonEscape +\\[abfnrtv\'"\\]+ contained -syn match pythonEscape "\\\o\{1,3}" contained -syn match pythonEscape "\\x\x\{2}" contained -syn match pythonEscape "\(\\u\x\{4}\|\\U\x\{8}\)" contained +syn keyword pythonBoolean and in is not or -syn match pythonEscape "\\$" +syn keyword pythonStatement assert break continue del global lambda nonlocal +syn keyword pythonStatement pass return yield +syn keyword pythonTodo TODO FIXME XXX contained -if exists("python_highlight_numbers") - syn match pythonNumber "\<0x\x\+[Ll]\=\>" - syn match pythonNumber "\<\d\+[LljJ]\=\>" - syn match pythonNumber "\.\d\+\([eE][+-]\=\d\+\)\=[jJ]\=\>" - syn match pythonNumber "\<\d\+\.\([eE][+-]\=\d\+\)\=[jJ]\=\>" - syn match pythonNumber "\<\d\+\.\d\+\([eE][+-]\=\d\+\)\=[jJ]\=\>" +syn keyword pythonException try except finally raise -endif +syn match pythonStatement "\" +syn match pythonContext "\(\\(\(\\)\@!\&\_.\{-}\)\)\@<=\" +syn match pythonImport "\(\\(\(\\)\@!\&\_.\{-}\)\)\@<=\" +syn match pythonFuncName "[a-zA-Z_][a-zA-Z0-9_]*" contained -if exists("python_highlight_builtins") - syn keyword pythonBuiltin Ellipsis False None NotImplemented True __debug__ - syn keyword pythonBuiltin __import__ abs all any bool - syn keyword pythonBuiltin buffer callable chr classmethod cmp - syn keyword pythonBuiltin complex copyright credits delattr dict - syn keyword pythonBuiltin dir divmod enumerate eval exec exit - syn keyword pythonBuiltin filter float frozenset getattr globals hasattr - syn keyword pythonBuiltin hash help hex id int isinstance - syn keyword pythonBuiltin issubclass iter len license list locals map - syn keyword pythonBuiltin max min object oct open ord pow property quit - syn keyword pythonBuiltin range reload repr reversed round - syn keyword pythonBuiltin set setattr slice sorted staticmethod str sum - syn keyword pythonBuiltin super trunc tuple type unicode vars - syn keyword pythonBuiltin zip +syn match pythonDecorator "^\s*\zs@\ze[a-zA-Z_][a-zA-Z0-9_]*\(\.[a-zA-Z_][a-zA-Z0-9_]*\)*\((.*)\)\=$" +syn match pythonComment "#.*$" contains=pythonTodo + +if exists("python_highlight_numbers") + syn match pythonNumber "\<[0-9]\+[jJ]\>" + syn match pythonNumber "\<[1-9][0-9]*\>" + syn match pythonNumber "\<0\+\>" + syn match pythonNumber "\<0[oO][0-7]\+\>" + syn match pythonNumber "\<0[xX]\x\+\>" + syn match pythonNumber "\<0[bB][01]\+\>" + syn match pythonNumber "\<[0-9]\+\.[jJ]\>" + syn match pythonNumber "\<[0-9]\+\.\=[eE][+-]\=[0-9]\+[jJ]\=\>" + syn match pythonNumber "\<[0-9]\+\.[0-9]\+\([eE][+-]\=[0-9]\+\)\=[jJ]\=\>" + syn match pythonNumber "\<[0-9]\+\.\ze\_W" + syn match pythonNumber "\(\W\|^\)\zs\.[0-9]\+\([eE][+-]\=[0-9]\+\)\=[jJ]\=\>" endif +if exists("python_highlight_builtins") + syn keyword pythonBuiltin ArithmeticError AssertionError AttributeError + syn keyword pythonBuiltin BaseException BufferError BytesWarning + syn keyword pythonBuiltin DeprecationWarning EOFError Ellipsis + syn keyword pythonBuiltin EnvironmentError Exception FloatingPointError + syn keyword pythonBuiltin FutureWarning GeneratorExit IOError ImportError + syn keyword pythonBuiltin ImportWarning IndentationError IndexError KeyError + syn keyword pythonBuiltin KeyboardInterrupt LookupError MemoryError + syn keyword pythonBuiltin NameError NotImplemented NotImplementedError + syn keyword pythonBuiltin OSError OverflowError PendingDeprecationWarning + syn keyword pythonBuiltin ReferenceError RuntimeError RuntimeWarning + syn keyword pythonBuiltin StopIteration SyntaxError SyntaxWarning + syn keyword pythonBuiltin SystemError SystemExit TabError TypeError + syn keyword pythonBuiltin UnboundLocalError UnicodeDecodeError + syn keyword pythonBuiltin UnicodeEncodeError UnicodeError + syn keyword pythonBuiltin UnicodeTranslateError UnicodeWarning UserWarning + syn keyword pythonBuiltin ValueError Warning ZeroDivisionError + syn keyword pythonBuiltin __build_class__ __import__ abs all any ascii bin + syn keyword pythonBuiltin bool bytearray bytes chr classmethod compile + syn keyword pythonBuiltin complex copyright credits delattr dict dir divmod + syn keyword pythonBuiltin enumerate eval exec exit filter float format + syn keyword pythonBuiltin frozenset getattr globals hasattr hash help hex id + syn keyword pythonBuiltin input int isinstance issubclass iter len license + syn keyword pythonBuiltin list locals map max memoryview min next object oct + syn keyword pythonBuiltin open ord pow print property quit range repr + syn keyword pythonBuiltin reversed round set setattr slice sorted + syn keyword pythonBuiltin staticmethod str sum super tuple type vars zip +endif -if exists("python_highlight_exceptions") - syn keyword pythonException ArithmeticError AssertionError AttributeError - syn keyword pythonException BaseException DeprecationWarning EOFError - syn keyword pythonException EnvironmentError Exception FloatingPointError - syn keyword pythonException FutureWarning GeneratorExit IOError ImportError - syn keyword pythonException ImportWarning IndentationError IndexError - syn keyword pythonException KeyError KeyboardInterrupt LookupError - syn keyword pythonException MemoryError NameError NotImplementedError - syn keyword pythonException OSError OverflowError PendingDeprecationWarning - syn keyword pythonException ReferenceError RuntimeError RuntimeWarning - syn keyword pythonException StopIteration SyntaxError - syn keyword pythonException SyntaxWarning SystemError SystemExit TabError - syn keyword pythonException TypeError UnboundLocalError UnicodeDecodeError - syn keyword pythonException UnicodeEncodeError UnicodeError - syn keyword pythonException UnicodeTranslateError UnicodeWarning - syn keyword pythonException UserWarning ValueError Warning - syn keyword pythonException ZeroDivisionError - +if exists("python_highlight_space_errors") + syn match pythonSpaceError excludenl "\S\@<=\s\+$" + syn match pythonSpaceError " \+\t" + syn match pythonSpaceError "\t\+ " endif +hi def link pythonString String -if exists("python_highlight_space_errors") - syn match pythonSpaceError display excludenl "\S\s\+$"ms=s+1 - syn match pythonSpaceError display " \+\t" - syn match pythonSpaceError display "\t\+ " +hi def link pythonLineJoin Special +hi def link pythonUnicodeEscape Special +hi def link pythonStringEscape Special -endif +hi def link pythonConditional Conditional +hi def link pythonLooping Repeat +hi def link pythonException Exception +hi def link pythonContext Keyword +hi def link pythonDefinition Keyword +hi def link pythonBoolean Operator +hi def link pythonImport Include +hi def link pythonConstant Constant +hi def link pythonStatement Keyword +hi def link pythonTodo Todo - hi def link pythonStatement Statement - hi def link pythonStatement Statement - hi def link pythonFunction Function - hi def link pythonRepeat Repeat - hi def link pythonConditional Conditional - hi def link pythonOperator Operator - hi def link pythonPreCondit PreCondit - hi def link pythonComment Comment - hi def link pythonTodo Todo - hi def link pythonString String - hi def link pythonEscape Special - hi def link pythonEscape Special +hi def link pythonFuncName Function - if exists("python_highlight_numbers") - hi def link pythonNumber Number - endif +hi def link pythonDecorator Function - if exists("python_highlight_builtins") - hi def link pythonBuiltin Function - endif +hi def link pythonComment Comment - if exists("python_highlight_exceptions") - hi def link pythonException Exception - endif +if exists("python_highlight_numbers") + hi def link pythonNumber Number +endif - if exists("python_highlight_space_errors") - hi def link pythonSpaceError Error - endif +if exists("python_highlight_builtins") + hi def link pythonBuiltin Constant +endif +if exists("python_highlight_space_errors") + hi def link pythonSpaceError Error +endif + " Uncomment the 'minlines' statement line and comment out the 'maxlines' " statement line; changes behaviour to look at least 2000 lines previously for " syntax matches instead of at most 200 lines @@ -146,3 +184,4 @@ "syn sync minlines=2000 let b:current_syntax = "python" + Index: Misc/Vim/syntax_test.py =================================================================== --- Misc/Vim/syntax_test.py (revision 77235) +++ Misc/Vim/syntax_test.py (working copy) @@ -1,62 +1,224 @@ """Test file for syntax highlighting of editors. Meant to cover a wide range of different types of statements and expressions. -Not necessarily sensical or comprehensive (assume that if one exception is -highlighted that all are, for instance). Extraneous trailing whitespace can't be tested because of svn pre-commit hook checks for such things. """ -# Comment -# OPTIONAL: XXX catch your attention -# Statements -from __future__ import with_statement # Import -from sys import path as thing -assert True # keyword -def foo(): # function definition - return [] -class Bar(object): # Class definition - def __enter__(self): - pass - def __exit__(self, *args): - pass -foo() # UNCOLOURED: function call -while False: # 'while' - continue -for x in foo(): # 'for' - break -with Bar() as stuff: +# Strings + +'\n\u1111' # two escapes +b'\n\u1111' # one escape (no Unicode) +r'\n\u1111' # no escapes (raw) +br'\n\u1111' +B'\n\u1111' +r"\n\u1111" +bR'\n\u1111' + +'''\t\U1111111f''' +'''\z\U11Z1111F''' # no escapes +b'''\t\U1111111F''' +r'''\t\U1111111F''' + +'''\'''' +"""\"""" +'\'' +"\"" + +r'''\'''' +r"""\"""" +r'\'' +r"\"" + +'\N{asdf}' +b'\N{asdf}' + +# Line join + +123 + \ + 567 + +'asdf \ +ghjk' + +''' \ +'2' +''' + +# raw string - '\' not coloured as special +r' \ +lkjh +' + +r''' \ +hjkl +''' + +# Imports + +from sys import path as thing, argv as arguments + +# Conditional + +if 1: pass -if False: pass # 'if' -elif False: pass +elif 2: pass +else: + pass + +# Looping + +for i in range(10): + break + continue + +while False: + pass + +# Exception + +try: + raise IndexError +except LookupError: + pass else: pass +finally: + pass -# Constants -'single-quote', u'unicode' # Strings of all kinds; prefixes not highlighted -"double-quote" -"""triple double-quote""" -'''triple single-quote''' -r'raw' -ur'unicode raw' -'escape\n' -'\04' # octal -'\xFF' # hex -'\u1111' # unicode character -1 # Integral -1L -1.0 # Float -.1 -1+2j # Complex +# Context -# Expressions -1 and 2 or 3 # Boolean operators -2 < 3 # UNCOLOURED: comparison operators -spam = 42 # UNCOLOURED: assignment -2 + 3 # UNCOLOURED: number operators -[] # UNCOLOURED: list -{} # UNCOLOURED: dict -(1,) # UNCOLOURED: tuple -all # Built-in functions -GeneratorExit # Exceptions +with open(arguments[0], 'r') as f, open(arguments[1], 'w') as g: + g.write(f.read()) + +# Definition + +def somefunction(): + global a + nonlocal b + c = 0 + del c + yield 10.e-2 + +class SomeClass(): + @some_decorator(i) + @classmethod + def somemethod(self): + return 0B010010010100111 + +# Boolean + +1 or 3 in () and 4 is 5 + +# 'Constants' + +True, False, None, __debug__ + +# Other statements + +assert 1 +x = (lambda x: x - x) + +# TODO FIXME XXX + +# Number + +1048576 +0000000 + +0o71035 +0O71035 + +0x834af +0X834Af + +0b01001 +0B01001 + +012349j +012349J + +01234. +01234.j +01234.J + +01.234 +01.234j +01.234J + +.12e3 +.12e3j +.12e3J + +0.2e3 +0.2e3j +0.2e3J + +01.e3 +01.e3j +01.e3J + +012e3 +012e3j +012e3J + +.12e+3 +.12e+3j +.12e+3J + +0.2e+3 +0.2e+3j +0.2e+3J + +01.e+3 +01.e+3j +01.e+3J + +012e+3 +012e+3j +012e+3J + +.12e-3 +.12e-3j +.12e-3J + +0.2e-3 +0.2e-3j +0.2e-3J + +01.e-3 +01.e-3j +01.e-3J + +012e-3 +012e-3j +012e-3J + +.12 ++.12 +-.12 +0.2 +01. + +012345. +.543210 + +012345.+.543210 +012345.**.543210 + +# Builtin object + +int, float, tuple, zip, classmethod, any, AttributeError + +# Uncoloured + +a = SomeClass.somemethod() < someClass.somemethod() + +a += a +[a] +{a} +{a:a} +(a,) +() +