ocaml / merlin

Context sensitive completion for OCaml in Vim and Emacs
https://ocaml.github.io/merlin/
MIT License
1.56k stars 234 forks source link

Use asynchronous completion in Vim 8 / Neovim #726

Open edwintorok opened 6 years ago

edwintorok commented 6 years ago

Same as https://github.com/ocaml/merlin/issues/725 but for Vim.

Vim 8 and Neovim now support asynchronous job execution, and there are several plugins for asynchronous completion that support both editors(e.g. asyncomplete or nvim-completion-manager). They can be used with merlin as is, however calling omnifunc is always done synchronously (even in deoplete, it would be nice if there was an async merlin completion source that these plugins could use (with the current blocking omnifunc as fallback for Vim 7.x). See here for an example: https://github.com/prabirshrestha/asyncomplete-flow.vim/blob/master/autoload/asyncomplete/sources/flow.vim

With the default config recommended by the merlin docs Vim/Neovim with neocomplete/deoplete is in fact a lot slower than Emacs because it invokes the completion over and over for each character typed in hosts (and setting the various delay parameters of the plugins doesn't help because it only delays displaying the popup, not calling omnifunc). If the pattern is modified to trigger only on the dot then it is somewhat faster but the UI still freezes for several seconds:

if has("nvim")                                                                                                                                                
    let g:deoplete#enable_at_startup=1                                                                                                                        
    if !exists('g:deoplete#omni_input_patterns')                                                                                                              
      let g:deoplete#omni#input_patterns = {}                                                                                                                 
    endif                                                                                                                                                     
    let g:deoplete#omni#input_patterns.ocaml = '[^. *\t]\.'                                                                                                   
else                                                                                                                                                          
   let g:neocomplete#enable_at_startup = 1                                                                                                                    
    if !exists('g:neocomplete#force_omni_input_patterns')                                                                                                     
        let g:neocomplete#force_omni_input_patterns = {}                                                                                                      
    endif                                                                                                                                                     
    let g:neocomplete#force_omni_input_patterns.ocaml = '[^. *\t]\.'                                                                                          
    let g:neocomplete#auto_complete_delay = 50                                                                                                                
endif     
copy commented 6 years ago

I'm working on a plugin for this, I will send a PR probably this week.

copy commented 6 years ago

I released this as a standalone vim plugin: https://github.com/copy/deoplete-ocaml

edwintorok commented 6 years ago

Thanks a lot @copy for the plugin, I've just tried it and Vim 8 doesn't freeze anymore when completion is slow. In fact it is a lot better than emacs now :)

zploskey commented 6 years ago

If this works, this would be amazing to merge.

bluddy commented 6 years ago

Please merge this. I've been searching for a solution and almost didn't find this. Without asynchronous completion, merlin completion is barely usable on neovim.

Leandros commented 5 years ago

@copy Hmm. With neovim, your plugin, deoplete and merlin enabled, the completion is still super slow. Do I need to setup merlin differently, so it doesn't override the completion from deoplete?

copy commented 5 years ago

@Leandros My plugin doesn't speed up completion, it only makes it asynchronous, so you can type without lags while completion is running in the background. You can check that the plugin is working if the completion list contains [ocaml] at the end of each entry. If it contains [o] or nothing, you're using synchronous completion.

That said, @Khady and @andreypopp have recently merged asynchronous completion via LSP. I haven't tested it yet, but I intend to deprecate my plugin once that's working stably.

Leandros commented 5 years ago

@copy Alright, it seems to be working (completions come from [ocaml]), however, the lag while typing isn't completely gone. I'll look at completion via LSP later today.

let-def commented 5 years ago

Can one of you point me to a repository where the completion is slow? I would like to investigate.

copy commented 5 years ago

@let-def Maybe @Leandros has a better test case, but here's a starting point:

open! Core
open! Async

Core.
(executable
 (name test)
 (libraries core async))
% dune build .merlin
% ocamlmerlin server complete-prefix -prefix Core. -position 4:6 -filename $PWD/test.ml -doc y < test.ml
"timing":{"total":319.54100000000017,"query":318.8710000000002,"reader":0.09199999999998454,"ppx":0.01999999999998181,"typer":0.5579999999999927,"error":0.0}

319 ms is a significant latency while typing text, but it's not too bad with asynchronous completion. Leaving out -doc y reduces the delay to 15 ms.

trefis commented 5 years ago

That is not too surprising: -doc will fetch you a bunch of cmt files, and “do things” with them. I’ll have look on Monday at just how much is done in that particular case.

Btw, I expect the latency to reduce overtime as the docs are cached. What’s the timing of you make that same query a second time?

let-def commented 5 years ago

There is a caching problem with -doc. On my setup, the measurements are noise without -doc y and is 300+-50ms with.