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
that has a span in any ways
"""
_TABSTOP = re.compile(r'''(?xms)
(?:\${(\d+):(.*?)})| # A simple tabstop with default value
(?:\$(\d+)) # A mirror or a tabstop without default value.
''')
# A simple tabstop with default value
_TABSTOP = re.compile(r'''\${(\d+):(.*?)}''')
# A mirror or a tabstop without default value.
_MIRROR_OR_TS = re.compile(r'\$(\d+)')
def __init__(self, parent, start, end, initial_text):
self._start = start
@ -137,13 +137,23 @@ class TextObject(object):
if parent is not None:
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):
pass
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))
for c in self._children:
debug("%s Updating Child%s" % (indend, c))
@ -180,7 +190,6 @@ class TextObject(object):
if m == obj:
continue
debug("Considering %s for moving!" % m)
delta_lines = 0
delta_cols_begin = 0
@ -196,8 +205,6 @@ class TextObject(object):
if m.start.line == m.end.line:
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.end.line += delta_lines
m.start.col += delta_cols_begin
@ -207,7 +214,7 @@ class TextObject(object):
def _get_pos(s, pos):
line_idx = s[:pos].count('\n')
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 _get_pos(val, start_pos), _get_pos(val, end_pos)
@ -220,14 +227,10 @@ class TextObject(object):
start_pos, end_pos = m.span()
start, end = self._get_start_end(val,start_pos,end_pos)
val = val[:start_pos] + val[end_pos:]
ts = TabStop(self, start, def_text)
ts = TabStop(self, start, end, def_text)
self.add_tabstop(no,ts)
return val
def _get_tabstop(self,no):
if no in self._tabstops:
return self._tabstops[no]
@ -235,35 +238,41 @@ class TextObject(object):
return self._parent._get_tabstop(no)
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, end = self._get_start_end(val,start_pos,end_pos)
ts = self._get_tabstop(no)
if ts is not None:
m = Mirror(self, ts, start)
m = Mirror(self, ts, start, end)
else:
ts = TabStop(self, start)
ts = TabStop(self, start, end)
self.add_tabstop(no,ts)
val = val[:start_pos] + val[end_pos:]
return val
def add_tabstop(self,no, ts):
self._tabstops[no] = ts
def _parse(self, val):
while 1:
m = self._TABSTOP.search(val)
self._has_parsed = True
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))
return val
@ -312,8 +321,7 @@ class Mirror(ChangeableText):
"""
A Mirror object mirrors a TabStop that is, text is repeated here
"""
def __init__(self, parent, ts, start):
end = start + (ts.end - ts.start)
def __init__(self, parent, ts, start, end):
ChangeableText.__init__(self, parent, start, end)
self._ts = ts
@ -331,16 +339,15 @@ class TabStop(ChangeableText):
This is the most important TextObject. A TabStop is were the cursor
comes to rest when the user taps through the Snippet.
"""
def __init__(self, parent, start, default_text = ""):
end = Position(start.line,start.col)
def __init__(self, parent, start, end, default_text = ""):
ChangeableText.__init__(self, parent, start, end, default_text)
def __repr__(self):
return "TabStop(%s -> %s, %s)" % (self._start, self._end,
repr(self._current_text))
def select(self):
lineno, col = self._parent.start.line, self._parent.start.col
def select(self, start):
lineno, col = start.line, start.col
newline = lineno + self._start.line
newcol = self._start.col
@ -350,18 +357,23 @@ class TabStop(ChangeableText):
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:
# 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':
move_one_right = "l"
else:
move_one_right = ""
vim.command(r'call feedkeys("\<Esc>%sv%il\<c-g>")'
% (move_one_right, len(self.current_text)-1))
if 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):
@ -380,6 +392,8 @@ class SnippetInstance(TextObject):
self._vb = VimBuffer(text_before, text_after)
self._current_text = TextBuffer(self._parse(initial_text))
debug("Before update!");
self.update(self._vb)
debug("After update!");
@ -417,7 +431,7 @@ class SnippetInstance(TextObject):
ts = self._tabstops[self._cts]
ts.select()
ts.select(self._start)
self._tab_selected = True
return True

64
test.py
View File

@ -167,8 +167,17 @@ class TabStopNoReplace_ExceptCorrectResult(_VimTest):
self.type("echo\t")
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):
snippets = ("hallo", "hallo ${0:End} mitte ${1:Beginning}")
snippets = ("hallo", "hallo ${2:End} mitte ${1:Beginning}")
wanted = "hallo TestHi mitte Beginning"
def cmd(self):
self.type("hallo\t\tTest\tHi")
@ -254,6 +263,19 @@ class TextTabStopAllSurrounded_ExceptCorrectResult(_VimTest):
self.type("test\thallo welt")
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):
snippets = ("test", "$1\n$1")
wanted = "hallo\nhallo"
@ -286,7 +308,6 @@ class MultilineTabStopSimpleMirrorDeleteInLine_ExceptCorrectResult(_VimTest):
self.type("test\thallo Du\nHi\b\bAch Blah")
def runTest(self): self.check_output()
class SimpleMirrorDelete_ExceptCorrectResult(_VimTest):
snippets = ("test", "$1\n$1")
wanted = "hal\nhal"
@ -379,21 +400,36 @@ class TabstopWithMirrorInDefaultOverwrite_ExceptCorrectResult(_VimTest):
self.type("test\tstdin\toverwritten")
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: 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__':
import sys