import regex, util from point2 import Point class Marker: def __init__(self, name, level): self.name = name self.level = level def __repr__(self): return '' % (self.name, self.level) class Tabber: wsre = regex.whitespace wst = 'null' def __init__(self, m): self.mode = m self.lines = {} def get_highlighter(self): return self.mode.window.buffer.highlights[self.mode.name()] def get_tokens(self, y): return self.mode.window.buffer.highlights[self.mode.name()].tokens[y] def get_token(self, y, i): return self.mode.window.buffer.highlights[self.mode.name()].tokens[y][i] def token_is_whitespace(self, y, i): token = self.get_token(y, i) return token.name == self.wst and self.wsre.match(token.string) def get_next_left_token(self, y, i): tokens = self.get_tokens(y) assert i >= 0 and i < len(tokens) for j in range(1, i): if not self.token_is_whitespace(y, i - j): return tokens[i - j] return None def get_next_right_token(self, y, i): tokens = self.get_tokens(y) assert i >= 0 and i < len(tokens) for j in range(i + 1, len(tokens)): if not self.token_is_whitespace(y, j): return tokens[j] return None def is_leftmost_token(self, y, i): return self.get_next_left_token(y, i) is None def is_rightmost_token(self, y, i): return self.get_next_right_token(y, i) is None def is_only_token(self, y, i): return self.is_leftmost_token(y, i) and self.is_rightmost_token(y, i) def get_leftmost_token(self, y): tokens = self.get_tokens(y) for i in range(0, len(tokens)): if not self.token_is_whitespace(y, i): return tokens[i] return None def get_rightmost_token(self, y): tokens = self.get_tokens(y) i = len(tokens) - 1 for j in range(0, len(tokens)): if not self.token_is_whitespace(y, i - j): return tokens[i - j] return None def region_added(self, p, newlines): self.lines = {} def region_removed(self, p1, p2): self.lines = {} def is_base(self, y): return True def get_level(self, y): if y in self.lines: return self.lines[y] else: self._calc_level(y) return self.lines.get(y) def _calc_level(self, y): pass class StackTabber(Tabber): def __init__(self, m): self.mode = m self.lines = {} self.record = {} self.markers = [] def get_curr_level(self): if self.markers: return self.markers[-1].level else: return 0 def region_added(self, p, newlines): self.lines = {} self.record = {} self.markers = [] def region_removed(self, p1, p2): self.lines = {} self.record = {} self.markers = [] def is_base(self, y): return y == 0 def _calc_level(self, y): # first we need to step back to find the last place where we have tab # stops figured out, or a suitable place to start target = y while not self.is_base(y) and y > 0: y -= 1 # ok now, let's do this shit self.markers = [] currlvl = 0 while y <= target: currlvl = self.get_curr_level() tokens = self.get_tokens(y) for i in range(0, len(tokens)): currlvl = self._handle_token(currlvl, y, i) self.lines[y] = currlvl self.record[y] = tuple(self.markers) y += 1 def _handle_token(self, currlvl, y, i): token = self.get_token(y, i) s = token.string if token.name == self.mode.closetoken and s in self.mode.closetags: currlvl = self._handle_close_token(currlvl, y, i) elif token.name == self.mode.opentoken and s in self.mode.opentags: currlvl = self._handle_open_token(currlvl, y, i) else: currlvl = self._handle_other_token(currlvl, y, i) return currlvl def _handle_open_token(self, currlvl, y, i): token = self.get_token(y, i) rtoken = self.get_next_right_token(y, i) if rtoken is None: level = self.get_curr_level() + 4 else: level = rtoken.x self._append(token.string, level) return currlvl def _handle_close_token(self, currlvl, y, i): token = self.get_token(y, i) s1 = token.string if not self.markers: raise Exception, "unmatched closing token %r" % s1 s2 = self.markers[-1].name if self.mode.closetags[s1] == s2: self._pop() if self.is_leftmost_token(y, i): currlvl = self.get_curr_level() #else: # raise Exception, "hmmmm: %r" % self.get_next_left_token(y, i) else: raise Exception, "mismatched closing tag %r vs %r" % (s2, s1) return currlvl def _handle_other_token(self, currlvl, y, i): return currlvl def _append(self, name, level): self.markers.append(Marker(name, level)) def _pop(self): self.markers.pop(-1) def _pop_until(self, *names): while self.markers: if self.markers[-1].name in names: self.markers.pop(-1) return else: self.markers.pop(-1) def _opt_append(self, name, level): if self.markers and self.markers[-1].name == name: pass else: self._append(name, level) def _opt_pop(self, *names): if self.markers and self.markers[-1].name in names: self.markers.pop(-1)