mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			227 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from __future__ import with_statement
 | 
						|
 | 
						|
import keyword
 | 
						|
import exceptions
 | 
						|
import __builtin__
 | 
						|
from string import Template
 | 
						|
from sys import subversion
 | 
						|
 | 
						|
comment_header = '''" Auto-generated Vim syntax file for Python (%s: r%s).
 | 
						|
"
 | 
						|
" 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 = sorted(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 = sorted(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 % 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 + 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")
 |