Fixed a bug with one char tabstops. Began working on transformation
This commit is contained in:
parent
7461ad1f54
commit
7438a73d2b
98
PySnipEmu.py
98
PySnipEmu.py
@ -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
64
test.py
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user