1 from __future__
import with_statement
6 from string
import Template
7 from sys
import subversion
9 comment_header
= '''" Auto-generated Vim syntax file for Python (%s: r%s).
11 " To use: copy or symlink to ~/.vim/syntax/python.vim'''
13 statement_header
= """
14 if exists("b:current_syntax")
18 statement_footer
= '''
19 " Uncomment the 'minlines' statement line and comment out the 'maxlines'
20 " statement line; changes behaviour to look at least 2000 lines previously for
21 " syntax matches instead of at most 200 lines
22 syn sync match pythonSync grouphere NONE "):$"
24 "syn sync minlines=2000
26 let b:current_syntax = "python"'''
28 looping
= ('for', 'while')
29 conditionals
= ('if', 'elif', 'else')
30 boolean_ops
= ('and', 'in', 'is', 'not', 'or')
31 import_stmts
= ('import', 'from')
32 object_defs
= ('def', 'class')
34 exception_names
= sorted(exc
for exc
in dir(exceptions
)
35 if not exc
.startswith('__'))
37 # Need to include functions that start with '__' (e.g., __import__), but
38 # nothing that comes with modules (e.g., __name__), so just exclude anything in
39 # the 'exceptions' module since we want to ignore exceptions *and* what any
41 builtin_names
= sorted(builtin
for builtin
in dir(__builtin__
)
42 if builtin
not in dir(exceptions
))
44 escapes
= (r
'+\\[abfnrtv\'"\\]+', r'"\\\o\
{1,3}"', r'"\\x\x\{2}
"',
45 r'"\
(\\u\x\{4}\|
\\U\x\{8}\
)"', r'"\\$
"')
47 todos = ("TODO
", "FIXME
", "XXX
")
50 numbers = (r'"\
<0x\x\
+[Ll
]\
=\
>"', r'"\
<\d\
+[LljJ
]\
=\
>"',
51 '"\
.\d\
+\
([eE
][+-]\
=\d\
+\
)\
=[jJ
]\
=\
>"',
52 '"\
<\d\
+\
.\
([eE
][+-]\
=\d\
+\
)\
=[jJ
]\
=\
>"',
53 '"\
<\d\
+\
.\d\
+\
([eE
][+-]\
=\d\
+\
)\
=[jJ
]\
=\
>"')
55 contained = lambda x: "%s contained
" % x
58 """Generator to yield various combinations of strings regexes"""
59 regex_template = Template('matchgroup=Normal ' +
60 'start=+[uU]\=${raw}${sep}+ ' +
64 skip_regex = Template(r'skip=+\\\\\|\\${sep}+')
65 for raw in ('', '[rR]'):
66 for separator in ("'", '"', '"""', "'''"):
67 if len(separator) == 1:
68 skip = skip_regex.substitute(sep=separator)
71 contains = 'contains=pythonEscape' if not raw else ''
72 yield regex_template.substitute(raw=raw, sep=separator, skip=skip,
75 space_errors = (r'excludenl "\S\s\+$"ms=s+1', r'" \+\t"', r'"\t\+ "')
79 # XXX Might need to change pythonStatement since have
80 # specific Repeat, Conditional, Operator, etc. for 'while',
82 [("Statement", "pythonStatement", "keyword",
83 (kw for kw in keyword.kwlist
84 if kw not in (looping + conditionals + boolean_ops +
85 import_stmts + object_defs))
87 ("Statement", "pythonStatement", "keyword",
88 (' '.join(object_defs) +
89 ' nextgroup=pythonFunction skipwhite')),
90 ("Function","pythonFunction", "match",
91 contained('"[a-zA-Z_][a-zA-Z0-9_]*"')),
92 ("Repeat", "pythonRepeat", "keyword", looping),
93 ("Conditional", "pythonConditional", "keyword",
95 ("Operator", "pythonOperator", "keyword", boolean_ops),
96 ("PreCondit", "pythonPreCondit", "keyword", import_stmts),
97 ("Comment", "pythonComment", "match",
98 '"#.*$" contains=pythonTodo'),
99 ("Todo", "pythonTodo", "keyword",
100 contained(' '.join(todos))),
101 ("String", "pythonString", "region", str_regexes()),
102 ("Special", "pythonEscape", "match",
103 (contained(esc) for esc in escapes
105 ("Special", "pythonEscape", "match", r'"\\$"'),
108 ("python_highlight_numbers",
109 [("Number", "pythonNumber", "match", numbers)]
111 ("python_highlight_builtins",
112 [("Function", "pythonBuiltin", "keyword", builtin_names)]
114 ("python_highlight_exceptions",
115 [("Exception", "pythonException", "keyword",
118 ("python_highlight_space_errors",
119 [("Error", "pythonSpaceError", "match",
120 ("display " + err for err in space_errors))]
124 def syn_prefix(type_, kind):
125 return 'syn %s %s ' % (type_, kind)
127 def fill_stmt(iterable, fill_len):
128 """Yield a string that fills at most fill_len characters with strings
129 returned by 'iterable' and separated by a space"""
130 # Deal with trailing char to handle ' '.join() calculation
138 buffer_.append(overflow)
139 total_len += len(overflow) + 1
141 while total_len < fill_len:
144 buffer_.append(new_item)
145 total_len += len(new_item) + 1
146 except StopIteration:
152 if total_len > fill_len:
153 overflow = buffer_.pop()
154 total_len -= len(overflow) - 1
155 ret = ' '.join(buffer_)
156 assert len(ret) <= fill_len
162 with open(file_path, 'w') as FILE:
164 print>>FILE, comment_header % subversion[1:]
166 # Statements at start of file
167 print>>FILE, statement_header
169 # Generate case for python_highlight_all
170 print>>FILE, 'if exists("python_highlight_all")'
171 for statement_var, statement_parts in statements:
173 print>>FILE, ' let %s = 1' % statement_var
177 # Generate Python groups
178 for statement_var, statement_parts in statements:
180 print>>FILE, 'if exists("%s")' % statement_var
184 for colour_group, group, type_, arguments in statement_parts:
185 if not isinstance(arguments, basestring):
186 prefix = syn_prefix(type_, group)
187 if type_ == 'keyword':
188 stmt_iter = fill_stmt(arguments,
189 FILL - len(prefix) - len(indent))
192 print>>FILE, indent + prefix + stmt_iter.next()
193 except StopIteration:
196 for argument in arguments:
197 print>>FILE, indent + prefix + argument
202 print>>FILE, indent + syn_prefix(type_, group) + arguments
209 # Associating Python group with Vim colour group
210 for statement_var, statement_parts in statements:
212 print>>FILE, ' if exists("%s")' % statement_var
216 for colour_group, group, type_, arguments in statement_parts:
217 print>>FILE, (indent + "hi def link %s %s" %
218 (group, colour_group))
221 print>>FILE, ' endif'
223 # Statements at the end of the file
224 print>>FILE, statement_footer
226 if __name__ == '__main__':