藻ログ

都会でOLをしています

neovim + coc.nvim で LSP

TL;DR

  • LSP (Language Server Protocol) をサポートしたツールが充実してきている
  • coc.nvim を使って まとめて各言語の補助機能を Language Server に移行した
  • TypeScript 製であることや npm の利用など,VSCode っぽくなって面白い

  • LanguageClient-neovim使ったことありません
  • vim-lsc使ったことありません
  • vim-lsp使ったことありません
  • VSCode 使ったことありません

LSP とは

各言語の(auto complete, goto def, find references, auto formatting, error checker ...) のような機能をまとめて提供するサービス(= language server)とそれを利用するツール間のプロトコルを定めたものです.MS が発表したのが確か 2016年頃だったので割と昔からあります.
github.com

何が嬉しいのか

これまでは各IDE/Editor に依存したツールをメンテナンスしていたのが,LSPに集約することによって :vim: を使っていようが :vscode: を使っていようが共通の LSP資産を利用することができる.とても🆒.

neovim から LSP を利用するには

まず LSP Client が必要.

どの LSP client を使うか

built-in の LSP Client の提供はまだまだ先なので,third party の LSP client を選ぶ必要がある
www.reddit.com

Langserver.org で各LSP client の対応状況を見てみる*2
f:id:nisimur:20190325194324p:plain

有名どころの

はいずれもフルチェックなので,どれを選んでも良さそう(本当か?)
LanguageClient-neovim は Rust製,coc.nvim は TypeScript製,vim-lsp ALE は VimScript 製なのでこの辺りも好みが分かれるかもしれない.

ALE

ALEは高速な非同期 linter だと思っていたらいつの間にか LSP integration も提供するようになっていた.
GitHub - w0rp/ale: Asynchronous linting/fixing for Vim and Language Server Protocol (LSP) integration

ALE acts as a "language client" to support a variety of Language Server Protocol features, including:
Diagnostics (via Language Server Protocol linters)
Go To Definition (:ALEGoToDefinition)
Completion (let g:ale_completion_enabled = 1 before ALE is loaded)
Finding references (:ALEFindReferences)
Hover information (:ALEHover)
Symbol search (:ALESymbolSearch)

元々ALE を使っていたので全てこれで賄えれば便利かと思ったが,既存の ale_linterale_lsp_linter が一部競合して煩わしく感じたり*3,速度面で不満が出てきたので ALE は 非LSPのlinter専用として使うことにした*4

coc.nvim

後は vim-lspcoc.nvim で悩んだが,現状 cocが最もLSPの機能サポートが充実している
https://github.com/neoclide/coc.nvim/wiki/Language-servers#supported-features
ように見えたということと,TypeScript 製なので何か壊れてても自分で直せそうという理由から coc を選択した.*.nvim と付いてますが Vimからも使えるようだ*5

これを書いてる土日の間に GitHub Star が500増えてた*6ので履歴を調べると,どうも最近指数関数的にユーザー数が増えているらしい.
star-history でグラフを取ってみたら,丁度ここ数日で coc が language-client-neovim を超えていた.

f:id:nisimur:20190403000124p:plain
Star history


nvim の floating window もサポートしていてすばやい.
F.A.Q · neoclide/coc.nvim Wiki · GitHub

vim-lsp

余談だが,spacemacs 系の spacevim では vim-lsp の方を同梱しているらしい.
SpaceVim language server protocol layer | SpaceVim

coc.nvim の install

wiki の情報が結構不足してるようだったので,
coc.nvim/coc.txt at master · neoclide/coc.nvim · GitHub やソースを読んでエスパーした*7

dependencies

node.js と yarn が必要です.普段から使ってる人が多いと思うので特に問題ないと思う
Install coc.nvim · neoclide/coc.nvim Wiki · GitHub

dein

dein.vim を使っているので toml でインストールする

[[plugins]]
repo = 'neoclide/coc.nvim'
build = 'coc#util#install()'
hook_add = 'source path/to/your/coc-setting.vim'

coc-setting.vim について,キーマップなどの設定は以下を参考にすると良い
GitHub - neoclide/coc.nvim: Intellisense engine for vim8 & neovim, full language server protocol support as VSCode

status line は lightline との連携方法が提供されている.
GitHub - itchyny/lightline.vim: A light and configurable statusline/tabline plugin for Vim

coc extensions

Using coc extensions · neoclide/coc.nvim Wiki · GitHub
coc では,様々な extension を :CocInstall で手軽に入れることが出来る.バックエンドでは yarn を使って npm モジュールを workspace.env.extensionRoot のパス以下にインストールするようになっている.

