From 9cc97cd7cb1168252d75bd523c83201f4da187ae Mon Sep 17 00:00:00 2001 From: Holger Rapp Date: Mon, 16 Jan 2012 22:25:12 +0100 Subject: [PATCH] All enabled tests pass again --- plugin/UltiSnips/TextObjects.py | 38 +++++--- plugin/UltiSnips/__init__.py | 8 +- plugin/UltiSnips/edit_distance.py | 147 ++++++++++++++++++++---------- 3 files changed, 125 insertions(+), 68 deletions(-) diff --git a/plugin/UltiSnips/TextObjects.py b/plugin/UltiSnips/TextObjects.py index 6befbe5..29a9205 100644 --- a/plugin/UltiSnips/TextObjects.py +++ b/plugin/UltiSnips/TextObjects.py @@ -331,8 +331,10 @@ class TextObject(CheapTotalOrdering): for c in self._childs: if c in skip: continue + debug("b4: c.abs_span: %r" % (c.abs_span)) _move_start(c) _move_end(c) + debug("a4: c.abs_span: %r" % (c.abs_span)) if self._parent and self._parent not in skip: self._parent.child_end_moved(sp, diff, set((self,))) @@ -402,14 +404,22 @@ class TextObject(CheapTotalOrdering): self.child_end_moved(old_end, delta, set((self,))) - return True - - def edited(self, cmds): debug("begin: self.current_text: %r" % (self.current_text)) debug("self.abs_start: %r, self.abs_end: %r" % (self.abs_start, self.abs_end)) for cmd in cmds: self._do_edit(cmd) + + # Update all referers # TODO: maybe in a function of its own + def _do_it(obj): + if isinstance(obj, TabStop): + obj.update_referencers() + + for c in obj._childs: + _do_it(c) + + _do_it(self) + debug("end: self.current_text: %r" % (self.current_text)) debug("self.abs_start: %r, self.abs_end: %r" % (self.abs_start, self.abs_end)) debug("self._childs: %r" % (self._childs)) @@ -559,10 +569,18 @@ class Mirror(TextObject): """ A Mirror object mirrors a TabStop that is, text is repeated here """ - def new_text(self, tb): + def new_text(self, tb): # TODO: function has a stupid name debug("new_text, self: %r" % (self)) debug("self.abs_start: %r, self.abs_end: %r, self.current_text: %r" % (self.abs_start, self.abs_end, self.current_text)) - self.initial_replace(tb) + # TODO: initial replace does not need to take an argument + old_end = self.abs_end + tb.to_vim(self.abs_start, self.abs_end) # TODO: to vim returns something unused + debug("self.abs_end: %r" % (self.abs_end)) + self._end = tb.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: + # TODO: child_end_moved is a stupid name for this function + self.child_end_moved(old_end, self.abs_end - old_end, set((self,))) def __repr__(self): return "Mirror(%s -> %s)" % (self.abs_start, self.abs_end) @@ -876,16 +894,6 @@ class TabStop(TextObject): TextObject.__init__(self, parent, token) self._no = token.no - # debug("In Referencer: %r" % (r)) - # for r in self._referencer: - # r.new_text(TextBuffer(self.current_text)) - - - def _do_edit(self, *args, **kwargs): - TextObject._do_edit(self, *args, **kwargs) - - self.update_referencers() - def update_referencers(self): for r in self._referencer: debug("r: %r" % (r)) diff --git a/plugin/UltiSnips/__init__.py b/plugin/UltiSnips/__init__.py index 4d300b6..5d8d02a 100644 --- a/plugin/UltiSnips/__init__.py +++ b/plugin/UltiSnips/__init__.py @@ -789,11 +789,9 @@ class SnippetManager(object): debug("self._lvb: %r, cb: %r" % (self._lvb, cb)) rv = edit_distance.edit_script(self._lvb, cb) debug("rv: %r" % (rv,)) - cv = edit_distance.compactify(rv) - debug("cv: %r" % (cv)) - self._csnippets[0].edited(cv) - - # debug("rv: %r" % (rv,)) + self._csnippets[0].edited(rv) + debug("## self._csnippets: %r" % (self._csnippets[0])) + debug("## self._cnsippets._childs: %r" % (self._csnippets[0]._childs)) self._lvb = as_unicode('\n'.join(vim.current.buffer)) return self._vstate.update() diff --git a/plugin/UltiSnips/edit_distance.py b/plugin/UltiSnips/edit_distance.py index 1eacaf3..a90ae4d 100755 --- a/plugin/UltiSnips/edit_distance.py +++ b/plugin/UltiSnips/edit_distance.py @@ -27,7 +27,7 @@ def edit_script(a, b): # TODO: needs some doku cost = 0 - DI_COST = 1000 # len(a)+len(b) Fix this up + DI_COST = len(a)+len(b) # Fix this up while True: while len(d[cost]): #sumarized = [ compactify(what) for c, x, line, col, what in d[cost] ] # TODO: not needed @@ -44,43 +44,45 @@ def edit_script(a, b): if a[x] == '\n': ncol = 0 nline +=1 - if seen[x+1,y+1] > cost + len(a) - x: - d[cost + len(a) - x].append((x+1,y+1, nline, ncol, what)) # TODO: slow! - seen[x+1,y+1] = cost + len(a) - x - if y < len(b): + if seen[x+1,y+1] > cost: + d[cost].append((x+1,y+1, nline, ncol, what)) # TODO: slow! + seen[x+1,y+1] = cost + + if y < len(b): # INSERT ncol = col + 1 nline = line if b[y] == '\n': ncol = 0 nline += 1 - if seen[x,y+1] > cost + DI_COST: - seen[x,y+1] = cost + DI_COST - d[cost + DI_COST].append((x,y+1, nline, ncol, what + (("I", line, col,b[y]),))) - if x < len(a): - if seen[x+1,y] > cost + DI_COST: + if (what and what[-1][0] == "I" and what[-1][1] == nline and + what[-1][2]+len(what[-1][-1]) == col and b[y] != '\n' and + seen[x,y+1] > cost + (DI_COST + x) // 2 + ): + seen[x,y+1] = cost + (DI_COST + x) // 2 + d[cost + (DI_COST + x) // 2].append((x,y+1, line, ncol, what[:-1] + (("I", what[-1][1], what[-1][2], what[-1][-1] + b[y]),) )) + elif seen[x,y+1] > cost + DI_COST + x: + seen[x,y+1] = cost + DI_COST + x + d[cost + x + DI_COST].append((x,y+1, nline, ncol, what + (("I", line, col,b[y]),))) + + if x < len(a): # DELETE + if (what and what[-1][0] == "D" and what[-1][1] == line and + what[-1][2] == col and a[x] != '\n' and + seen[x+1,y] > cost + DI_COST // 2 + ): + seen[x+1,y] = cost + DI_COST // 2 + d[cost + DI_COST // 2].append((x+1,y, line, col, what[:-1] + (("D",line, col, what[-1][-1] + a[x]),) )) + elif seen[x+1,y] > cost + DI_COST: seen[x+1,y] = cost + DI_COST d[cost + DI_COST].append((x+1,y, line, col, what + (("D",line, col, a[x]),) )) cost += 1 -def compactify(es): - cmds = [] - for cmd in es: - ctype, line, col, char = cmd - if (cmds and ctype == "D" and cmds[-1][1] == cmd[1] and cmds[-1][2] == cmd[2] and char != '\n'): - cmds[-1][-1] += char - elif (cmds and ctype == "I" and cmds[-1][1] == cmd[1] and cmds[-1][2]+1 == cmd[2] and char != '\n'): - cmds[-1][-1] += char - else: - cmds.append(list(cmd)) - return cmds - def transform(a, cmds): buf = a.split("\n") for cmd in cmds: ctype, line, col, char = cmd if ctype == "D": - buf[line] = buf[line][:col] + buf[line][col+1:] + buf[line] = buf[line][:col] + buf[line][col+len(char):] elif ctype == "I": buf[line] = buf[line][:col] + char + buf[line][col:] buf = '\n'.join(buf).split('\n') @@ -92,45 +94,94 @@ import unittest class _Base(object): def runTest(self): es = edit_script(self.a, self.b) - print "compactify(es: %r" % (compactify(es)) tr = transform(self.a, es) self.assertEqual(self.b, tr) + self.assertEqual(self.wanted, es) -# class TestEmptyString(_Base, unittest.TestCase): - # a, b = "", "" +class TestEmptyString(_Base, unittest.TestCase): + a, b = "", "" + wanted = () -# class TestAllMatch(_Base, unittest.TestCase): - # a, b = "abcdef", "abcdef" +class TestAllMatch(_Base, unittest.TestCase): + a, b = "abcdef", "abcdef" + wanted = () -# class TestLotsaNewlines(_Base, unittest.TestCase): - # a, b = "Hello", "Hello\nWorld\nWorld\nWorld" +class TestLotsaNewlines(_Base, unittest.TestCase): + a, b = "Hello", "Hello\nWorld\nWorld\nWorld" + wanted = ( + ("I", 0, 5, "\n"), + ("I", 1, 0, "World"), + ("I", 1, 5, "\n"), + ("I", 2, 0, "World"), + ("I", 2, 5, "\n"), + ("I", 3, 0, "World"), + ) -# class TestCrash(_Base, unittest.TestCase): - # a = 'hallo Blah mitte=sdfdsfsd\nhallo kjsdhfjksdhfkjhsdfkh mittekjshdkfhkhsdfdsf' - # b = 'hallo Blah mitte=sdfdsfsd\nhallo b mittekjshdkfhkhsdfdsf' +class TestCrash(_Base, unittest.TestCase): + a = 'hallo Blah mitte=sdfdsfsd\nhallo kjsdhfjksdhfkjhsdfkh mittekjshdkfhkhsdfdsf' + b = 'hallo Blah mitte=sdfdsfsd\nhallo b mittekjshdkfhkhsdfdsf' + wanted = ( + ("I", 1, 6, "b"), + ("D", 1, 7, "kjsdhfjksdhfkjhsdfkh"), + ) -# class TestRealLife(_Base, unittest.TestCase): - # a = 'hallo End Beginning' - # b = 'hallo End t' +class TestRealLife(_Base, unittest.TestCase): + a = 'hallo End Beginning' + b = 'hallo End t' + wanted = ( + ("I", 0, 10, "t"), + ("D", 0, 11, "Beginning"), + ) class TestRealLife1(_Base, unittest.TestCase): a = 'Vorne hallo Hinten' b = 'Vorne hallo Hinten' - # def test_all_match(self): - # rv = edit_script("abcdef", "abcdef") - # self.assertEqual("MMMMMM", rv) + wanted = ( + ("I", 0, 11, " "), + ) - # def test_no_substr(self): - # rv = edit_script("abc", "def") - # self.assertEqual("SSS", rv) +class TestCheapDelete(_Base, unittest.TestCase): + a = 'Vorne hallo Hinten' + b = 'Vorne Hinten' + wanted = ( + ("D", 0, 5, " hallo"), + ) - # def test_paper_example(self): - # rv = edit_script("abcabba","cbabac") - # self.assertEqual(rv, "SMDMMDMI") +class TestNoSubstring(_Base, unittest.TestCase): + a,b = "abc", "def" + wanted = ( + ("I", 0, 0, "def"), + ("D", 0, 3, "abc"), + ) +# TODO: quote the correct paper +# +class TestPaperExample(_Base, unittest.TestCase): + a,b = "abcabba", "cbabac" + wanted = ( + ("I", 0, 0, "cb"), + ("I", 0, 4, "a"), + ("D", 0, 6, "abba"), + ) + +class TestSKienaExample(_Base, unittest.TestCase): + a, b = "thou shalt not", "you should not" + wanted = ( + ('I', 0, 0, 'y'), + ('D', 0, 1, 'th'), + ('I', 0, 6, 'ou'), + ('D', 0, 8, 'a'), + ('I', 0, 9, 'd'), + ('D', 0, 10, 't'), + ) + +class TestUltiSnipsProblem(_Base, unittest.TestCase): + a = "this is it this is it this is it" + b = "this is it a this is it" + wanted = ( + ("I", 0, 11, "a"), + ("D", 0, 12, "this is it") + ) - # def test_skiena_example(self): - # rv = edit_script("thou shalt not", "you should not") - # self.assertEqual(rv, "DSMMMMMISMSMMMM") if __name__ == '__main__': unittest.main() # k = TestEditScript()