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