neovim で Language Server Protocol を利用してコード支援機能を実現してみる

この記事はMisoca+弥生 Advent Calendar 2019の2日目です。

先月末、 昨年に続いて、Safecast Hackathon に参加してきました。昨年のHackahtonぐらいから再開したポケモンGoはまだ細々と続けています。最近、毎週50kmの週間リワードも貰いますが、ボールが使い切れなくて困っています。

今回は、solargraph という ruby の Language Server を使って、neovim でコード補完や定義への移動をできるようにしてみましたので、その設定方法を紹介します。

Language Server Protocol (LSP) とは?

The Language Server protocol is used between a tool (the client) and a language smartness provider (the server) to integrate features like auto complete, go to definition, find all references and alike into the tool

Langserver.org  でこのように定義されています。Language Server Protocol は、コード補完、定義への移動、参照箇所の検索というようなコード支援に必要な情報を提供する言語サーバーとその情報を受け取る開発ツール(クライアント)の間のやり取りを定めたものです。

 Rubyの場合、vim-ruby (vim)、ruby-mode (emacs)、vscode-ruby (vscode) のように、コード支援機能は、開発ツールごとに実装されています。LSP を使うことで、言語サーバーがコード支援に必要な情報を提供して、開発ツールはクライアントとてして、その情報を受け取ることで、コード支援機能を提供することができるようになります。

Solargraph (言語サーバー) の設定

solargraph は、Ruby向けの言語サーバーです。コード補完やRubyの標準クラスの文書などの情報を提供します。

 

f:id:eitoball:20191202093629p:plain

solargraph は rubygem として提供されているので、gem コマンドで簡単にインストールできます。

$ gem install solargraph

デフォルトでは、ruby 2.2 向けの「core」(標準クラスのドキュメント)が同梱されています。list-cores コマンドで確認できます。

$ solargraph list-cores
2.2.2

使用しているrubyのバージョンをcoreは、download-core コマンドで取得します。available-cores で取得可能なcoreを表示することができます。

$ solargraph available-cores
2.6.1
2.6.0
2.5.3
...
$ solargraph download-core 2.6.1

download-core でバージョンを指定しない場合は、使用している(パスが通っている)rubyのバージョンにあうcoreを取得します。

プロジェクトで利用しているrubygemの文書を表示したい場合は、プロジェクトのルートディレクトリに移動して、bundle コマンドを実行します。

$ solargraph bundle

Gemfile を読み、必要な文書を取得します。

最後に config コマンドで設定ファイルを作成します。プロジェクトのルートディレクトリに移動して実行します。

$ solargraph config

実行したディレクトリに.solargraph.yml というファイルが作成されます。 Rails アプリケーションの場合、デフォルトの設定で問題ないと思います。興味がある方は、こちら を参照して下さい。

vim-lsp (クライアント)の設定

今回は、neovim で LSP クライアントとして、vim-lsp を使用します。async.vim も必要です。それぞれのプラグイン管理方法に応じた方法で2つのプラグインを追加します。

vim-lsp の Wikiページ にあるように ~/.config/nvim/init.vim に以下を追加します。

if executable('solargraph')
    " gem install solargraph
    au User lsp_setup call lsp#register_server({
        \ 'name': 'solargraph',
        \ 'cmd': {server_info->[&shell, &shellcmdflag, 'solargraph stdio']},
        \ 'initialization_options': {"diagnostics": "true"},
        \ 'whitelist': ['ruby'],
        \ })
endif

'initialization_options': {"diagnostics": "true"}, は、デバッグ用のログを出力するためなので、vim-lsp を正しく動作するように設定できたら、削除して良いと思います。。

次にコード補完のための設定をします。今回は、asyncomplete.vim を使います。このプラグインasyncomplete-lsp.vim を追加します。そして、

inoremap <silent><expr> <TAB>
  \ pumvisible() ? "\<C-n>" :
  \ <SID>check_back_space() ? "\<TAB>" :
  \ asyncomplete#force_refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"

という設定を ~/.config/nvim/init.vim に追加すれば、コード補完ができるようになります。このように文字を入力すると候補が表示されます。Ctrl-N や Ctrl-P を使って、候補から選択します。

f:id:eitoball:20191202031756p:plain

コマンドモードで:LspPeekDefinitionと入力すればカーソル上のクラスやメソッドの定義をポップアップに表示することができます。

f:id:eitoball:20191202032214p:plain

LspDefinition の場合は、定義されている場所に移動することができます。

その他の使用できるコマンドについては、ここ を参照して下さい。利用する言語サーバーによっては対応していないコマンドがあるようです。solargraph の場合、LspDeclarationLspPeekDecalation は対応していないようでした。

まとめ

solargraph と vim-lsp を使って、neovim で、LSP を利用しての ruby のコード補完や定義への移動ができるように設定をしてみました。vim でも バージョン8なら、同じように設定できるようです。

当初は、RubyMine で LSP を利用するように設定をしてみたかったのですが、試してみたところ、ruby に関しては、RubyMine のコード支援機能が協力強力で、変化がなかったため、neovim で設定をしました。

明日、Misoca+弥生 Advent Calendar 2019の3日目は、ryotaro_kawakami さんです。