Fixed a bug with one char tabstops. Began working on transformation

This commit is contained in:
Holger Rapp 2009-07-03 13:54:35 +02:00
parent 7461ad1f54
commit 7438a73d2b
2 changed files with 106 additions and 56 deletions

View File

@ -120,10 +120,10 @@ class TextObject(object):
This base class represents any object in the text This base class represents any object in the text
that has a span in any ways that has a span in any ways
""" """
_TABSTOP = re.compile(r'''(?xms) # A simple tabstop with default value
(?:\${(\d+):(.*?)})| # A simple tabstop with default value _TABSTOP = re.compile(r'''\${(\d+):(.*?)}''')
(?:\$(\d+)) # A mirror or a tabstop without default value. # A mirror or a tabstop without default value.
''') _MIRROR_OR_TS = re.compile(r'\$(\d+)')
def __init__(self, parent, start, end, initial_text): def __init__(self, parent, start, end, initial_text):
self._start = start self._start = start
@ -137,13 +137,23 @@ class TextObject(object):
if parent is not None: if parent is not None:
parent.add_child(self) parent.add_child(self)
self._current_text = TextBuffer(self._parse(initial_text)) self._has_parsed = False
self._current_text = initial_text
debug("New text_object: %s" % self)
if len(self._children):
debug(" Children:")
for c in self._children:
debug(" %s" % c)
def _do_update(self): def _do_update(self):
pass pass
def update(self, change_buffer, indend = ""): def update(self, change_buffer, indend = ""):
if not self._has_parsed:
self._current_text = TextBuffer(self._parse(self._current_text))
debug("%sUpdating %s" % (indend, self)) debug("%sUpdating %s" % (indend, self))
for c in self._children: for c in self._children:
debug("%s Updating Child%s" % (indend, c)) debug("%s Updating Child%s" % (indend, c))
@ -180,7 +190,6 @@ class TextObject(object):
if m == obj: if m == obj:
continue continue
debug("Considering %s for moving!" % m)
delta_lines = 0 delta_lines = 0
delta_cols_begin = 0 delta_cols_begin = 0
@ -196,8 +205,6 @@ class TextObject(object):
if m.start.line == m.end.line: if m.start.line == m.end.line:
delta_cols_end = cols delta_cols_end = cols
debug("delta_lines: %i, delta_cols_begin: %i, delta_cols_end: %i" %
(delta_lines, delta_cols_begin, delta_cols_end))
m.start.line += delta_lines m.start.line += delta_lines
m.end.line += delta_lines m.end.line += delta_lines
m.start.col += delta_cols_begin m.start.col += delta_cols_begin
@ -207,7 +214,7 @@ class TextObject(object):
def _get_pos(s, pos): def _get_pos(s, pos):
line_idx = s[:pos].count('\n') line_idx = s[:pos].count('\n')
line_start = s[:pos].rfind('\n') + 1 line_start = s[:pos].rfind('\n') + 1
start_in_line = start_pos - line_start start_in_line = pos - line_start
return Position(line_idx, start_in_line) return Position(line_idx, start_in_line)
return _get_pos(val, start_pos), _get_pos(val, end_pos) return _get_pos(val, start_pos), _get_pos(val, end_pos)
@ -220,14 +227,10 @@ class TextObject(object):
start_pos, end_pos = m.span() start_pos, end_pos = m.span()
start, end = self._get_start_end(val,start_pos,end_pos) start, end = self._get_start_end(val,start_pos,end_pos)
val = val[:start_pos] + val[end_pos:] ts = TabStop(self, start, end, def_text)
ts = TabStop(self, start, def_text)
self.add_tabstop(no,ts) self.add_tabstop(no,ts)
return val
def _get_tabstop(self,no): def _get_tabstop(self,no):
if no in self._tabstops: if no in self._tabstops:
return self._tabstops[no] return self._tabstops[no]
@ -235,35 +238,41 @@ class TextObject(object):
return self._parent._get_tabstop(no) return self._parent._get_tabstop(no)
def _handle_ts_or_mirror(self, m, val): def _handle_ts_or_mirror(self, m, val):
no = int(m.group(3)) no = int(m.group(1))
start_pos, end_pos = m.span() start_pos, end_pos = m.span()
start, end = self._get_start_end(val,start_pos,end_pos) start, end = self._get_start_end(val,start_pos,end_pos)
ts = self._get_tabstop(no) ts = self._get_tabstop(no)
if ts is not None: if ts is not None:
m = Mirror(self, ts, start) m = Mirror(self, ts, start, end)
else: else:
ts = TabStop(self, start) ts = TabStop(self, start, end)
self.add_tabstop(no,ts) self.add_tabstop(no,ts)
val = val[:start_pos] + val[end_pos:]
return val
def add_tabstop(self,no, ts): def add_tabstop(self,no, ts):
self._tabstops[no] = ts self._tabstops[no] = ts
def _parse(self, val): def _parse(self, val):
while 1: self._has_parsed = True
m = self._TABSTOP.search(val)
if not len(val):
return val
for m in self._TABSTOP.finditer(val):
self._handle_tabstop(m,val)
# Replace the whole definition with spaces
s, e = m.span()
val = val[:s] + (e-s)*" " + val[e:]
debug("Handled a tabstop: %s" % repr(val))
for m in self._MIRROR_OR_TS.finditer(val):
self._handle_ts_or_mirror(m,val)
# Replace the whole definition with spaces
s, e = m.span()
val = val[:s] + (e-s)*" " + val[e:]
debug("Handled a mirror or ts: %s" % repr(val))
if m is not None:
if m.group(1) is not None: # ${1:hallo}
val = self._handle_tabstop(m,val)
elif m.group(3) is not None: # $1
val = self._handle_ts_or_mirror(m,val)
else:
break
debug("End of parse: %s" % repr(val)) debug("End of parse: %s" % repr(val))
return val return val
@ -312,8 +321,7 @@ class Mirror(ChangeableText):
""" """
A Mirror object mirrors a TabStop that is, text is repeated here A Mirror object mirrors a TabStop that is, text is repeated here
""" """
def __init__(self, parent, ts, start): def __init__(self, parent, ts, start, end):
end = start + (ts.end - ts.start)
ChangeableText.__init__(self, parent, start, end) ChangeableText.__init__(self, parent, start, end)
self._ts = ts self._ts = ts
@ -331,16 +339,15 @@ class TabStop(ChangeableText):
This is the most important TextObject. A TabStop is were the cursor This is the most important TextObject. A TabStop is were the cursor
comes to rest when the user taps through the Snippet. comes to rest when the user taps through the Snippet.
""" """
def __init__(self, parent, start, default_text = ""): def __init__(self, parent, start, end, default_text = ""):
end = Position(start.line,start.col)
ChangeableText.__init__(self, parent, start, end, default_text) ChangeableText.__init__(self, parent, start, end, default_text)
def __repr__(self): def __repr__(self):
return "TabStop(%s -> %s, %s)" % (self._start, self._end, return "TabStop(%s -> %s, %s)" % (self._start, self._end,
repr(self._current_text)) repr(self._current_text))
def select(self): def select(self, start):
lineno, col = self._parent.start.line, self._parent.start.col lineno, col = start.line, start.col
newline = lineno + self._start.line newline = lineno + self._start.line
newcol = self._start.col newcol = self._start.col
@ -350,18 +357,23 @@ class TabStop(ChangeableText):
vim.current.window.cursor = newline + 1, newcol vim.current.window.cursor = newline + 1, newcol
# Select the word
# Depending on the current mode and position, we
# might need to move escape out of the mode and this
# will move our cursor one left
if len(self.current_text) > 0: if len(self.current_text) > 0:
# Select the word
# Depending on the current mode and position, we
# might need to move escape out of the mode and this
# will move our cursor one left
if newcol != 0 and vim.eval("mode()") == 'i': if newcol != 0 and vim.eval("mode()") == 'i':
move_one_right = "l" move_one_right = "l"
else: else:
move_one_right = "" move_one_right = ""
vim.command(r'call feedkeys("\<Esc>%sv%il\<c-g>")' if len(self.current_text) == 1:
% (move_one_right, len(self.current_text)-1)) do_select = ""
else:
do_select = "%il" % (len(self.current_text)-1)
vim.command(r'call feedkeys("\<Esc>%sv%s\<c-g>")' %
(move_one_right, do_select))
class SnippetInstance(TextObject): class SnippetInstance(TextObject):
@ -380,6 +392,8 @@ class SnippetInstance(TextObject):
self._vb = VimBuffer(text_before, text_after) self._vb = VimBuffer(text_before, text_after)
self._current_text = TextBuffer(self._parse(initial_text))
debug("Before update!"); debug("Before update!");
self.update(self._vb) self.update(self._vb)
debug("After update!"); debug("After update!");
@ -417,7 +431,7 @@ class SnippetInstance(TextObject):
ts = self._tabstops[self._cts] ts = self._tabstops[self._cts]
ts.select() ts.select(self._start)
self._tab_selected = True self._tab_selected = True
return True return True

