roxma / nvim-completion-manager

:warning: PLEASE USE https://github.com/ncm2/ncm2 INSTEAD
MIT License
917 stars 49 forks source link

Doesn't work with LanguageClient-neovim in Vim8 (but works in Neovim) #175

Open kodemeister opened 6 years ago

kodemeister commented 6 years ago

Hi @roxma,

I'm having issues while trying to get NCM work with LanguageClient-neovim in Vim 8. In Neovim completions from LanguageClient-neovim work perfectly but I can't get them working in Vim 8 at all.

I'm using C++ but the language doesn't really matter. Here is a test C++ file:

#include <iostream>

int main(int argc, char **argv)
{
    std:: // Completions show up in Neovim but not in Vim 8
    return 0;
}

In Vim 8 LanguageClient-neovim issues the following error in /tmp/LanguageClient.log:

2018-01-13T23:17:45.186112346+06:00 ERROR languageclient::languageclient - Error handling message. Message: {"method":"LanguageClient_NCMRefresh","jsonrpc":"2.0","params":[{"scopes":["cpp"],"cm_refresh_patterns":["\\.",">",":"],"early_cache":0,"cm_refresh":"LanguageClient_NCMRefresh","priority":9,"enable":1,"auto_popup":1,"cm_refresh_length":3,"sort":1,"abbreviation":"LC","name":"LanguageClient_cpp"},{"scope_match":"cpp","lnum":5,"bufnr":1,"changedtick":3,"typed":"\tstd::","base":"","filetype":"cpp","curpos":[0,5,7,0,14],"col":7,"early_cache":0,"filepath":"/home/kodemeister/test.cpp","scope":"cpp","force":0,"startcol":7,"match_end":6}]}. Error: ErrorImpl { code: Message("invalid type: integer `0`, expected a boolean"), line: 0, column: 0 }

So basically LanguageClient-neovim tells us that it expects some Boolean value but gets a plain integer 0 instead.

I've tracked the issue down to NCM function cm#_notify_sources_to_refresh, particularly to the code which calls source completion functions:

elseif l:type==1
    "string
    call call(g:_cm_sources[l:name].cm_refresh,[g:_cm_sources[l:name],l:call['context']],g:_cm_sources[l:name])

The problem is that l:call['context'] value differs in Neovim and Vim 8. Here is its value in Neovim:

{'scope_match': 'cpp', 'lnum': 5, 'bufnr': 1, 'changedtick': 3, 'typed': ' std::', 'base' : '', 'filetype': 'cpp', 'curpos': [0, 5, 7, 0, 14], 'col': 7, 'early_cache': v:false, 'filepath': '/home/kodemeister/test.cpp', 'scope': 'cpp', 'force': 0, 'startcol': 7, 'match_end': 6}

And in Vim 8:

{'scope_match': 'cpp', 'lnum': 5, 'bufnr': 1, 'changedtick': 3, 'typed': ' std::', 'base' : '', 'filetype': 'cpp', 'curpos': [0, 5, 7, 0, 14], 'col': 7, 'early_cache': 0, 'filepath': '/home/kodemeister/test.cpp', 'scope': 'cpp', 'force': 0, 'startcol': 7, 'match_end': 6}

Can you see the difference? In Neovim early_cache key is v:false whereas in Vim 8 early_cache is just plain integer 0. That's why LanguageClient-neovim gives us an error in Vim 8! It expects early_cache to be strictly v:true or v:false but not 1 or 0.

Since early_cache is set in Python code I think the difference comes from conversions between Python and VimL types. Neovim converts Python's True and False to VimL's v:true and v:false while Vim 8 bundled with vim-hug-neovim-rpc converts them to 1 and 0.

Nevertheless, I was able to temporarily fix the issue with an ugly hack:

elseif l:type==1
    "string
    let l:context = l:call['context']
    let l:context['early_cache'] = l:context['early_cache'] ? v:true : v:false
    call call(g:_cm_sources[l:name].cm_refresh,[g:_cm_sources[l:name],l:call['context']],g:_cm_sources[l:name])

Could you please suggest a better solution here? I thought about fixing Python code to always set early_cache to 0 or 1 but LanguageClient-neovim should be also adjusted in this case.

Thanks!