pmacs3/tab.py

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