209 lines
6.7 KiB
Python
209 lines
6.7 KiB
Python
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:
|
|
wsre = regex.whitespace
|
|
wst = ('null', 'eol',)
|
|
sre = regex.space
|
|
st = ('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.fqname() in self.wst and self.wsre.match(token.string)
|
|
def token_is_space(self, y, i):
|
|
token = self.get_token(y, i)
|
|
return token.name in self.st and self.sre.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 get_nonws_tokens(self, y):
|
|
tokens = self.get_tokens(y)
|
|
for i in range(0, len(tokens)):
|
|
if not self.token_is_whitespace(y, i):
|
|
yield tokens[i]
|
|
raise StopIteration
|
|
def get_nons_tokens(self, y):
|
|
tokens = self.get_tokens(y)
|
|
for i in range(0, len(tokens)):
|
|
if not self.token_is_space(y, i):
|
|
yield tokens[i]
|
|
raise StopIteration
|
|
|
|
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 in self.mode.closetokens and s in self.mode.closetags:
|
|
currlvl = self._handle_close_token(currlvl, y, i)
|
|
elif token.name in self.mode.opentokens 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
|
|
level = self.get_curr_level() + self.mode.tabwidth
|
|
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, "mismatched closing tag %r vs %r" % (s2, s1)
|
|
return currlvl
|
|
def _handle_other_token(self, currlvl, y, i):
|
|
return currlvl
|
|
|
|
def _has_markers(self):
|
|
return len(self.markers) > 0
|
|
def _empty(self):
|
|
return len(self.markers) == 0
|
|
def _append(self, name, level):
|
|
self.markers.append(Marker(name, level))
|
|
def _peek(self):
|
|
return self.markers[-1]
|
|
def _peek_name(self):
|
|
return self.markers[-1].name
|
|
def _peek_level(self):
|
|
return self.markers[-1].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)
|