64
test.py
View File

@ -167,8 +167,17 @@ class TabStopNoReplace_ExceptCorrectResult(_VimTest):
self.type("echo\t") self.type("echo\t")
def runTest(self): self.check_output() def runTest(self): self.check_output()
# TODO: multiline tabstops, maybe?
class TabStopWithOneChar_ExceptCorrectResult(_VimTest):
snippets = ("hallo", "nothing ${1:i} hups")
wanted = "nothing ship hups"
def cmd(self):
self.type("hallo\tship")
def runTest(self): self.check_output()
class TabStopTestJumping_ExceptCorrectResult(_VimTest): class TabStopTestJumping_ExceptCorrectResult(_VimTest):
snippets = ("hallo", "hallo ${0:End} mitte ${1:Beginning}") snippets = ("hallo", "hallo ${2:End} mitte ${1:Beginning}")
wanted = "hallo TestHi mitte Beginning" wanted = "hallo TestHi mitte Beginning"
def cmd(self): def cmd(self):
self.type("hallo\t\tTest\tHi") self.type("hallo\t\tTest\tHi")
@ -254,6 +263,19 @@ class TextTabStopAllSurrounded_ExceptCorrectResult(_VimTest):
self.type("test\thallo welt") self.type("test\thallo welt")
def runTest(self): self.check_output() def runTest(self): self.check_output()
class MirrorBeforeTabstopLeave_ExceptCorrectResult(_VimTest):
snippets = ("test", "$1 ${1:this is it} $1")
wanted = "this is it this is it this is it"
def cmd(self):
self.type("test\t")
def runTest(self): self.check_output()
class MirrorBeforeTabstopOverwrite_ExceptCorrectResult(_VimTest):
snippets = ("test", "$1 ${1:this is it} $1")
wanted = "a a a"
def cmd(self):
self.type("test\ta")
def runTest(self): self.check_output()
class TextTabStopSimpleMirrorMultiline_ExceptCorrectResult(_VimTest): class TextTabStopSimpleMirrorMultiline_ExceptCorrectResult(_VimTest):
snippets = ("test", "$1\n$1") snippets = ("test", "$1\n$1")
wanted = "hallo\nhallo" wanted = "hallo\nhallo"
@ -286,7 +308,6 @@ class MultilineTabStopSimpleMirrorDeleteInLine_ExceptCorrectResult(_VimTest):
self.type("test\thallo Du\nHi\b\bAch Blah") self.type("test\thallo Du\nHi\b\bAch Blah")
def runTest(self): self.check_output() def runTest(self): self.check_output()
class SimpleMirrorDelete_ExceptCorrectResult(_VimTest): class SimpleMirrorDelete_ExceptCorrectResult(_VimTest):
snippets = ("test", "$1\n$1") snippets = ("test", "$1\n$1")
wanted = "hal\nhal" wanted = "hal\nhal"
@ -379,21 +400,36 @@ class TabstopWithMirrorInDefaultOverwrite_ExceptCorrectResult(_VimTest):
self.type("test\tstdin\toverwritten") self.type("test\tstdin\toverwritten")
def runTest(self): self.check_output() def runTest(self): self.check_output()
class MirrorRealLifeExample_ExceptCorrectResult(_VimTest):
snippets = (
("for", "for(size_t ${2:i} = 0; $2 < ${1:count}; ${3:++$2})" \
"\n{\n\t${0:/* code */}\n}"),
)
wanted = """for(size_t a_variable = 0; a_variable < 100; a_variable *= 2)
{
\t// do nothing
}"""
def cmd(self):
self.type("for\t100\tavar\b\b\b\ba_variable\ta_variable *= 2"
"\t// do nothing")
def runTest(self): self.check_output()
# class MirrorMoreInvolved_ExceptCorrectResult(_VimTest):
# snippets = (
# ("for", "for(size_t ${2:i} = 0; $2 < ${1:count}; ${3:++$2})\n{\n\t${0:/* code */}\n}"),
# )
#
# def cmd(self):
# self.type("for\t")
#
# def runTest(self):
# self.assertEqual(self.output,"hallo Du Nase na")
# TODO: recursive expansion # TODO: recursive expansion
# TODO: mirrors in default expansion
# TODO: $1 ${1:This is the tabstop} ###################
# TRANSFORMATIONS #
###################
class Transformation_SimpleCase_ExceptCorrectResult(_VimTest):
snippets = ("test", "$1 ${1/foo/batzl/}")
wanted = "hallo foo boy hallo batzl boy"
def cmd(self):
self.type("test\t","hallo foo boy")
class Transformation_SimpleCaseNoTransform_ExceptCorrectResult(_VimTest):
snippets = ("test", "$1 ${1/foo/batzl/}")
wanted = "hallo hallo"
def cmd(self):
self.type("test\t","hallo")
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys