141 lines
4.6 KiB
Python
141 lines
4.6 KiB
Python
|
import point, regex, util
|
||
|
|
||
|
class Tabber:
|
||
|
def __init__(self, m):
|
||
|
self.mode = m
|
||
|
self.levels = None
|
||
|
|
||
|
def invalidate(self):
|
||
|
self.levels = None
|
||
|
|
||
|
def calculate_tabs(self):
|
||
|
raise Exception, "Unimplemented 22"
|
||
|
|
||
|
def get_indentation_level(self, y):
|
||
|
if self.levels is None:
|
||
|
self.calculate_tabs()
|
||
|
return self.levels[y]
|
||
|
|
||
|
class TokenStackTabber(Tabber):
|
||
|
def __init__(self, m):
|
||
|
Tabber.__init__(self, m)
|
||
|
|
||
|
# state variables for tab processing
|
||
|
self.errors = None
|
||
|
self.y = None
|
||
|
self.index = None
|
||
|
self.tab_stack = None
|
||
|
self.line_depth = None
|
||
|
self.start_offset = None
|
||
|
self.end_offset = None
|
||
|
|
||
|
def stack_append(self, item):
|
||
|
self.tab_stack.append(item)
|
||
|
def stack_pop(self):
|
||
|
assert len(self.tab_stack) > 1, "rjrjrjr"
|
||
|
self.tab_stack.pop(-1)
|
||
|
|
||
|
def handle_token(self, prev_token, token, next_token, y=None):
|
||
|
s = token.string
|
||
|
if s == "(":
|
||
|
if next_token is None:
|
||
|
self.stack_append((s, self.tab_stack[-1][1] + 4))
|
||
|
else:
|
||
|
p = self.mode.window.buffer.get_offset_point(next_token.start)
|
||
|
self.stack_append((s, p.x))
|
||
|
elif s == ")":
|
||
|
if self.tab_stack[-1][0] == "(":
|
||
|
self.stack_pop()
|
||
|
if prev_token is None:
|
||
|
self.line_depth = self.tab_stack[-1][1]
|
||
|
else:
|
||
|
# mismatched tag
|
||
|
if self.errors is False:
|
||
|
err = "line %d: expected %r, got %r" % \
|
||
|
(self.tab_stack[-1][0], s)
|
||
|
self.mode.window.application.set_error(err)
|
||
|
self.errors = True
|
||
|
|
||
|
def base_indentation_level(self, y):
|
||
|
return y == 0
|
||
|
|
||
|
def calculate_tabs(self, start=0, goal=None):
|
||
|
lines = self.mode.window.buffer.lines
|
||
|
tokens = self.mode.highlighter.tokens
|
||
|
buffer = self.mode.window.buffer
|
||
|
|
||
|
if self.levels is None:
|
||
|
self.levels = [None] * (len(lines))
|
||
|
|
||
|
self.errors = False
|
||
|
self.index = 0
|
||
|
self.y = start
|
||
|
self.tab_stack = [(None, 0)]
|
||
|
|
||
|
# we want to process every logical line in the file
|
||
|
while self.y < len(lines):
|
||
|
self.line_depth = self.tab_stack[-1][1]
|
||
|
|
||
|
if self.index >= len(tokens):
|
||
|
self.levels[self.y] = self.line_depth
|
||
|
self.y += 1
|
||
|
continue
|
||
|
|
||
|
line = lines[self.y]
|
||
|
self.start_offset = buffer.get_point_offset(point.Point(0, self.y))
|
||
|
self.end_offset = buffer.get_point_offset(point.Point(len(line), self.y))
|
||
|
|
||
|
# we want to find all the tokens on the line we are currently processing
|
||
|
while self.index < len(tokens):
|
||
|
token = tokens[self.index]
|
||
|
|
||
|
# previous token, or None if token is first on the line
|
||
|
if self.index > 0 and \
|
||
|
tokens[self.index - 1].start > self.start_offset:
|
||
|
prev_token = tokens[self.index - 1]
|
||
|
else:
|
||
|
prev_token = None
|
||
|
|
||
|
# next token, or None if token is last on the line
|
||
|
#if self.index < len(tokens) - 1 and \
|
||
|
if self.index < len(tokens) - 1 and \
|
||
|
tokens[self.index + 1].end <= self.end_offset:
|
||
|
next_token = tokens[self.index + 1]
|
||
|
else:
|
||
|
next_token = None
|
||
|
|
||
|
if token.end < self.start_offset:
|
||
|
# token is too far back
|
||
|
pass
|
||
|
elif token.start > self.end_offset:
|
||
|
# token is too far forward
|
||
|
break
|
||
|
else:
|
||
|
self.handle_token(prev_token, token, next_token, self.y)
|
||
|
|
||
|
if token.end >= self.end_offset:
|
||
|
# token continues to the next line
|
||
|
break
|
||
|
else:
|
||
|
self.index += 1
|
||
|
|
||
|
self.levels[self.y] = self.line_depth
|
||
|
self.y += 1
|
||
|
if goal is not None and self.y > goal:
|
||
|
return
|
||
|
|
||
|
def get_indentation_level(self, y):
|
||
|
if self.levels is not None and self.levels[y] is not None:
|
||
|
result = self.levels[y]
|
||
|
else:
|
||
|
i = max(0, y - 1)
|
||
|
while i > 0:
|
||
|
if self.base_indentation_level(i):
|
||
|
break
|
||
|
i -= 1
|
||
|
self.calculate_tabs(i, y)
|
||
|
result = self.levels[y]
|
||
|
if result == -1:
|
||
|
return None
|
||
|
return result
|