diff --git a/editscript/edit_script.py b/editscript/edit_script.py deleted file mode 100755 index febf257..0000000 --- a/editscript/edit_script.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -import heapq # TODO: overkill. Bucketing is better -from collections import defaultdict - -class GridPoint(object): - """Docstring for GridPoint """ - - __slots__ = ("parent", "cost",) - - def __init__(self, parent, cost): - """@todo: to be defined - - :parent: @todo - :cost: @todo - """ - self._parent = parent - self._cost = cost - -def edit_script(a, b): - - heap = [ (0,0,0,"") ] - - while True: - cost, y, x,what = heapq.heappop(heap) - - if x == len(a) and y == len(b): - return what - - if x < len(a) and y < len(b) and a[x] == b[y]: - heapq.heappush(heap, (cost, y+1,x+1, what + "M")) - else: - if x < len(a) and y < len(b): - heapq.heappush(heap, (cost + 1, y+1, x+1, what + "S")) - if x < len(a): - heapq.heappush(heap, (cost + 1, y, x+1, what + "D")) - if y < len(b): - heapq.heappush(heap, (cost + 1, y+1, x, what + "I")) - - -import unittest - -class TestEditScript(unittest.TestCase): - def test_empty_string(self): - rv = edit_script("","") - self.assertEqual(rv, "") - - def test_all_match(self): - rv = edit_script("abcdef", "abcdef") - self.assertEqual("MMMMMM", rv) - - def test_no_substr(self): - rv = edit_script("abc", "def") - self.assertEqual("SSS", rv) - - def test_paper_example(self): - rv = edit_script("abcabba","cbabac") - self.assertEqual(rv, "SMDMMDMI") - - 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() - # unittest.TextTestRunner().run(k) - - - diff --git a/plugin/UltiSnips.vim b/plugin/UltiSnips.vim index 66faba8..d8b3861 100644 --- a/plugin/UltiSnips.vim +++ b/plugin/UltiSnips.vim @@ -200,8 +200,8 @@ exec g:_uspy "UltiSnips_Manager.forward_trigger = vim.eval('g:UltiSnipsJumpForwa exec g:_uspy "UltiSnips_Manager.backward_trigger = vim.eval('g:UltiSnipsJumpBackwardTrigger')" au CursorMovedI * call UltiSnips_CursorMoved() -au InsertEnter * call UltiSnips_EnteredInsertMode() -au WinLeave * call UltiSnips_LeavingWindow() +"au InsertEnter * call UltiSnips_EnteredInsertMode() +"au WinLeave * call UltiSnips_LeavingWindow() call UltiSnips_MapKeys() diff --git a/plugin/UltiSnips/__init__.py b/plugin/UltiSnips/__init__.py index 6e4ded5..8dfd3f5 100644 --- a/plugin/UltiSnips/__init__.py +++ b/plugin/UltiSnips/__init__.py @@ -1,6 +1,9 @@ #!/usr/bin/env python # encoding: utf-8 +import edit_distance +from debug import debug + from functools import wraps import glob import hashlib @@ -650,6 +653,7 @@ class SnippetManager(object): @err_to_scratch_buffer def reset(self, test_error=False): + self._lvb = "" self._test_error = test_error self._snippets = {} self._visual_content = as_unicode("") @@ -795,6 +799,11 @@ class SnippetManager(object): @err_to_scratch_buffer def cursor_moved(self): + cb = as_unicode('\n'.join(vim.current.buffer)) + rv = edit_distance.edit_script(self._lvb, cb) + # debug("rv: %r" % (rv,)) + self._lvb = cb + return self._vstate.update() if not self._vstate.buf_changed and not self._expect_move_wo_change: diff --git a/plugin/UltiSnips/edit_distance.py b/plugin/UltiSnips/edit_distance.py new file mode 100755 index 0000000..1455eaa --- /dev/null +++ b/plugin/UltiSnips/edit_distance.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import heapq # TODO: overkill. Bucketing is better +from collections import defaultdict + +class GridPoint(object): + """Docstring for GridPoint """ + + __slots__ = ("parent", "cost",) + + def __init__(self, parent, cost): + """@todo: to be defined + + :parent: @todo + :cost: @todo + """ + self._parent = parent + self._cost = cost + +def edit_script(a, b): + d = defaultdict(list) + + d[0] = [ (0,0,0,0, ()) ] + + cost = 0 + while True: + while len(d[cost]): + y, x, nline, ncol, what = d[cost].pop() + + if x == len(a) and y == len(b): + return what + + if x < len(a) and y < len(b) and a[x] == b[y]: + ncol += 1 + if a[x] == '\n': + ncol = 0 + nline += 1 + d[cost].append((y+1,x+1, nline, ncol, what)) + else: + if x < len(a): + d[cost + 1].append((y,x+1, nline, ncol, what + (("D",nline, ncol),) )) + if y < len(b): + oline, ocol = nline, ncol + ncol += 1 + if b[y] == '\n': + ncol = 0 + nline += 1 + d[cost + 1].append((y+1,x, nline, ncol, what + (("I", oline, ocol,b[y]),))) + cost += 1 + +def transform(a, cmds): + buf = a.split("\n") + + for cmd in cmds: + if cmd[0] == "D": + line, col = cmd[1:] + buf[line] = buf[line][:col] + buf[line][col+1:] + elif cmd[0] == "I": + line, col, char = cmd[1:] + buf[line] = buf[line][:col] + char + buf[line][col:] + buf = '\n'.join(buf).split('\n') + return '\n'.join(buf) + + +import unittest + +class _Base(object): + def runTest(self): + es = edit_script(self.a, self.b) + tr = transform(self.a, es) + self.assertEqual(self.b, tr) + +class TestEmptyString(_Base, unittest.TestCase): + a, b = "", "" + +class TestAllMatch(_Base, unittest.TestCase): + a, b = "abcdef", "abcdef" + +class TestLotsaNewlines(_Base, unittest.TestCase): + a, b = "Hello", "Hello\nWorld\nWorld\nWorld" + + # def test_all_match(self): + # rv = edit_script("abcdef", "abcdef") + # self.assertEqual("MMMMMM", rv) + + # def test_no_substr(self): + # rv = edit_script("abc", "def") + # self.assertEqual("SSS", rv) + + # def test_paper_example(self): + # rv = edit_script("abcabba","cbabac") + # self.assertEqual(rv, "SMDMMDMI") + + # 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() + # unittest.TextTestRunner().run(k) + + +