pmacs3/tab2.py

216 lines
7.2 KiB
Python
Raw Normal View History

import regex, util
from point2 import Point
class Marker:
def __init__(self, name, level):
self.name = name
self.level = level
def __repr__(self):
return '<Marker(%r, %r)>' % (self.name, self.level)
class Tabber:
def __init__(self, m):
self.mode = m
self.lines = {}
2007-06-19 14:45:51 -04:00
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):
2007-06-19 14:45:51 -04:00
m = regex.whitespace.match(tokens[i - j].string)
if not m:
2007-06-19 14:45:51 -04:00
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)
2007-06-19 14:45:51 -04:00
for j in range(i + 1, len(tokens)):
m = regex.whitespace.match(tokens[j].string)
if not m:
2007-06-19 14:45:51 -04:00
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):
2007-06-19 14:45:51 -04:00
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]
2007-06-19 14:45:51 -04:00
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):
2007-06-19 14:45:51 -04:00
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)
2007-06-19 14:45:51 -04:00
else:
currlvl = self._handle_other_token(currlvl, y, i)
return currlvl
2007-06-19 14:45:51 -04:00
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):
2007-06-19 14:45:51 -04:00
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()
2007-06-19 14:45:51 -04:00
if self.is_leftmost_token(y, i):
currlvl = self.get_curr_level()
#else:
# raise Exception, "hmmmm: %r" % self.get_next_left_token(y, i)
2007-06-19 14:45:51 -04:00
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)
2007-06-19 14:45:51 -04:00
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