junegunn / fzf.vim

fzf :heart: vim
MIT License
9.68k stars 585 forks source link

Snippet expansion and word under cursor #796

Open aldantas opened 5 years ago

aldantas commented 5 years ago

When the Snippet command is called, the word under cursor is automatically used as initial pattern for the search. The problem is that, once a matching is selected, the snippet keyword is inserted after the current word and hence the snippet expansion fails.

For example, if the word under cursor is 'def', one possible suggestion could be 'defm'. Upon selecting the later, the resulting text becomes 'defdefm', which is not a valid snippet keyword.

So perhaps there could be a way to prevent this, either by deleting the current word under cursor before inserting the selected keyword, or by completing the keyword instead of inserting it whole. The former solution is simpler, just replace

function! s:inject_snippet(line)
  let snip = split(a:line, "\t")[0]
  execute 'normal! a'.s:strip(snip)."\<c-r>=UltiSnips#ExpandSnippet()\<cr>"
endfunction

to

function! s:inject_snippet(line)
  let snip = split(a:line, "\t")[0]
  execute 'normal! diwi'.s:strip(snip)."\<c-r>=UltiSnips#ExpandSnippet()\<cr>"
endfunction
maamo888 commented 5 years ago

Will this functionality change not be reflected?

I also prefer this behavior for :Snippets.

I use it in the insert mode, but now I use it with caution. :(

inoremap <c-f><c-u> <c-\><c-o>:Snippets<CR>

@junegunn @aldantas

josefson commented 4 years ago

Came here looking for this as well, i'd really like for this to work out. Right now i've been using the default g:UltiSnipsListSnippets bind which works well enough, but i dont have anyway of filtering the list down AND i gotta select with numbers.

liskin commented 4 years ago

I observed one additional problem with :Snippets: ultisnips often enters insert mode to let me fill in tabstops/placeholders and jump between them, but after :Snippets, this doesn't work and the cursor is positioned to the left of the first tabstop and vim is in normal mode. This happens e.g. with the vim for snippet. This is most likely because ultisnips uses :startinsert which doesn't work from :normal.

Both problems seem to be fixed by using the following:

function! s:inject_snippet(line)
  startinsert

  let col = col('.')
  if col > 1 && getline('.')[: col-2] =~ "\\S$"
    call feedkeys("\<c-w>", 'n')
  endif

  let snip = split(a:line, "\t")[0]
  call feedkeys(s:strip(snip) . "\<c-r>=UltiSnips#ExpandSnippet()\<cr>", 'n')
endfunction

together with

nnoremap <silent> <C-_> :Snippets<CR>
inoremap <silent> <C-_> <C-\><C-O>:Snippets<CR>

Can you folks please test that before I submit a pull request?

liskin commented 4 years ago

I didn't really like the :startinsert so I figured a better way to fix this:

function! s:inject_snippet(line)
  let ve = &ve
  set ve=onemore
  let del = col('.') > 1 && getline('.')[0 : col('.')-2] =~ "\\S$" ? "\<c-w>" : ""
  let snip = split(a:line, "\t")[0]
  execute 'normal! i'.del.s:strip(snip)
  execute 'normal! l'
  call UltiSnips#ExpandSnippet()
  let &ve = ve
endfunction

It feels solid so I submitted a PR right away: #1196

liskin commented 4 years ago

Oh crap, invoking UltiSnips#ExpandSnippet via call breaks the select mode. :-(

liskin commented 3 years ago

I just updated #1196 with a fix for another glitch, and the select mode problem goes away if the insert mode mapping uses <Cmd> instead of <C-\><C-O> (needs vim 8.2.1978+), e.g.:

inoremap <silent> <C-_> <Cmd>:Snippets<CR>

If any of you still have some problems with fzf.vim + UltiSnips, can you perhaps give my PR a try? (If you have older vim without <Cmd>, then just revert the latest commit in the PR.)