From a4fe18227d48edbb41b76f2861be2c6b800c6609 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sat, 25 Feb 2006 14:52:53 +0000 Subject: Add a script that auto-generates a Vim syntax highlighting file for Python. Just symlink or copy python.vim to ~/.vim/syntax/ . Also included is a sample Python file with basic expressions to make sure they are highlighted. Also add a Vim directory in Misc to hold all Vim configuration files. --- Misc/Vim/python.vim | 145 ++++++++++++++++++++++++++++++ Misc/Vim/syntax_test.py | 36 ++++++++ Misc/Vim/vim_syntax.py | 232 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 413 insertions(+) create mode 100644 Misc/Vim/python.vim create mode 100644 Misc/Vim/syntax_test.py create mode 100644 Misc/Vim/vim_syntax.py diff --git a/Misc/Vim/python.vim b/Misc/Vim/python.vim new file mode 100644 index 0000000..6a1fa9f --- /dev/null +++ b/Misc/Vim/python.vim @@ -0,0 +1,145 @@ +" Auto-generated Vim syntax file for Python +" +" To use: copy or symlink to ~/.vim/syntax/python.vim + + +if exists("b:current_syntax") + finish +endif + +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 assert break continue del except exec finally +syn keyword pythonStatement global lambda pass print raise return try yield + +syn keyword pythonStatement def class nextgroup=pythonFunction skipwhite + +syn match pythonFunction "[a-zA-Z_][a-zA-Z0-9_]*" contained + +syn keyword pythonRepeat for while + +syn keyword pythonConditional if elif else + +syn keyword pythonOperator and in is not or + +syn keyword pythonPreCondit import from + +syn match pythonComment "#.*$" contains=pythonTodo + +syn keyword pythonTodo TODO FIXME XXX contained + +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 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 match pythonEscape "\\$" + + +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]\=\>" + +endif + + +if exists("python_highlight_builtins") + syn keyword pythonBuiltin unichr all set abs vars int __import__ unicode + syn keyword pythonBuiltin enumerate reduce coerce intern exit issubclass + syn keyword pythonBuiltin divmod file Ellipsis apply isinstance open any + syn keyword pythonBuiltin locals help filter basestring slice copyright min + syn keyword pythonBuiltin super sum tuple hex execfile long id xrange chr + syn keyword pythonBuiltin complex bool zip pow dict True oct NotImplemented + syn keyword pythonBuiltin map None float hash getattr buffer max reversed + syn keyword pythonBuiltin object quit len repr callable credits setattr + syn keyword pythonBuiltin eval frozenset sorted ord __debug__ hasattr + syn keyword pythonBuiltin delattr False input license classmethod type + syn keyword pythonBuiltin raw_input list iter compile reload range globals + syn keyword pythonBuiltin staticmethod str property round dir cmp + +endif + + +if exists("python_highlight_exceptions") + syn keyword pythonException GeneratorExit ImportError RuntimeError + syn keyword pythonException UnicodeTranslateError MemoryError StopIteration + syn keyword pythonException PendingDeprecationWarning EnvironmentError + syn keyword pythonException LookupError OSError DeprecationWarning + syn keyword pythonException UnicodeError FloatingPointError ReferenceError + syn keyword pythonException NameError OverflowWarning IOError SyntaxError + syn keyword pythonException FutureWarning SystemExit Exception EOFError + syn keyword pythonException StandardError ValueError TabError KeyError + syn keyword pythonException ZeroDivisionError SystemError + syn keyword pythonException UnicodeDecodeError IndentationError + syn keyword pythonException AssertionError TypeError IndexError + syn keyword pythonException RuntimeWarning KeyboardInterrupt UserWarning + syn keyword pythonException SyntaxWarning UnboundLocalError ArithmeticError + syn keyword pythonException Warning NotImplementedError AttributeError + syn keyword pythonException OverflowError UnicodeEncodeError + +endif + + +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\+ " + +endif + + + 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 + + if exists("python_highlight_numbers") + hi def link pythonNumber Number + endif + + if exists("python_highlight_builtins") + hi def link pythonBuiltin Function + endif + + if exists("python_highlight_exceptions") + hi def link pythonException Exception + 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 +syn sync match pythonSync grouphere NONE "):$" +syn sync maxlines=200 +"syn sync minlines=2000 + +let b:current_syntax = "python" diff --git a/Misc/Vim/syntax_test.py b/Misc/Vim/syntax_test.py new file mode 100644 index 0000000..67b3199 --- /dev/null +++ b/Misc/Vim/syntax_test.py @@ -0,0 +1,36 @@ +"""Test file for syntax highlighting of editors. + +Meant to cover a wide range of different types of statements and expressions. +Not necessarily sensical. + +""" +assert True +def foo(): pass +foo() # Uncoloured +while False: pass +1 and 2 +if False: pass +from sys import path +# Comment +# XXX catch your attention +'single-quote', u'unicode' +"double-quote" +"""triple double-quote""" +'''triple single-quote''' +r'raw' +ur'unicode raw' +'escape\n' +'\04' # octal +'\xFF' # hex +'\u1111' # unicode character +1 +1L +1.0 +.1 +1+2j +[] # Uncoloured +{} # Uncoloured +() # Uncoloured +all +GeneratorExit +trailing_whitespace = path diff --git a/Misc/Vim/vim_syntax.py b/Misc/Vim/vim_syntax.py new file mode 100644 index 0000000..b733929 --- /dev/null +++ b/Misc/Vim/vim_syntax.py @@ -0,0 +1,232 @@ +import keyword +import exceptions +import __builtin__ +from string import Template + +comment_header = """" Auto-generated Vim syntax file for Python +" +" To use: copy or symlink to ~/.vim/syntax/python.vim""" + +statement_header = """ +if exists("b:current_syntax") + finish +endif""" + +statement_footer = ''' +" 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 +syn sync match pythonSync grouphere NONE "):$" +syn sync maxlines=200 +"syn sync minlines=2000 + +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 = frozenset(exc for exc in dir(exceptions) + if not exc.startswith('__')) + +# 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 = frozenset(builtin for builtin in dir(__builtin__) + if builtin not in dir(exceptions)) + +escapes = (r'+\\[abfnrtv\'"\\]+', r'"\\\o\{1,3}"', r'"\\x\x\{2}"', + r'"\(\\u\x\{4}\|\\U\x\{8}\)"', r'"\\$"') + +todos = ("TODO", "FIXME", "XXX") + +# XXX codify? +numbers = (r'"\<0x\x\+[Ll]\=\>"', r'"\<\d\+[LljJ]\=\>"', + '"\.\d\+\([eE][+-]\=\d\+\)\=[jJ]\=\>"', + '"\<\d\+\.\([eE][+-]\=\d\+\)\=[jJ]\=\>"', + '"\<\d\+\.\d\+\([eE][+-]\=\d\+\)\=[jJ]\=\>"') + +contained = lambda x: "%s contained" % x + +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) + else: + skip = '' + if not raw: + contains = 'contains=pythonEscape' + else: + contains = '' + yield regex_template.substitute(raw=raw, sep=separator, skip=skip, + contains = contains) + +space_errors = (r'excludenl "\S\s\+$"ms=s+1', r'" \+\t"', r'"\t\+ "') + +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'"\\$"'), + ] + ), + ("python_highlight_numbers", + [("Number", "pythonNumber", "match", numbers)] + ), + ("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))] + ) + ) + +def syn_prefix(type_, kind): + return 'syn %s %s ' % (type_, kind) + +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 = it.next() + buffer_.append(new_item) + total_len += len(new_item) + 1 + except StopIteration: + if buffer_: + break + if not buffer_ and overflow: + yield buffer_ + return + else: + return + if total_len > fill_len: + overflow = buffer_.pop() + total_len -= len(overflow) - 1 + ret = ' '.join(buffer_) + assert len(ret) <= fill_len + yield ret + +FILL = 80 + +def main(file_path): + FILE = open(file_path, 'w') + try: + # Comment for file + print>>FILE, comment_header + 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 + stmt_iter.next() + except StopIteration: + print>>FILE, '' + else: + for argument in arguments: + print>>FILE, indent + prefix + argument + else: + print>>FILE, '' + + 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 + finally: + FILE.close() + +if __name__ == '__main__': + main("python.vim") -- cgit v0.12