藻ログ

都会で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 が必要.

neovim 本体での LSP support について

余談だが neovim では built-in で LSP client を提供する計画があるらしい *1

www.slideshare.net

どの 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: Check syntax (linting) and fix files asynchronously, with Language Server Protocol (LSP) integration in Vim

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_linter と ale_lsp_linter が一部競合して煩わしく感じたり*3,速度面で不満が出てきたので ALE は 非LSPのlinter専用として使うことにした*4.

coc.nvim

後は vim-lsp と coc.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 = './install.sh nightly'
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

validation

:CheckHealth すれば,neovim の他の環境と一緒に coc の状態も確認できる
f:id:nisimur:20190503204326p:plain

現状 extension root のディレクトリが空だと coc の initialize に失敗してしまうので,$ mkdir -p ~/.config/coc/extensions しておく必要がある.

[vim-node-coc]: Error on Initialize: ENOENT: no such file or directory, open .config/coc/memos.json
" dein/repos/github.com/neoclide/coc.nvim/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 かソースを参照して欲しい.

coc extensions

Using coc extensions · neoclide/coc.nvim Wiki · GitHub
coc では,様々な extension を :CocInstall で手軽に入れることが出来る.バックエンドでは yarn を使って npm モジュールを ~/.config/coc/extensions/node_modules に入れていく挙動になる.

:CocInstall coc-python coc-tsserver
:CocList extensions

で現在インストールされているプラグインのリストを確認できる
f:id:nisimur:20190503210456p:plain

extension がない language server は

C++

$ brew install llvm
$ echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> ~/.zshrc
  • :CocConfig に設定を追加することで利用できる
  "languageserver": {
    "clangd": {
      "command": "clangd",
      "rootPatterns": ["compile_flags.txt", "compile_commands.json", ".vim/", ".git/", ".hg/"],
      "filetypes": ["c", "cpp", "objc", "objcpp"]
    }
  }

efm

既存のツールを LSP対応にするツールが最近公開されたばかりで,これを使うとかなり手軽にオレオレ language server を自作することができる.
Big Sky :: Lint ツールを Language Server に対応させるコマンド efm-langserver 作った。
efm-langserver で作る簡単 Language Server – dictav – Medium

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

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

結論

  • VSCode + nvim がメインエディタの人には coc.nvim が非常にお勧めできる(VSCode使ってません)
  • TypeScript + node + json なので,VimLが苦手でもデバッグしやすい
  • Vim Plugin の数をかなり減らせた

*1:と vimconf.swp で聞いた

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

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

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

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

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

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