为了体验 LSP 的效果,最近试用了下 LanguageClient-neovim 这个插件(以下简称 LCN )。
总的来说 LSP 的基本功都已实现,但是细节体验上还跟 vscode 存在很大差距,尤其是在补全功能的实现上面。
我给作者提了几次 issue, 但是似乎作者不愿意讨论相关问题,所以记录在此,以供诸位 vim 用户参考、讨论。
不支持 complete
的 supportSnippet
却会在 initialize 中发送 {"supportSnippet": true}
。
LCN 简单的检测了用户是否安装了 snippet 相关插件,如果有安装就声明 supportSnippet 为 true,但是实际上 LCN 并没有任何代码支持对 LSP 服务端返回的 snippet 进行扩展,也没有为 completion 插件声明如何处理 snippet。相关 issue: https://github.com/autozimu/LanguageClient-neovim/issues/379 https://github.com/autozimu/LanguageClient-neovim/pull/410
可能错误的补全起始位置判定:
源码使用了 python 的 \w
寻找补全单词起始位: https://github.com/autozimu/LanguageClient-neovim/blob/next/rplugin/python3/deoplete/sources/LanguageClientSource.py#L20
但是不同语言类型关键词并不相同,这里使用 vim 中的 \k
来寻找补全的起始位置应该更合适些。正确的实现应该是在 LSP 服务端返回的 TextEdit
中的 range
里面获取补全的起始和终止位置。
发送错误的补全起始位置给 LSP server。
LSP 服务端 completion 接受的 position 中的 charactor 字段应该是当前光标所在列,但是 LSP 却会发送当前单词第一个字母所在列,相关代码: https://github.com/autozimu/LanguageClient-neovim/blob/next/rplugin/python3/deoplete/sources/LanguageClientSource.py#L23, 这会导致部分 LSP 服务端位置判定错,例如: https://github.com/chemzqm/wxml-languageserver 需要在补全时判定当前光标后面是否已经紧跟 =
来返回不同 textEdit
对象。
猜测如此实现是为了更好支持 deoplete 插件中提供的 fuzzy match 功能,因为 LSP 服务端可能对于补全前半部分做的是全匹配验证。
错误的处理返回的 TextEdit
代码: https://github.com/autozimu/LanguageClient-neovim/blob/d7cac79c1dd2b7b644c07ff55c8208821ff1192e/src/types.rs#L419 text_edit.new_text
应该就是服务端返回用于插入的文本,但是由于 LCN 无法支持 text_edit
中的 range
修改已有 buffer,所以只能去主观的截取第一个单词,然后移除末尾的非单词部分。该做法会极大影响部分 LSP 服务的使用,例如 https://github.com/vscode-langservers/vscode-css-languageserver-bin 补全 css 属性时 new_text
最后为空格,另外像 https://github.com/Microsoft/vscode-html-languageservice 会返回带有 "
的 snippet 补全项。
问题根源在与 neovim/vim 提供的 complete 功能无法支持 LSP 中的 TextEdit
以及 snippet
等定义,所以我提了一个需求 https://github.com/neovim/neovim/issues/8334
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.