226 lines · 8.7 KB · Python
RawDownload
from __future__ import with_statement import keywordimport exceptionsimport __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")  finishendif""" 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 linessyn 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 havebuiltin_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 = ''            contains = 'contains=pythonEscape' if not raw else ''            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 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 FILL = 80 def main(file_path):    with open(file_path, 'w') as FILE:        # 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 if __name__ == '__main__':    main("python.vim")