From b057d6332eb4af33646ffca3bf0bb5f1358d8bb3 Mon Sep 17 00:00:00 2001 From: Holger Rapp Date: Tue, 17 Jan 2012 13:48:01 +0100 Subject: [PATCH] More mirror tests --- plugin/UltiSnips/TextObjects.py | 67 ++++++++++++---------- plugin/UltiSnips/edit_distance.py | 50 +++++++++++------ test.py | 93 ++++++++++++++++--------------- 3 files changed, 116 insertions(+), 94 deletions(-) diff --git a/plugin/UltiSnips/TextObjects.py b/plugin/UltiSnips/TextObjects.py index 8fc1ef3..0dd9a43 100644 --- a/plugin/UltiSnips/TextObjects.py +++ b/plugin/UltiSnips/TextObjects.py @@ -152,8 +152,7 @@ class _TOParser(object): seen_ts[token.no] = ts parent._add_tabstop(ts) else: - m = Mirror(parent, token) - seen_ts[token.no].add_referencer(m) + Mirror(parent, seen_ts[token.no], token) def _create_objects_with_links_to_tabs(self, all_tokens, seen_ts): for parent, token in all_tokens: @@ -163,17 +162,22 @@ class _TOParser(object): Transformation(parent, seen_ts[token.no], token) def _replace_initital_texts(self, seen_ts): - def _do_it(obj): - debug("In _do_it: obj: %r" % (obj)) + def _place_initial_text(obj): + debug("In _place_initial_text: obj: %r" % (obj)) obj.initial_replace() for c in obj._childs: # TODO: private parts! - _do_it(c) + _place_initial_text(c) - _do_it(self._parent_to) + _place_initial_text(self._parent_to) - for ts in seen_ts.values(): - ts.update_referencers() + def _update_non_tabstops(obj): # TODO: Stupid function name + obj._really_updateman() + + for c in obj._childs: + _update_non_tabstops(c) + + _update_non_tabstops(self._parent_to) def _do_parse(self, all_tokens, seen_ts): tokens = list(tokenize(self._text, self._indent)) @@ -364,7 +368,7 @@ class TextObject(object): 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): + if (pos < abs_start and end_pos >= abs_end): debug("Case 1") to_kill.add(c) # Case: this edit command is completely for the child @@ -443,14 +447,13 @@ class TextObject(object): vc = VimCursor(self) assert(len([c for c in self._childs if isinstance(c, VimCursor)]) == 1) # Update all referers # TODO: maybe in a function of its own - def _do_it(obj): - if isinstance(obj, TabStop): - obj.update_referencers() + def _update_non_tabstops(obj): # TODO: stupid functon name + obj._really_updateman() for c in obj._childs: - _do_it(c) + _update_non_tabstops(c) - _do_it(self) + _update_non_tabstops(self) #debug("self._childs: %r, vc: %r" % (self._childs, vc)) vc.update_position() @@ -491,6 +494,7 @@ class TextObject(object): # return new_end def _get_next_tab(self, no): + debug("_get_next_tab: self: %r, no: %r" % (self, no)) if not len(self._tabstops.keys()): return tno_max = max(self._tabstops.keys()) @@ -540,7 +544,7 @@ class TextObject(object): ############################### # Private/Protected functions # ############################### - def _do_update(self): + def _really_updateman(self): # TODO: pass # def _move_textobjects_behind(self, start, end, lines, cols, obj_idx): @@ -632,10 +636,21 @@ class Mirror(TextObject): """ A Mirror object mirrors a TabStop that is, text is repeated here """ - def new_text(self, tb): # TODO: function has a stupid name - if self._is_killed: - return + def __init__(self, parent, tabstop, token): + TextObject.__init__(self, parent, token) + self._ts = tabstop + + def _really_updateman(self): # TODO: function has a stupid name + # TODO: this function will get called to often. It should + # check if a replacement is really needed + assert(not self._is_killed) + + if self._ts._is_killed: + tb = TextBuffer("") + else: + + tb = TextBuffer(self._ts.current_text) 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)) # TODO: initial replace does not need to take an argument @@ -648,6 +663,9 @@ class Mirror(TextObject): # TODO: child_end_moved is a stupid name for this function self.child_end_moved(old_end, self.abs_end - old_end, set((self,))) + if self._ts._is_killed: + self._parent._del_child(self) + def __repr__(self): return "Mirror(%s -> %s)" % (self.abs_start, self.abs_end) @@ -951,8 +969,6 @@ class TabStop(TextObject): comes to rest when the user taps through the Snippet. """ def __init__(self, parent, token, start = None, end = None): - self._referencer = [] - if start is not None: self._no = token TextObject.__init__(self, parent, start, end) @@ -960,16 +976,6 @@ class TabStop(TextObject): TextObject.__init__(self, parent, token) self._no = token.no - def update_referencers(self): - for r in self._referencer: - debug("r: %r" % (r)) - debug("self.current_text: %r" % (self.current_text)) - r.new_text(TextBuffer(self.current_text)) - - def add_referencer(self, r): - self._referencer.append(r) - self._referencer.sort() - def no(self): return self._no no = property(no) @@ -1015,6 +1021,7 @@ class SnippetInstance(TextObject): return rv def select_next_tab(self, backwards = False): + debug("select_next_tab: self: %r, self._cts: %r" % (self, self._cts)) if self._cts is None: return diff --git a/plugin/UltiSnips/edit_distance.py b/plugin/UltiSnips/edit_distance.py index fe61097..42b85b9 100755 --- a/plugin/UltiSnips/edit_distance.py +++ b/plugin/UltiSnips/edit_distance.py @@ -5,6 +5,8 @@ import heapq # TODO: overkill. Bucketing is better from collections import defaultdict import sys +# TODO: check test cases here. They are not up to date + def edit_script(a, b, sline = 0, scol = 0): d = defaultdict(list) seen = defaultdict(lambda: sys.maxint) @@ -13,7 +15,8 @@ def edit_script(a, b, sline = 0, scol = 0): # TODO: needs some doku cost = 0 - DI_COST = len(a)+len(b) + D_COST = len(a)+len(b) + I_COST = len(a)+len(b) while True: while len(d[cost]): #sumarized = [ compactify(what) for c, x, line, col, what in d[cost] ] # TODO: not needed @@ -30,9 +33,14 @@ def edit_script(a, b, sline = 0, scol = 0): if a[x] == '\n': ncol = 0 nline +=1 - if seen[x+1,y+1] > cost + 1: - d[cost+1].append((x+1,y+1, nline, ncol, what)) # TODO: slow! - seen[x+1,y+1] = cost + 1 + lcost = cost + 1 + if (what and what[-1][0] == "D" and what[-1][1] == line and + what[-1][2] == col and a[x] != '\n'): + # Matching directly after a deletion should be as costly as DELETE + INSERT + a bit + lcost = (D_COST + I_COST)*1.5 + if seen[x+1,y+1] > lcost: + d[lcost].append((x+1,y+1, nline, ncol, what)) # TODO: slow! + seen[x+1,y+1] = lcost if y < len(b): # INSERT ncol = col + 1 @@ -42,24 +50,24 @@ def edit_script(a, b, sline = 0, scol = 0): nline += 1 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 + ncol) // 2 + seen[x,y+1] > cost + (I_COST + ncol) // 2 ): - seen[x,y+1] = cost + (DI_COST + ncol) // 2 - d[cost + (DI_COST + ncol) // 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 + ncol: - seen[x,y+1] = cost + DI_COST + ncol - d[cost + ncol + DI_COST].append((x,y+1, nline, ncol, what + (("I", line, col,b[y]),))) + seen[x,y+1] = cost + (I_COST + ncol) // 2 + d[cost + (I_COST + ncol) // 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 + I_COST + ncol: + seen[x,y+1] = cost + I_COST + ncol + d[cost + ncol + I_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 + D_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]),) )) + seen[x+1,y] = cost + D_COST // 2 + d[cost + D_COST // 2].append((x+1,y, line, col, what[:-1] + (("D",line, col, what[-1][-1] + a[x]),) )) + elif seen[x+1,y] > cost + D_COST: + seen[x+1,y] = cost + D_COST + d[cost + D_COST].append((x+1,y, line, col, what + (("D",line, col, a[x]),) )) cost += 1 def transform(a, cmds): @@ -150,6 +158,13 @@ class TestPaperExample(_Base, unittest.TestCase): ("I", 0, 5, "c"), ) +class TestCommonCharacters(_Base, unittest.TestCase): + a,b = "hasomelongertextbl", "hol" + wanted = ( + ("D", 0, 1, "asomelongertextb"), + ("I", 0, 1, "o"), + ) + class TestSKienaExample(_Base, unittest.TestCase): a, b = "thou shalt not", "you should not" wanted = ( @@ -173,8 +188,7 @@ class MatchIsTooCheap(_Base, unittest.TestCase): a = "stdin.h" b = "s" wanted = ( - ("D", 0, 0, "stdin.h"), - ("I", 0, 0, "s"), + ("D", 0, 1, "tdin.h"), ) if __name__ == '__main__': diff --git a/test.py b/test.py index 46baf77..e47fb8e 100755 --- a/test.py +++ b/test.py @@ -735,52 +735,53 @@ class TabStop_TSInDefaultText_ZeroLengthNested_OverwriteSecondJumpBackAndForward wanted = """halongertextblEnd""" # 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" -## wanted = "hi this Hallo Ende" -##class TabStop_TSInDefaultNested_OverwriteOneJumpToThird(_VimTest): -## snippets = ("test", "hi ${1:this ${2:second ${3:third}}} $4") -## keys = "test" + EX + JF + JF + "Hallo" + JF + "Ende" -## wanted = "hi this second Hallo Ende" -##class TabStop_TSInDefaultNested_OverwriteOneJumpAround(_VimTest): -## snippets = ("test", "hi ${1:this ${2:second ${3:third}}} $4") -## keys = "test" + EX + JF + JF + "Hallo" + JB+JB + "Blah" + JF + "Ende" -## wanted = "hi Blah Ende" -## -##class TabStop_TSInDefault_MirrorsOutside_DoNothing(_VimTest): -## snippets = ("test", "hi ${1:this ${2:second}} $2") -## keys = "test" + EX -## wanted = "hi this second second" -##class TabStop_TSInDefault_MirrorsOutside_OverwriteSecond(_VimTest): -## snippets = ("test", "hi ${1:this ${2:second}} $2") -## keys = "test" + EX + JF + "Hallo" -## wanted = "hi this Hallo Hallo" -##class TabStop_TSInDefault_MirrorsOutside_Overwrite(_VimTest): -## snippets = ("test", "hi ${1:this ${2:second}} $2") -## keys = "test" + EX + "Hallo" -## wanted = "hi Hallo " -##class TabStop_TSInDefault_MirrorsOutside_Overwrite1(_VimTest): -## snippets = ("test", "$1: ${1:'${2:second}'} $2") -## keys = "test" + EX + "Hallo" -## wanted = "Hallo: Hallo " -##class TabStop_TSInDefault_MirrorsOutside_OverwriteSecond1(_VimTest): -## snippets = ("test", "$1: ${1:'${2:second}'} $2") -## keys = "test" + EX + JF + "Hallo" -## wanted = "'Hallo': 'Hallo' Hallo" -##class TabStop_TSInDefault_MirrorsOutside_OverwriteFirstSwitchNumbers(_VimTest): -## snippets = ("test", "$2: ${2:'${1:second}'} $1") -## keys = "test" + EX + "Hallo" -## wanted = "'Hallo': 'Hallo' Hallo" -##class TabStop_TSInDefault_MirrorsOutside_OverwriteFirst_RLExample(_VimTest): -## snippets = ("test", """`!p snip.rv = t[1].split('/')[-1].lower().strip("'")` = require(${1:'${2:sys}'})""") -## keys = "test" + EX + "WORLD" + JF + "End" -## wanted = "world = require(WORLD)End" -##class TabStop_TSInDefault_MirrorsOutside_OverwriteSecond_RLExample(_VimTest): -## snippets = ("test", """`!p snip.rv = t[1].split('/')[-1].lower().strip("'")` = require(${1:'${2:sys}'})""") -## keys = "test" + EX + JF + "WORLD" + JF + "End" -## wanted = "world = require('WORLD')End" -## +class TabStop_TSInDefaultNested_OverwriteOneJumpBackToOther(_VimTest): + snippets = ("test", "hi ${1:this ${2:second ${3:third}}} $4") + keys = "test" + EX + JF + "Hallo" + JF + "Ende" + wanted = "hi this Hallo Ende" +class TabStop_TSInDefaultNested_OverwriteOneJumpToThird(_VimTest): + snippets = ("test", "hi ${1:this ${2:second ${3:third}}} $4") + keys = "test" + EX + JF + JF + "Hallo" + JF + "Ende" + wanted = "hi this second Hallo Ende" +class TabStop_TSInDefaultNested_OverwriteOneJumpAround(_VimTest): + snippets = ("test", "hi ${1:this ${2:second ${3:third}}} $4") + keys = "test" + EX + JF + JF + "Hallo" + JB+JB + "Blah" + JF + "Ende" + wanted = "hi Blah Ende" + +class TabStop_TSInDefault_MirrorsOutside_DoNothing(_VimTest): + snippets = ("test", "hi ${1:this ${2:second}} $2") + keys = "test" + EX + wanted = "hi this second second" +class TabStop_TSInDefault_MirrorsOutside_OverwriteSecond(_VimTest): + snippets = ("test", "hi ${1:this ${2:second}} $2") + keys = "test" + EX + JF + "Hallo" + wanted = "hi this Hallo Hallo" +class TabStop_TSInDefault_MirrorsOutside_Overwrite0(_VimTest): + snippets = ("test", "hi ${1:this ${2:second}} $2") + keys = "test" + EX + "Hallo" + wanted = "hi Hallo " +class TabStop_TSInDefault_MirrorsOutside_Overwrite1(_VimTest): + snippets = ("test", "$1: ${1:'${2:second}'} $2") + keys = "test" + EX + "Hallo" + wanted = "Hallo: Hallo " +class TabStop_TSInDefault_MirrorsOutside_OverwriteSecond1(_VimTest): + snippets = ("test", "$1: ${1:'${2:second}'} $2") + keys = "test" + EX + JF + "Hallo" + wanted = "'Hallo': 'Hallo' Hallo" +class TabStop_TSInDefault_MirrorsOutside_OverwriteFirstSwitchNumbers(_VimTest): + snippets = ("test", "$2: ${2:'${1:second}'} $1") + keys = "test" + EX + "Hallo" + wanted = "'Hallo': 'Hallo' Hallo" +# TODO: these tests have python in them +# class TabStop_TSInDefault_MirrorsOutside_OverwriteFirst_RLExample(_VimTest): + # snippets = ("test", """`!p snip.rv = t[1].split('/')[-1].lower().strip("'")` = require(${1:'${2:sys}'})""") + # keys = "test" + EX + "WORLD" + JF + "End" + # wanted = "world = require(WORLD)End" +# class TabStop_TSInDefault_MirrorsOutside_OverwriteSecond_RLExample(_VimTest): + # snippets = ("test", """`!p snip.rv = t[1].split('/')[-1].lower().strip("'")` = require(${1:'${2:sys}'})""") + # keys = "test" + EX + JF + "WORLD" + JF + "End" + # wanted = "world = require('WORLD')End" + ##class TabStop_Multiline_Leave(_VimTest): ## snippets = ("test", "hi ${1:first line\nsecond line} world" ) ## keys = "test" + EX