JumpForward does not happen in certain cases when line is indented

Bug #1251994 reported by Sergey Alexandrov on 2013-11-17
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
UltiSnips
Fix Committed
Medium
Unassigned

Bug Description

Hi,

I have been using UltiSnips for a very long while with no problems, however recently I came across a strange behavior. Here is a minimal snippet that reproduces the problem:

snippet test "Test snippet" !b
${2:#2} [$1] ${1:#1};$0
endsnippet

The expected behavior is following. You enter some text in the first tabstop (it automatically gets copied over inside the square brackets due to $1 mirror), then you press Tab and enter some text in the second tabstop. Finally, you press Tab once again and jump to the end of the line.

The actual behavior is that after entering the text for the second tabstop and pressing Tab the jump to the end of the line does not happen.

I suspect it is somehow related with the [$1] thing. My experiments show that if you do not modify the default text of the first tabstop (consequently the mirrored text inside the square brackets is not modified), then the jump happens as expected. Also, if you put the [$1] thing before the second tabstop, the behavior will be as expected. To summarize, there seems to be a problem with JumpForward when a tabstop is followed by a mirror of another tabstop (which gets entered earlier).

The output of :py import sys; print sys.version:
2.7.3 (default, Sep 26 2013, 16:38:06)
[GCC 4.7.2]

Regards,
Sergey

SirVer (sirver) wrote :

works for me:

test<tab>hello<jump>world<jump>blub yields

world [hello] hello;blub

I am using the latest dev version from github and mvim (mac vim). What is your setup?

Changed in ultisnips:
status: New → Incomplete

I have the latest revision of the master branch from github. My setup is Ubuntu 12.10 with the standard vim and terminal versions.

I thought that maybe some of the other plugins interfere, so I disabled everything but ultisnips. I also reverted to the default ultisnips keymaps. But still:

test<Tab>hello<C-j>world<C-j>blub

yields

worldblub [hello] hello;

As before, if I avoid changing the first tabstop, the jump happens, i.e.

test<Tab><C-j>world<C-j>blub

yields

world [#1] #1;blub

Also, I think the problem is definitely not in keymappings, because UltiSnips_JumpForwards() does not perform jump even if invoked manually:

test<Tab>hello<C-j>world<Esc>:UltiSnips_JumpForwards()<CR>

does not jump to the end of the line.

Any ideas? What additional information could I provide?

SirVer (sirver) wrote :

From where did you clone? github.com/sirver/ultisnips is the only supported branch.

 You could try with a minimal .vimrc and see if this changes things.

Sure, I cloned from "github.com/sirver/ultisnips". There are two branches though, so I used "master".

I tried with the following minimal setup:

a) Only two lines in ".vimrc":

set nocompatible
syntax on

b) The ".vim" folder contains only the clone of the plugin repository.

Nevertheless, the behavior is exactly the same.

SirVer (sirver) wrote :

I repeated #4 and I do not see the bug. Are you on linux? Which vim version? Do you have access to a mac box to try with mvim there (it could be a language setting or whatever).

Yes, I am on Ubuntu 12.10
Vim version is:

