From f2ce576fbdccbf46b6fe7e63a211e735c7d5dd5d Mon Sep 17 00:00:00 2001 From: Holger Rapp Date: Fri, 27 Jan 2012 22:48:36 +0100 Subject: [PATCH] Fixed various smaller bugs I encountered --- plugin/UltiSnips/__init__.py | 24 +++++++++---------- plugin/UltiSnips/_diff.py | 6 +++++ plugin/UltiSnips/text_objects/_base.py | 23 +++++++++++++----- .../text_objects/_snippet_instance.py | 8 ++++--- test.py | 20 ++++++++++++++-- 5 files changed, 58 insertions(+), 23 deletions(-) diff --git a/plugin/UltiSnips/__init__.py b/plugin/UltiSnips/__init__.py index d70cd50..7292a01 100644 --- a/plugin/UltiSnips/__init__.py +++ b/plugin/UltiSnips/__init__.py @@ -603,25 +603,24 @@ class SnippetManager(object): debug("lt: %r" % (lt)) debug("ct: %r" % (ct)) + debug("self._lpos: %r, pos: %r" % (self._lpos, pos)) # Cut down on lines searched for changes. Start from behind and # remove all equal lines. Then do the same from the front. - while (lt[lt_span[1]-1] == ct[ct_span[1]-1] and - self._lpos.line < lt_span[1] and pos.line < ct_span[1] and - (lt_span[0] < lt_span[1]) and - (ct_span[0] < ct_span[1])): - ct_span[1] -= 1 - lt_span[1] -= 1 - debug("1 lt_span: %r, ct_span: %r" % (lt_span ,ct_span)) - try: - while (lt[lt_span[0]] == ct[ct_span[0]] and - self._lpos.line <= lt_span[0] and pos.line <= ct_span[0] and + if lt and ct: + while (lt[lt_span[1]-1] == ct[ct_span[1]-1] and + self._lpos.line < initial_line + lt_span[1]-1 and pos.line < initial_line + ct_span[1]-1 and (lt_span[0] < lt_span[1]) and (ct_span[0] < ct_span[1])): + ct_span[1] -= 1 + lt_span[1] -= 1 + debug("1 lt_span: %r, ct_span: %r" % (lt_span ,ct_span)) + while (lt_span[0] < lt_span[1] and + ct_span[0] < ct_span[1] and + lt[lt_span[0]] == ct[ct_span[0]] and + self._lpos.line >= initial_line and pos.line >= initial_line): ct_span[0] += 1 lt_span[0] += 1 initial_line += 1 - except IndexError: - pass debug("2 lt_span: %r, ct_span: %r" % (lt_span ,ct_span)) ct_span[0] = max(0, ct_span[0] - 1) lt_span[0] = max(0, lt_span[0] - 1) @@ -656,6 +655,7 @@ class SnippetManager(object): snippets must be properly terminated """ while len(self._csnippets): + debug("*** Current snippet is done ***") self._current_snippet_is_done() self._reinit() diff --git a/plugin/UltiSnips/_diff.py b/plugin/UltiSnips/_diff.py index d1448f6..1a1410d 100644 --- a/plugin/UltiSnips/_diff.py +++ b/plugin/UltiSnips/_diff.py @@ -27,6 +27,12 @@ def guess_edit(initial_line, lt, ct, ppos, pos): movements like insertion, deletion of a line or carriage return. """ if not len(lt) and not len(ct): return True, () + if len(lt) and not ct: + es = [] + for i in lt: + es.append(("D", pos.line, pos.col, lt)) + es.append(("D", pos.line, pos.col, "\n")) + if is_complete_edit(initial_line, lt, ct, es): return True, es if pos.line == ppos.line: # Movement only in one line llen = len(lt[ppos.line - initial_line]) clen = len(ct[pos.line - initial_line]) diff --git a/plugin/UltiSnips/text_objects/_base.py b/plugin/UltiSnips/text_objects/_base.py index 114a884..948d026 100755 --- a/plugin/UltiSnips/text_objects/_base.py +++ b/plugin/UltiSnips/text_objects/_base.py @@ -39,6 +39,7 @@ class TextObject(object): # We explicitly do not want to move our childs around here as we # either have non or we are replacing text initially which means we do # not want to mess with their positions + if self.current_text == gtext: return old_end = self._end self._end = _vim.text_to_vim( self._start, self._end, gtext or self._initial_text) @@ -133,23 +134,32 @@ class EditableTextObject(TextObject): if ctype == "I": # Insertion if c._start < pos < Position(c._end.line, c._end.col) and isinstance(c, NoneditableTextObject): to_kill.add(c) + new_cmds.add(cmd) + break elif (c._start <= pos <= c._end) and isinstance(c, EditableTextObject): c._do_edit(cmd) return else: # Deletion - delend = pos + Position(0, len(text)) if text != "\n"\ + delend = pos + Position(0, len(text)) if text != "\n" \ else Position(line + 1, 0) if (c._start <= pos < c._end) and (c._start < delend <= c._end): + debug("Case 1") # this edit command is completely for the child if isinstance(c, NoneditableTextObject): to_kill.add(c) - continue - c._do_edit(cmd) - return + new_cmds.append(cmd) + break + else: + c._do_edit(cmd) + return elif (pos < c._start and c._end <= delend) or (pos <= c._start and c._end < delend): + debug("Case 2") # Case: this deletion removes the child to_kill.add(c) + new_cmds.append(cmd) + break elif (pos < c._start and (c._start < delend <= c._end)): + debug("Case 3") # Case: partially for us, partially for the child my_text = text[:(c._start-pos).col] c_text = text[(c._start-pos).col:] @@ -157,6 +167,7 @@ class EditableTextObject(TextObject): new_cmds.append((ctype, line, col, c_text)) break elif (delend >= c._end and (c._start <= pos < c._end)): + debug("Case 4") # Case: partially for us, partially for the child c_text = text[(c._end-pos).col:] my_text = text[:(c._end-pos).col] @@ -238,7 +249,7 @@ class EditableTextObject(TextObject): break i -= 1 - c = [ c._get_prev_tab(no) for c in self._childs ] + c = [ c._get_prev_tab(no) for c in self._editable_childs ] c = filter(lambda i: i, c) possible_sol += c @@ -251,7 +262,7 @@ class EditableTextObject(TextObject): def _get_tabstop(self, requester, no): if no in self._tabstops: return self._tabstops[no] - for c in self._childs: + for c in self._editable_childs: if c is requester: continue diff --git a/plugin/UltiSnips/text_objects/_snippet_instance.py b/plugin/UltiSnips/text_objects/_snippet_instance.py index b50f17d..d7e5a8c 100755 --- a/plugin/UltiSnips/text_objects/_snippet_instance.py +++ b/plugin/UltiSnips/text_objects/_snippet_instance.py @@ -48,17 +48,17 @@ class SnippetInstance(EditableTextObject): def replay_user_edits(self, cmds): """Replay the edits the user has done to keep endings of our Text objects in sync with reality""" - debug("---- BEFORE") + debug("---- BEGIN USER EDITS") echo_to_hierarchy(self) for cmd in cmds: self._do_edit(cmd) echo_to_hierarchy(self) - debug("---- AFTER") def update_textobjects(self): """Update the text objects that should change automagically after the users edits have been replayed. This might also move the Cursor """ + debug("---- BEGIN UPDATE TEXTOBJECTS") vc = _VimCursor(self) done = set() @@ -77,10 +77,12 @@ class SnippetInstance(EditableTextObject): done.add(obj) counter -= 1 if counter == 0: - raise RuntimeError("Cyclic dependency in TextElements!") + raise RuntimeError("Cyclic dependency in Snippet definition!") vc.to_vim() self._del_child(vc) + debug("--- ALL DONE") + echo_to_hierarchy(self) def select_next_tab(self, backwards = False): if self._cts is None: diff --git a/test.py b/test.py index a7fdfb5..dbcbaae 100755 --- a/test.py +++ b/test.py @@ -25,8 +25,6 @@ # and will compare the resulting output to expected results. # # -# TODO: more edits that cross boundaries between text objects -# TODO: delete hallo snippet -> hallo '' and then delete snippet # TODO: remove formatoption tests # TODO: python3 tests import os @@ -1156,6 +1154,14 @@ class PythonCode_LongerTextThanSource_MultiLine(_VimTest): keys = """test""" + EX + JF + "ups" wanted = "hi" + 100*"a" + 100*"\n" + 100*"a" + "endups" +class PythonCode_AccessKilledTabstop_OverwriteSecond(_VimTest): + snippets = ("test", r"`!p snip.rv = t[2].upper()`${1:h${2:welt}o}`!p snip.rv = t[2].upper()`") + keys = "test" + EX + JF + "okay" + wanted = "OKAYhokayoOKAY" +class PythonCode_AccessKilledTabstop_OverwriteFirst(_VimTest): + snippets = ("test", r"`!p snip.rv = t[2].upper()`${1:h${2:welt}o}`!p snip.rv = t[2].upper()`") + keys = "test" + EX + "aaa" + wanted = "aaa" # End: New Implementation #}}} # End: PythonCode Interpolation #}}} @@ -2497,6 +2503,16 @@ class Undo_RemoveEditInTabstop(_VimTest): snippets = ("test", "$1 Hello\naaa ${1} bbb\nWorld") keys = "hello test" + EX + "upsi" + ESC + "hh" + "iabcdef" + ESC + "u" wanted = "hello upsi Hello\naaa upsi bbb\nWorld" +class Undo_RemoveWholeSnippet(_VimTest): + snippets = ("test", "Hello\n${1:Hello}World") + keys = "first line\n\n\n\n\n\nthird line" + \ + ESC + "3k0itest" + EX + ESC + "uiupsy" + wanted = "first line\n\n\nupsy\n\n\nthird line" +class JumpForward_DefSnippet(_VimTest): + snippets = ("test", "${1}\n`!p snip.rv = '\\n'.join(t[1].split())`\n\n${0:pass}") + keys = "test" + EX + "a b c" + JF + "shallnot" + JF + "end" + wanted = "a b c\na\nb\nc\n\nshallnotend" + # End: Undo of Snippet insertion #}}} # Tab Completion of Words {{{# class Completion_SimpleExample_ECR(_VimTest):