diff --git a/plugin/UltiSnips/TextObjects.py b/plugin/UltiSnips/TextObjects.py index 2a9637b..1e539cf 100644 --- a/plugin/UltiSnips/TextObjects.py +++ b/plugin/UltiSnips/TextObjects.py @@ -227,13 +227,17 @@ class TextObject(CheapTotalOrdering): def initial_replace(self): ct = self._initial_text # TODO: Initial Text is nearly unused. debug("self._start: %r, self._end: %r" % (self._start, self._end)) + debug("self.abs_start: %r, self.abs_end: %r" % (self.abs_start, self.abs_end)) debug("ct: %r" % (ct)) old_end = self.abs_end ct.to_vim(self.abs_start, self.abs_end) # TODO: to vim returns something unused + debug("self.abs_end: %r" % (self.abs_end)) self._end = ct.calc_end(self._start) + debug("self.abs_start: %r, self.abs_end: %r" % (self.abs_start, self.abs_end)) if self.abs_end != old_end: - if self._parent is not None: - self._parent.child_end_moved(old_end, self.abs_end - old_end, set((self,))) + exclude = set(c for c in self._childs) + exclude.add(self) + self.child_end_moved(old_end, self.abs_end - old_end, exclude) def __cmp__(self, other): return self._start.__cmp__(other._start) @@ -320,18 +324,19 @@ class TextObject(CheapTotalOrdering): if self not in skip: _move_end(self) + for c in self._childs: if c in skip: continue _move_start(c) _move_end(c) - for c in self._childs: # TODO: is this needed? - if c.abs_start == self.abs_start and (c._start == c._end): - debug("Deleting Child: c: %r" % (c)) - self._del_child(c) # TODO: What about mirrors? + if self._parent and self._parent not in skip: + self._parent.child_end_moved(sp, diff, set((self,))) + def _do_edit(self, cmd): debug("self: %r, cmd: %r" % (self, cmd)) + debug("self._childs: %r" % (self._childs)) def __del_move_col_end(obj): end = obj.abs_end if end.line == line and end.col > col: @@ -352,50 +357,46 @@ class TextObject(CheapTotalOrdering): obj._start.col += 1 ctype, line, col, char = cmd - assert(char != '\n') + assert('\n' not in char) pos = Position(line, col) + to_kill = set() for c in self._childs: - abs_span = c.abs_span - if pos in abs_span: - if c._do_edit(cmd): - return True + abs_start = c.abs_start + abs_end = c.abs_end + + if ctype == "D": + end_pos = pos + Position(0, len(char)) + # TODO: char is no longer true -> Text + # Case: this deletion removes the child + if (pos <= abs_start and end_pos > abs_end): + to_kill.add(c) + # Case: this edit command is completely for the child + elif (abs_start <= pos <= abs_end) and (abs_start <= end_pos <= abs_end): + c._do_edit(cmd) + return + if ctype == "I": + if (abs_start <= pos <= abs_end): + c._do_edit(cmd) + return + for c in to_kill: + debug("Kill c: %r" % (c)) + self._del_child(c) # We have to handle this ourselves - if ctype == "D": - if self._start == self._end: - self._parent._del_child(self) - return False - oe = self.abs_end - __del_move_col_end(self) + if ctype == "D": # TODO: code duplication + assert(self.abs_start != self.abs_end) # Makes no sense to delete in empty textobject - for c in self._childs: - debug("b4c: %r" % (c)) - __del_move_col_start(c) - __del_move_col_end(c) - debug("afc: %r" % (c)) - ne = self.abs_end + delta = Position(0, -len(char)) + self._end += delta - if self._parent and oe != ne: - self._parent.child_end_moved(oe, ne - oe, set((self,))) + self.child_end_moved(self.abs_end, delta, set((self,))) else: - oe = self.abs_end - __ins_move_col_end(self) + old_end = self.abs_end + delta = Position(0, len(char)) + self._end += delta - for c in self._childs: - debug("b4c: %r" % (c)) - __ins_move_col_start(c) - __ins_move_col_end(c) - debug("afc: %r" % (c)) - - ne = self.abs_end - if self._parent and oe != ne: - self._parent.child_end_moved(oe, ne - oe, set((self,))) - - for c in self._childs: # TODO: Code duplicate - if c.abs_start == self.abs_start and (c._start == c._end): - debug("Deleting Child: c: %r" % (c)) - self._del_child(c) # TODO: What about mirrors? + self.child_end_moved(old_end, delta, set((self,))) return True diff --git a/plugin/UltiSnips/__init__.py b/plugin/UltiSnips/__init__.py index 898a1d5..ecf269d 100644 --- a/plugin/UltiSnips/__init__.py +++ b/plugin/UltiSnips/__init__.py @@ -791,7 +791,7 @@ class SnippetManager(object): debug("rv: %r" % (rv,)) cv = edit_distance.compactify(rv) debug("cv: %r" % (cv)) - self._csnippets[0].edited(rv) + self._csnippets[0].edited(cv) # debug("rv: %r" % (rv,)) self._lvb = cb diff --git a/plugin/UltiSnips/edit_distance.py b/plugin/UltiSnips/edit_distance.py index 9130d65..7fdfd5e 100755 --- a/plugin/UltiSnips/edit_distance.py +++ b/plugin/UltiSnips/edit_distance.py @@ -4,7 +4,6 @@ import heapq # TODO: overkill. Bucketing is better from collections import defaultdict import sys -from debug import debug class GridPoint(object): """Docstring for GridPoint """ @@ -29,34 +28,33 @@ def edit_script(a, b): cost = 0 while True: while len(d[cost]): - x, y, nline, ncol, what = d[cost].pop() + x, y, line, col, what = d[cost].pop() if x == len(a) and y == len(b): return what - while x < len(a) and y < len(b) and a[x] == b[y]: - ncol += 1 + if x < len(a) and y < len(b) and a[x] == b[y]: + ncol = col + 1 + nline = line if a[x] == '\n': ncol = 0 - nline += 1 - if seen[x,y] > cost: + nline +=1 + if seen[x+1,y+1] > cost: d[cost].append((x+1,y+1, nline, ncol, what)) - seen[x,y] = cost - x += 1 - y += 1 - if x < len(a): - if seen[x+1,y] > cost + 1: - seen[x+1,y] = cost + 1 - d[cost + 1].append((x+1,y, nline, ncol, what + (("D",nline, ncol, a[x]),) )) + seen[x+1,y+1] = cost if y < len(b): - oline, ocol = nline, ncol - ncol += 1 + ncol = col + 1 + nline = line if b[y] == '\n': ncol = 0 nline += 1 if seen[x,y+1] > cost + 1: seen[x,y+1] = cost + 1 - d[cost + 1].append((x,y+1, nline, ncol, what + (("I", oline, ocol,b[y]),))) + d[cost + 1].append((x,y+1, nline, ncol, what + (("I", line, col,b[y]),))) + if x < len(a): + if seen[x+1,y] > cost + 1: + seen[x+1,y] = cost + 1 + d[cost + 1].append((x+1,y, line, col, what + (("D",line, col, a[x]),) )) cost += 1 def compactify(es): @@ -104,6 +102,10 @@ class TestLotsaNewlines(_Base, unittest.TestCase): class TestCrash(_Base, unittest.TestCase): a = 'hallo Blah mitte=sdfdsfsd\nhallo kjsdhfjksdhfkjhsdfkh mittekjshdkfhkhsdfdsf' b = 'hallo Blah mitte=sdfdsfsd\nhallo b mittekjshdkfhkhsdfdsf' + +class TestRealLife(_Base, unittest.TestCase): + a = 'hallo End Beginning' + b = 'hallo End t' # def test_all_match(self): # rv = edit_script("abcdef", "abcdef") # self.assertEqual("MMMMMM", rv) diff --git a/test.py b/test.py index dc92067..a484aec 100755 --- a/test.py +++ b/test.py @@ -563,6 +563,10 @@ class TabStopSimpleReplace_ExceptCorrectResult(_VimTest): snippets = ("hallo", "hallo ${0:End} ${1:Beginning}") keys = "hallo" + EX + "na" + JF + "Du Nase" wanted = "hallo Du Nase na" +class TabStopSimpleReplaceReversed_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "hallo ${1:End} ${0:Beginning}") + keys = "hallo" + EX + "na" + JF + "Du Nase" + wanted = "hallo na Du Nase" class TabStopSimpleReplaceSurrounded_ExceptCorrectResult(_VimTest): snippets = ("hallo", "hallo ${0:End} a small feed") keys = "hallo" + EX + "Nase" @@ -719,7 +723,7 @@ class TabStop_TSInDefaultText_ZeroLengthNested_Overwrite(_VimTest): keys = "test" + EX + JF + "ups" + JF + "End" wanted = """haupsblEnd""" - +# TODO: Test for Python where initial text is longer than python code. Might lead to problems ##class TabStop_TSInDefaultNested_OverwriteOneJumpBackToOther(_VimTest): ## snippets = ("test", "hi ${1:this ${2:second ${3:third}}} $4") ## keys = "test" + EX + JF + "Hallo" + JF + "Ende"