bugfixes and comments for mode_python
--HG-- branch : pmacs2
This commit is contained in:
parent
cec50f0ad7
commit
865b3b33bc
|
@ -28,15 +28,16 @@ class PythonGrammar(Grammar):
|
|||
PatternRule(name=r"integer", pattern=r"(?<![\.0-9a-zA-Z_])(?:0|[1-9][0-9]*|0[0-7]+|0[xX][0-9a-fA-F]+)[lL]?(?![\.0-9a-zA-Z_])"),
|
||||
PatternRule(name=r"float", pattern=r"(?<![\.0-9a-zA-Z_])(?:[0-9]+\.[0-9]*|\.[0-9]+|(?:[0-9]|[0-9]+\.[0-9]*|\.[0-9]+)[eE][\+-]?[0-9]+)(?![\.0-9a-zA-Z_])"),
|
||||
PatternRule(name=r"imaginary", pattern=r"(?<![\.0-9a-zA-Z_])(?:[0-9]+|(?:[0-9]+\.[0-9]*|\.[0-9]+|(?:[0-9]|[0-9]+\.[0-9]*|\.[0-9]+)[eE][\+-]?[0-9]+)[jJ])(?![\.0-9a-zA-Z_])"),
|
||||
RegionRule(name=r'docstring', start=r'^ *(?P<tag>"""|\'\'\')', grammar=Grammar(), end=r'%(tag)s'),
|
||||
RegionRule(name=r'string', start=r'(?P<tag>"""|\'\'\')', grammar=StringGrammar(), end=r'%(tag)s'),
|
||||
RegionRule(name=r'string', start=r'(?P<tag>"|\')', grammar=StringGrammar(), end=r'%(tag)s'),
|
||||
RegionRule(name=r'string', start=r'"""', grammar=StringGrammar(), end=r'"""'),
|
||||
RegionRule(name=r'string', start=r"'''", grammar=StringGrammar(), end=r"'''"),
|
||||
RegionRule(name=r'string', start=r'"', grammar=StringGrammar(), end=r'"'),
|
||||
RegionRule(name=r'string', start=r"'", grammar=StringGrammar(), end=r"'"),
|
||||
PatternRule(name=r'comment', pattern=r'#.*$'),
|
||||
PatternRule(name=r'continuation', pattern=r'\\$'),
|
||||
]
|
||||
|
||||
class PythonTabber(tab2.StackTabber):
|
||||
unanchored_names = ('null', 'string', 'docstring', 'comment')
|
||||
unanchored_names = ('null', 'string', 'comment')
|
||||
endlevel_names = ('pass', 'return', 'yield', 'raise', 'break', 'continue')
|
||||
startlevel_names = ('if', 'try', 'class', 'def', 'for', 'while', 'try')
|
||||
def __init__(self, m):
|
||||
|
@ -45,13 +46,18 @@ class PythonTabber(tab2.StackTabber):
|
|||
|
||||
def is_base(self, y):
|
||||
if y == 0:
|
||||
# we always know that line 0 is indented at the 0 level
|
||||
return True
|
||||
tokens = self.get_tokens(y)
|
||||
if not tokens:
|
||||
# if a line has no tokens, we don't know much about its indentation
|
||||
return False
|
||||
elif tokens[0].name not in self.unanchored_names:
|
||||
# if a line has no whitespace and beings with something like
|
||||
# 'while','class','def','if',etc. then we can start at it
|
||||
return True
|
||||
else:
|
||||
# otherwise, we can't be sure that its level is correct
|
||||
return False
|
||||
|
||||
def get_level(self, y):
|
||||
|
@ -59,15 +65,25 @@ class PythonTabber(tab2.StackTabber):
|
|||
return self.lines.get(y)
|
||||
|
||||
def _calc_level(self, y):
|
||||
# ok, so first remember where we are going, and find our starting point
|
||||
target = y
|
||||
while not self.is_base(y) and y > 0:
|
||||
y -= 1
|
||||
|
||||
# ok, so clear out our stack and then loop over each line
|
||||
self.markers = []
|
||||
while y <= target:
|
||||
self.continued = False
|
||||
self.popped = False
|
||||
tokens = self.get_tokens(y)
|
||||
currlvl = self.get_curr_level()
|
||||
# if we were continuing, let's pop that previous continuation token
|
||||
# and note that we're continuing
|
||||
if self.markers and self.markers[-1].name == 'cont':
|
||||
self.continued = True
|
||||
self._pop()
|
||||
# if we haven't reached the target-line yet, we can detect how many
|
||||
# levels of unindention, if any, the user chose on previous lines
|
||||
if y < target and tokens:
|
||||
if self.token_is_whitespace(y, 0):
|
||||
l = len(tokens[0].string)
|
||||
|
@ -77,8 +93,10 @@ class PythonTabber(tab2.StackTabber):
|
|||
self._pop()
|
||||
currlvl = self.get_curr_level()
|
||||
self.popped = True
|
||||
# ok, having done all that, we can now process each token on the line
|
||||
for i in range(0, len(tokens)):
|
||||
currlvl = self._handle_token(currlvl, y, i)
|
||||
# so let's store the level for this line, as well as some debugging
|
||||
self.lines[y] = currlvl
|
||||
self.record[y] = tuple(self.markers)
|
||||
y += 1
|
||||
|
@ -86,40 +104,50 @@ class PythonTabber(tab2.StackTabber):
|
|||
def _handle_other_token(self, currlvl, y, i):
|
||||
token = self.get_token(y, i)
|
||||
fqname = token.fqname()
|
||||
if fqname == 'string.start':
|
||||
if fqname == 'continuation':
|
||||
# we need to pop the indentation level over, unless last line was
|
||||
# also a continued line
|
||||
if self.continued:
|
||||
self._opt_append('cont', currlvl)
|
||||
else:
|
||||
self._opt_append('cont', currlvl + 4)
|
||||
elif fqname == 'string.start':
|
||||
# while inside of a string, there is no indention leve
|
||||
self._opt_append('string', None)
|
||||
elif fqname == 'string.end':
|
||||
# since we're done with the string, resume our indentation level
|
||||
self._opt_pop('string')
|
||||
elif fqname == 'docstring.start':
|
||||
self._opt_append('docstring', None)
|
||||
elif fqname == 'docstring.end':
|
||||
self._opt_pop('docstring')
|
||||
elif fqname == 'delimiter':
|
||||
if token.string == ':' and self.markers and self.markers[-1].name in ('[', '{'):
|
||||
# we are in a list range [:] or dictionary key/value {:}
|
||||
# we only reall care about a colon as part of a one-line statement,
|
||||
# i.e. "while ok: foo()" or "if True: print 3"
|
||||
if token.string == ':':
|
||||
if self.markers and self.markers[-1].name in ('[', '{'):
|
||||
pass
|
||||
elif self.is_rightmost_token(y, i):
|
||||
# we are at the end of a block
|
||||
pass
|
||||
else:
|
||||
# we are doing a one-liner
|
||||
self._pop()
|
||||
elif fqname == 'keyword':
|
||||
if token.string in self.endlevel_names:
|
||||
# we know we'll unindent at least once
|
||||
self._pop()
|
||||
elif token.string in self.startlevel_names and self.is_leftmost_token(y, i):
|
||||
# we know we will indent exactly once
|
||||
self._append(token.string, currlvl + 4)
|
||||
elif token.string in ('elif', 'else') and self.is_leftmost_token(y, i):
|
||||
# we know we'll unindent at least to the first if/elif
|
||||
if not self.popped:
|
||||
self._pop_until('if', 'elif')
|
||||
currlvl = self.get_curr_level()
|
||||
self._append(token.string, currlvl + 4)
|
||||
elif token.string == 'except' and self.is_leftmost_token(y, i):
|
||||
# we know we'll unindent at least to the first try
|
||||
if not self.popped:
|
||||
self._pop_until('try')
|
||||
currlvl = self.get_curr_level()
|
||||
self._append(token.string, currlvl + 4)
|
||||
elif token.string == 'finally' and self.is_leftmost_token(y, i):
|
||||
# we know we'll unindent at least to the first try/except
|
||||
if not self.popped:
|
||||
self._pop_until('try', 'except')
|
||||
currlvl = self.get_curr_level()
|
||||
|
@ -135,45 +163,35 @@ class Python(mode2.Fundamental):
|
|||
closetags = {')': '(', ']': '[', '}': '{'}
|
||||
def __init__(self, w):
|
||||
mode2.Fundamental.__init__(self, w)
|
||||
|
||||
# tag matching
|
||||
self.add_bindings('close-paren', (')',))
|
||||
self.add_bindings('close-brace', ('}',))
|
||||
self.add_bindings('close-bracket', (']',))
|
||||
# add python-specific methods
|
||||
self.add_action_and_bindings(PythonCheckSyntax(), ('C-c s',))
|
||||
self.add_action_and_bindings(PythonDictCleanup(), ('C-c h',))
|
||||
self.add_action_and_bindings(PythonUpdateTags(), ('C-c t',))
|
||||
self.add_action_and_bindings(PythonTagComplete(), ('C-c k',))
|
||||
|
||||
# we want to do these kinds of tag matching
|
||||
self.add_bindings('close-paren', (')',))
|
||||
self.add_bindings('close-brace', ('}',))
|
||||
self.add_bindings('close-bracket', (']',))
|
||||
|
||||
# highlighting
|
||||
self.colors = {
|
||||
'keyword': color.build('cyan', 'default'),
|
||||
'reserved': color.build('cyan', 'default'),
|
||||
'builtin': color.build('cyan', 'default'),
|
||||
'functionname': color.build('blue', 'default'),
|
||||
'classname': color.build('green', 'default'),
|
||||
|
||||
'string.start': color.build('green', 'default'),
|
||||
'string.null': color.build('green', 'default'),
|
||||
'string.escaped': color.build('magenta', 'default'),
|
||||
'string.octal': color.build('magenta', 'default'),
|
||||
'string.escaped': color.build('magenta', 'default'),
|
||||
'string.format': color.build('yellow', 'default'),
|
||||
'string.end': color.build('green', 'default'),
|
||||
|
||||
'integer': color.build('default', 'default'),
|
||||
'float': color.build('default', 'default'),
|
||||
'imaginary': color.build('default', 'default'),
|
||||
|
||||
'docstring.start': color.build('green', 'default'),
|
||||
'docstring.null': color.build('green', 'default'),
|
||||
'docstring.end': color.build('green', 'default'),
|
||||
|
||||
'comment': color.build('red', 'default'),
|
||||
'continuation': color.build('red', 'default'),
|
||||
'system_identifier': color.build('cyan', 'default'),
|
||||
}
|
||||
|
||||
def name(self):
|
||||
return "Python"
|
||||
|
||||
|
|
Loading…
Reference in New Issue