diff --git a/pythonx/UltiSnips/_vim.py b/pythonx/UltiSnips/_vim.py index 579de1d..f71b2f8 100644 --- a/pythonx/UltiSnips/_vim.py +++ b/pythonx/UltiSnips/_vim.py @@ -108,74 +108,42 @@ def new_scratch_buffer(text): feedkeys(r"\") +def virtual_position(line, col): + """Runs the position through virtcol() and returns the result.""" + nbytes = col2byte(line, col) + return line, int(eval('virtcol([%d, %d])' % (line, nbytes))) + def select(start, end): """Select the span in Select mode""" - _unmap_select_mode_mapping() - delta = end - start - lineno, col = start.line, start.col - - col = col2byte(lineno + 1, col) - vim.current.window.cursor = lineno + 1, col + col = col2byte(start.line + 1, start.col) + vim.current.window.cursor = start.line + 1, col move_cmd = "" if eval("mode()") != 'n': move_cmd += r"\" - # Case 1: Zero Length Tabstops - if delta.line == delta.col == 0: + if start == end: + # Zero Length Tabstops, use 'i' or 'a'. if col == 0 or eval("mode()") not in 'i' and \ - col < len(buf[lineno]): + col < len(buf[start.line]): move_cmd += "i" else: move_cmd += "a" else: - # Case 2a: Non zero length - # If a tabstop immediately starts with a newline, the selection must - # start after the last character in the current line. But if we are in - # insert mode and out of it, we cannot go past the last character - # with move_one_right and therefore cannot visual-select this newline. - # We have to hack around this by adding an extra space which we can - # select. Note that this problem could be circumvent by selecting the - # tab backwards (that is starting at the end); one would not need to - # modify the line for this. This creates other trouble though - if col >= len(buf[lineno]): - buf[lineno] += " " - - if delta.line: - move_lines = "%ij" % delta.line + # Non zero length, use Visual selection. + move_cmd += "v" + if "inclusive" in eval("&selection"): + if end.col == 0: + move_cmd += "%iG$" % end.line + else: + move_cmd += "%iG%i|" % virtual_position(end.line + 1, end.col) else: - move_lines = "" - # Depending on the current mode and position, we - # might need to move escape out of the mode and this - # will move our cursor one left - if col != 0 and eval("mode()") == 'i': - move_one_right = "l" - else: - move_one_right = "" - - # After moving to the correct line, we go back to column 0 - # and select right from there. Note that the we have to select - # one column less since Vim's visual selection is including the - # ending while Python slicing is excluding the ending. - inclusive = "inclusive" in eval("&selection") - if end.col == 0: - # Selecting should end at beginning of line -> Select the - # previous line till its end - do_select = "k$" - if not inclusive: - do_select += "j0" - elif end.col > 1: - do_select = "0%il" % (end.col-1 if inclusive else end.col) - else: - do_select = "0" if inclusive else "0l" - - move_cmd += _LangMapTranslator().translate( - r"%sv%s%s\" % (move_one_right, move_lines, do_select) - ) - - feedkeys(move_cmd) + move_cmd += "%iG%i|" % virtual_position(end.line + 1, end.col + 1) + move_cmd += "o%iG%i|o\\" % virtual_position( + start.line + 1, start.col + 1) + feedkeys(_LangMapTranslator().translate(move_cmd)) def _unmap_select_mode_mapping(): """This function unmaps select mode mappings if so wished by the user. diff --git a/pythonx/UltiSnips/compatibility.py b/pythonx/UltiSnips/compatibility.py index 84cedc4..1a05f13 100644 --- a/pythonx/UltiSnips/compatibility.py +++ b/pythonx/UltiSnips/compatibility.py @@ -35,7 +35,8 @@ if sys.version_info >= (3, 0): Convert a valid column index into a byte index inside of vims buffer. """ - pre_chars = vim.current.buffer[line-1][:col] + # We pad the line so that selecting the +1 st column still works. + pre_chars = (vim.current.buffer[line-1] + " ")[:col] return len(_vim_enc(pre_chars)) def byte2col(line, nbyte): @@ -68,7 +69,8 @@ else: Convert a valid column index into a byte index inside of vims buffer. """ - pre_chars = _vim_dec(vim.current.buffer[line-1])[:col] + # We pad the line so that selecting the +1 st column still works. + pre_chars = _vim_dec(vim.current.buffer[line-1] + " ")[:col] return len(_vim_enc(pre_chars)) def byte2col(line, nbyte): diff --git a/pythonx/UltiSnips/snippet_manager.py b/pythonx/UltiSnips/snippet_manager.py index eeb35cd..a71a40e 100644 --- a/pythonx/UltiSnips/snippet_manager.py +++ b/pythonx/UltiSnips/snippet_manager.py @@ -497,6 +497,8 @@ class SnippetManager(object): self._visual_content.reset() self._csnippets.append(si) + si.update_textobjects() + self._ignore_movements = True self._vstate.remember_buffer(self._csnippets[0]) diff --git a/pythonx/UltiSnips/text_objects/_tabstop.py b/pythonx/UltiSnips/text_objects/_tabstop.py index 4eff6af..ef0cb87 100644 --- a/pythonx/UltiSnips/text_objects/_tabstop.py +++ b/pythonx/UltiSnips/text_objects/_tabstop.py @@ -28,3 +28,7 @@ class TabStop(EditableTextObject): """True if this tabstop has been typed over and the user therefore can no longer jump to it.""" return self._parent is None + + def __repr__(self): + return "TabStop(%s,%r->%r,%r)" % (self.number, self._start, + self._end, self.current_text) diff --git a/test.py b/test.py index 948600c..73d70e2 100755 --- a/test.py +++ b/test.py @@ -740,6 +740,10 @@ class TabStopSimpleReplace_ExpectCorrectResult(_VimTest): snippets = ("hallo", "hallo ${0:End} ${1:Beginning}") keys = "hallo" + EX + "na" + JF + "Du Nase" wanted = "hallo Du Nase na" +class TabStopSimpleReplaceZeroLengthTabstops_ExpectCorrectResult(_VimTest): + snippets = ("test", r":latex:\`$1\`$0") + keys = "test" + EX + "Hello" + JF + "World" + wanted = ":latex:`Hello`World" class TabStopSimpleReplaceReversed_ExpectCorrectResult(_VimTest): snippets = ("hallo", "hallo ${1:End} ${0:Beginning}") keys = "hallo" + EX + "na" + JF + "Du Nase" @@ -3156,6 +3160,16 @@ class Bug1251994(_VimTest): keys = " test" + EX + "hello" + JF + "world" + JF + "blub" wanted = " world hello;blub" # End: 1251994 #}}} +# Test for https://github.com/SirVer/ultisnips/issues/157 (virtualedit) {{{# +class VirtualEdit(_VimTest): + snippets = ("pd", "padding: ${1:0}px") + keys = "\t\t\tpd" + EX + "2" + wanted = "\t\t\tpadding: 2px" + + def _extra_options_pre_init(self, vim_config): + vim_config.append('set virtualedit=all') + vim_config.append('set noexpandtab') +# End: 1251994 #}}} # Test for Github Pull Request #134 - Retain unnamed register {{{# class RetainsTheUnnamedRegister(_VimTest): snippets = ("test", "${1:hello} ${2:world} ${0}") @@ -3339,7 +3353,7 @@ class MySnippetSource(SnippetSource): # End: Snippet Source #}}} # Plugin: YouCompleteMe {{{# -class YouCompleteMe_IntegrationTest(_VimTest): +class Plugin_YouCompleteMe_IntegrationTest(_VimTest): def skip_if(self): r = python3() if r: @@ -3362,7 +3376,7 @@ class YouCompleteMe_IntegrationTest(_VimTest): time.sleep(1) # End: Plugin: YouCompleteMe #}}} # Plugin: Neocomplete {{{# -class Neocomplete_BugTest(_VimTest): +class Plugin_Neocomplete_BugTest(_VimTest): # Test for https://github.com/SirVer/ultisnips/issues/228 def skip_if(self): if "+lua" not in self.version: @@ -3381,7 +3395,7 @@ class Neocomplete_BugTest(_VimTest): vim_config.append('let g:neocomplete#enable_refresh_always = 1') # End: Plugin: Neocomplete #}}} # Plugin: Supertab {{{# -class SuperTab_SimpleTest(_VimTest): +class Plugin_SuperTab_SimpleTest(_VimTest): plugins = ["ervandew/supertab"] snippets = ("long", "Hello", "", "w") keys = ( "longtextlongtext\n" +