VIM - Vi IMproved 7.3 (2010 Aug 15, compiled May 3 2013 23:52:20)
Included patches: 1-831
Modified by <email address hidden>
Compiled by buildd@
Huge version without GUI. Features included (+) or not (-):
+arabic +file_in_path +mouse_sgr +tag_binary
+autocmd +find_in_path -mouse_sysmouse +tag_old_static
-balloon_eval +float +mouse_urxvt -tag_any_white
-browse +folding +mouse_xterm -tcl
++builtin_terms -footer +multi_byte +terminfo
+byte_offset +fork() +multi_lang +termresponse
+cindent +gettext -mzscheme +textobjects
-clientserver -hangul_input +netbeans_intg +title
-clipboard +iconv +path_extra -toolbar
+cmdline_compl +insert_expand -perl +user_commands
+cmdline_hist +jumplist +persistent_undo +vertsplit
+cmdline_info +keymap +postscript +virtualedit
+comments +langmap +printer +visual
+conceal +libcall +profile +visualextra
+cryptv +linebreak +python +viminfo
+cscope +lispindent -python3 +vreplace
+cursorbind +listcmds +quickfix +wildignore
+cursorshape +localmap +reltime +wildmenu
+dialog_con -lua +rightleft +windows
+diff +menu -ruby +writebackup
+digraphs +mksession +scrollbind -X11
-dnd +modify_fname +signs -xfontset
-ebcdic +mouse +smartindent -xim
+emacs_tags -mouseshape -sniff -xsmp
+eval +mouse_dec +startuptime -xterm_clipboard
+ex_extra +mouse_gpm +statusline -xterm_save
+extra_search -mouse_jsbterm -sun_workshop
+farsi +mouse_netterm +syntax
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
      user exrc file: "$HOME/.exrc"
  fall-back for $VIM: "/usr/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
Linking: gcc -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,--as-needed -o vim -lm -ltinfo -lnsl -lselinux -lacl -lattr -lgpm -ldl -L/usr/lib/python2.7/config -lpython2.7 -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions

I did some more experiments and figured out an additional condition for this behavior: the jump does happen only if the line in which the snippet is expanded has indentation. In other words,

test<Tab> ....

works as expected, whereas

  test<Tab> ....

gives the behavior I described before. I did not mention this difference because I tested inside a C++ file and always had indentation.

Unfortunately I do not have access to Mac OS. Could you please check if you can reproduce the bug now?

Sorry, I meant "the jump does NOT happen only if the line in which the snippet is expanded has indentation".

SirVer (sirver) wrote :

I can confirm the behavior now. Thanks for reporting.

Changed in ultisnips:
status: Incomplete → Confirmed
importance: Undecided → Medium
summary: - JumpForward does not happen in certain cases
+ JumpForward does not happen in certain cases when line is indented

Turns out the bug does not have anything to do with mirrors. This simplified version also fails:

snippet test "Test snippet" !b
${2:#2} ${1:#1};$0
endsnippet

I tried to track down the bug, but apparently I do not have a good understanding of the ins and outs of the plugin. What I found is that after entering text in the first tabstop and pressing Tab the cursor jumps to the second tabstop, but then two spurious calls to `SnippetsManager.cursor_moved()` occur, one of them indicating that the cursor moved 1 character to the left, another one that the cursor moved 1 character to the right. That is why indentation matters. When there is no indentation (i.e. we are in the beginning of the line), the spurious left motion has no effect and the cursor does not actually leave the snippet "territory". When there is indentation, the cursor moves out of the snippet therefore finishing it. Unfortunately, I have no clue why these motions happen...

SirVer (sirver) wrote :

Thanks for looking into this.. Have you seen the methods in debug.py ? I use them a lot to track what is happening and where.

I dimly remember that I originally added a space at the end of every line to avoid some problems - but I have found a way to make all tests pass without this. Maybe it is needed at the beginning too :).

I had some time to look into the problem again and I think I have found both the source of the problem and a solution. The reason why cursor moves left and then right after jumping to the second tab stop is because of the select() function from _vim.py. This function leaves insert mode and then visually selects the placeholder text of the second tab stop. It is smart enough to understand that leaving insert mode via "Esc" moves the cursor one character left, so it immediately moves it right to compensate. Unfortunately, these motions do not "cancel", and both trigger CursorMoved events, which consequently trigger `SnippetsManager.cursor_moved()` function which decides that the snippet is done.

I have submitted a pull request on github: https://github.com/SirVer/ultisnips/pull/120

SirVer (sirver) wrote :

Thanks sergey. excellent analysis and patch!

Changed in ultisnips:
status: Confirmed → Fix Committed

My pleasure. Thanks for the plugin!

To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers