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: def __init__(self, m): self.mode = m self.lines = {} 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): m = regex.whitespace.match(tokens[i - j].string) if not m: 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)): m = regex.whitespace.match(tokens[j].string) if not m: 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 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 def get_level(markers): if markers: return markers[-1].level else: return 0 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 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 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): highlighter = self.mode.window.buffer.highlights[self.mode.name()] target = 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 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 s1 == self.mode.opentags[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 _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) class PerlTabber(StackTabber): def is_base(self, y): if y == 0: return True highlighter = self.mode.window.buffer.highlights[self.mode.name()] if not highlighter.tokens[y]: return False t = highlighter.tokens[y][0] if t.name == 'keyword' and t.string == 'sub': return True return False def _handle_open_token(self, currlvl, y, i): currlvl = StackTabber._handle_open_token(self, currlvl, y, i) return currlvl def _handle_close_token(self, currlvl, y, i): self._opt_pop('cont') currlvl = StackTabber._handle_close_token(self, currlvl, y, i) token = self.get_token(y, i) if token.string == '}': self._opt_pop('cont') elif self.is_rightmost_token(y, i): self._opt_append('cont', currlvl + 4) return currlvl def _handle_other_token(self, currlvl, y, i): token = self.get_token(y, i) fqname = token.fqname() if fqname == 'delimiter' and token.string == ';': self._opt_pop('cont') elif fqname == 'heredoc.start': self._opt_append('heredoc', None) elif fqname == 'heredoc.end': self._opt_pop('heredoc') self._opt_pop('cont') elif fqname == 'pod.start': self._opt_append('pod', None) elif fqname == 'pod.end': self._opt_pop('pod') currlvl = 0 elif fqname == 'string.start': self._opt_append('string', None) elif fqname == 'string.end': self._opt_pop('string') if self.is_rightmost_token(y, i): self._opt_append('cont', currlvl + 4) if self.is_rightmost_token(y, i): if(not fqname.startswith('pod') and not fqname.startswith('heredoc') and not fqname.startswith('string') and not fqname.startswith('endblock') and not fqname == 'comment' and not fqname == 'null' and token.string not in ('}', ';', '(', '{', '[', ',')): self._opt_append('cont' % fqname, currlvl + 4) return currlvl