Shougo / neosnippet.vim

neo-snippet plugin
Other
1.12k stars 108 forks source link

Try to fix trigger when completing LSP snippet #490

Closed justinas closed 4 years ago

justinas commented 4 years ago

This tries to fix an issue I found while using rust-analyzer in conjuction with LanguageClient-neovim, deoplete and neosnippet.

The behavior I observe is:

  1. When cycling through the items, this setup fills in the shortened (label?) version of the completion item, e.g. bar(…) in my case, resulting in a line _foo.bar(…).
  2. When completion is done (e.g. on pressing a char like ;), LanguageClient proceeds with the full text edit. When neosnippet is enabled, this inserts a snippet like bar(${1:baz}, ${2:quux})$0 and neosnippet tries to expand / delete manually entered part of the item. However, it acts on the full snippet, unaware that the current line only contained bar(…) and thus deletes a much longer suffix of the line (according to the entire snippet).

I "fixed" this by instead treating v:completed_item.word as snippet_trigger, which contains the right suffix to delete: bar(…).

I tested that this fixes the issue with rust-analyzer and does not seem to break other language servers, specifically clangd and pyls.

Note that I barely know VimL and LSP, so I arrived at this fix through sheer bruteforce. Please feel free to suggest any ways to improve the solution.

See the original issue in rust-analyzer repo for demonstration https://github.com/rust-analyzer/rust-analyzer/issues/3991

Note that this code has previously been touched by another PR that also mentioned rust-analyzer: https://github.com/Shougo/neosnippet.vim/issues/487. I do not yet understand what the implications are.

justinas commented 4 years ago

Reproduce instructions (neovim):

vimrc

set runtimepath^=~/.vim runtimepath+=~/.vim/after
set clipboard=unnamedplus

filetype off
call plug#begin('~/.vim/plugged')
    Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' }
    Plug 'autozimu/LanguageClient-neovim', { 'branch': 'next', 'do': 'bash install.sh' }
    Plug 'Shougo/neosnippet.vim'
call plug#end()
filetype plugin indent on
syntax on

" Cycle on TAB
inoremap <silent><expr> <S-TAB> pumvisible() ? "\<C-p>" : "\<TAB>"
imap <silent><expr> <TAB>
     \ pumvisible()
     \ ? "\<C-n>"
     \ : neosnippet#jumpable()
     \ ? "\<Plug>(neosnippet_jump)"
     \ : "\<TAB>"

" Complete on CR
imap <silent><expr> <CR>
     \ pumvisible()
     \ ? "\<C-y>"
     \ : "\<CR>"

let g:deoplete#enable_at_startup = 1

let g:LanguageClient_serverCommands = {
    \ 'c': ['clangd-9', '-background-index'],
    \ 'python': ['pyls'],
    "\ 'rust': ['rustup', 'run', 'stable', 'rls'],
    \ 'rust': ['rustup', 'run', 'stable', 'rust-analyzer'],
    \ }
let g:LanguageClient_signatureHelpOnCompleteDone = 0 " does not work well yet

let g:neosnippet#disable_runtime_snippets = {
    \ '_' : 1
    \ }
let g:neosnippet#enable_complete_done = 1

impl Foo { fn bar(&self, baz: i32, quux: usize) -> &str { "quux" } }

fn main() { let _foo = Foo; }



Try to insert this line in `fn main`: `_foo.bar` and autocomplete the `bar` method. Observe that on completion neosnippet truncates the start of the line. [Asciinema recording](https://asciinema.org/a/v9vGCIrsz4h0sOknPGGcFP0rm)
Shougo commented 4 years ago

OK. I get it.

justinas commented 4 years ago

Thank you so much for the quick response!