garbas/vim-snipmate

Snippet expansion fails intermittently

victoriastuart opened this issue · 2 comments

Apologies if this is a FAQ. Examples:

  • when I expand pp to <p></p> after a word or at the end of a line, it works: <p><cursor></p>

  • when I expand <li> pp (<li> triggered by li <tab>) it fails to complete to <li> <p><cursor</p>

    • i.e., I type li <tab> pp <tab> expecting to get <li> <p><cursor</p>, but instead get <li> pp, with the [block] cursor positioned over the first p in pp
  • similarly fails when trying to expand the i, inside <b>i</b>, in a 2-step process: b <tab> giving <b></b> with cursor auto-positioned between those tags, so I can type i <tab>

    • i.e., if I type b <tab> i <tab> I get <b>i</b><cursor>, not the expected <b><i><cursor></i></b>

So, I constantly have to reposition the cursor and press <tab> to complete the expansion.

It appears to be an issue with completion of the second of two concurrent snippet expansions, perhaps exacerbated by the cursor repositioning (${1})?

For reference, here are the snippets mentioned:

snippet pp
	<p>${1:}</p>

snippet li
	<li> ${1:}

snippet b
	<b>${1:}</b>

snippet i
	<i>${1:}</i>

This is actually working as intended, though your confusion is totally understandable.

For each of your snippets, SnipMate adds a $0 to the end of it, which indicates where the cursor should be when the snippet is done with. By default SnipMate maps <tab> to a function that first tries to jump to the next tabstop. If none exists, only then does it trigger the snippet before the cursor. So when you're hitting tab, SnipMate jumps to that zero tabstop instead of triggering your snippet like you expect.

There are two possible solutions here: you can change your snippets so that the zero tabstop is inside the HTML tag, something like <p>$0</p>, or you can create another insert mode mapping that always triggers a snippet, whether you're in one already or not. That would look like :imap <C-J> <Plug>snipMateTrigger where ` is the key you want to map to. The map probably makes more sense for you.

The relevant sections in the help are :h SnipMate-zero-tabstop and :h SnipMate-mappings.

Hi Adnan: thank you for your reply. I played around a bit, finding a solution. In the second example above,

I type li <tab> pp <tab> expecting to get <li> <p><cursor</p>, but instead get <li> pp, with the [block] cursor positioned over the first p in pp

... I solved this by removing the ${1:} in my li snippet:

snippet li
	<li> 

not

snippet li
	<li> ${1:}

Likewise I solved the other examples shown by editing my snippets (replacing ${1:} with ${0}:

snippet b
	<b>${0:}</b>

snippet i
	<i>${0:}</i>

not

snippet b
	<b>${1:}</b>

snippet i
	<i>${1:}</i>

Now, I can get <b><i><cursor></i></b> (or the reciprocal, <i><b><cursor></b></i>) through a b <tab> i <tab> (etc.) keypress sequence. :-)

While I could have simply defined a "two-in-one snippet," e.g.

snippet bi
	<b><i>${1:}</i></b> ${0:}

... I needed to understand this behavior, as it affects some other tandem snippet combinations.

Thank you for your kind response and your work; much appreciated! :-)