[vim-node-coc]: Error on Initialize: ENOENT: no such file or directory, open .config/coc/memos.json

extension root のディレクトリが空だと coc の initialize に失敗してしまうので,$ mkdir -p ~/.config/coc/extensions しておく必要がある.
default では以下のパスになっているので,dotfiles (nvim以下) を git で管理しているなら .config/nvim/coc/extensions とかに変更しても良さそう *8

" autoload/coc/util.vim
function! coc#util#extension_root() abort
  if s:is_win
    let dir = $HOME.'/AppData/Local/coc/extensions'
  else
    let dir = $HOME.'/.config/coc/extensions'
  endif
  return dir
endfunction

coc settings

:CocConfig すると設定ファイルが開けます. これは nvim/coc-settings.json あたりに出来る
Using configuration file · neoclide/coc.nvim Wiki · GitHub

:CocConfig
Install coc-json for json intellisense ?
[Y]es, [N]o:

coc 用の json extension を空気を読んで勝手に入れてくれるので既に便利である.coc 用 config における 各変数の補完もしてくれる.
f:id:nisimur:20190331112258p:plain
設定ファイルの詳細に付いては wiki か doc かソースを参照して欲しい.

各言語ごとのlanguage server の導入と設定

:CocConfiglanguageserver attr に設定を追加していけば良い.↓に各言語の json サンプルがあるので,そちらを参照して欲しい.
Language servers · neoclide/coc.nvim Wiki · GitHub

C++

clangd を使った. OSX だと llvm 入れると一緒についてくる
https://clang.llvm.org/extra/clangd/

$ brew install llvm
$ echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> ~/.zshrc

Rust

Rust Language Server (RLS) を使った
GitHub - rust-lang/rls: Repository for the Rust Language Server (aka RLS)

$ rustup update
$ rustup component add rls-preview --toolchain nightly
$ rustup component add rust-analysis --toolchain nightly
$ rustup component add rust-src --toolchain nightly
:CocInstall coc-rls

GitHub - neoclide/coc-rls: Rust language server support for coc.nvim

dockerfile

dockerfile 関係のツールは今まで入れてなかったので,この機会に入れてみた

$ npm install -g dockerfile-language-server-nodejs

オレオレ language server

既存のツールを LSP対応にするツールが最近公開されたばかりで,これを使うとかなり手軽にオレオレ language server を自作することができる.
https://mattn.kaoriya.net/software/lang/go/20190205190203.htm
efm-langserver で作る簡単 Language Server – dictav – Medium

驚いたことに cocwiki では既に efm-langserver をサポートしている.こわい.

  "languageserver": {
    "efm": {
      "command": "efm-langserver",
      "args": [],
      // custom config path
      // "args": ["-c", "/path/to/your/config.yaml"],
      "filetypes": ["vim", "eruby", "markdown"]
    }
  }

その他

とかも移行しようとしたけど疲れたし長すぎて読んでられないので今度書く(書かないかもしれない)
MPLS とか pyright も使ってみたい気がする
GitHub - Microsoft/python-language-server: Microsoft Language Server for Python
GitHub - Microsoft/pyright: Static type checker for Python

感想

pros

  • 言語ごとにバラバラだった補完プラグインを1つの LSP Client に集約できる
  • 大分 Vim Plugin 減らせた
  • 補完がめちゃくちゃ速い
  • snippet などもエディタ間で共通化できる
  • LSP Client 選びが面白い

cons

  • プラグインを集約できる代わりに環境毎に language server を都度入れる *9
  • Vim Plugin が減り,language server が増えた
  • 移行できるまでめちゃくちゃ長い
  • Vim以外のエディタを使わないのでそこまで恩恵を受けない
  • LSP Client が戦国時代すぎる(どれを使えばいいんだ)

結論

  • VSCode + nvim がメインエディタの人には coc.nvim が非常にお勧めできる
  • TypeScript + node + json なので,VimLが苦手でもデバッグしやすい
  • coc をきっかけに VSCode も使えるようになりたい

*1:と vimconf.swp で聞いた

*2:この時点で neovim 多いなという感想を抱く

*3:ale_linter を surpress する必要があった

*4:ALE は機能を増やしすぎた気がしていて,1つのプラグインは直交する機能を追加すべきでない

*5:使ったことはない. 素の vim は RPC Client ないので vim-node-lsp を別途入れる必要がありそう

*6:Hacker News で上がってきたからかも

*7:ts コードはかなり綺麗で読みやすい

*8:package.json だけ git add しておけば良さそう. ~/.config 以下を dotfiles として管理しているならこのままでも良い

*9:dotfiles 以下で一括管理するのも,あれはあれで楽だった