vim-lsp の導入コストを下げるプラグイン vim-lsp-settings を書いた。

この記事は Vim Advent Calendar 2019 (vim1) 最終日のエントリです。

# はじめに

昨今、あらゆるテキストエディタやIDEが Language Server Protocol を実装してきており、各テキストエディタ/IDEがこれまで自前実装してきたコード補完や定義位置ジャンプなど、長年に渡って提供してきた機能のあり方を見直す時期に指しかかっています。

本記事では Language Server Protocol が変えつつあるテキストエディタ/IDEの未来が一体どの様な物なのか、そして Vim がこれから歩もうとしている道は明るいのか、最後に今回皆さんに初めてご紹介する vim-lsp-settings というプラグインについて説明します。

# Language Server とは

皆さんは Language Server という物をご存知でしょうか。

https://langserver.org/

Language Server Protocol は、各種プログラミング言語とテキストエディタ/IDEとの間で交換される JSON-RPC 仕様とそれにより実現される機能を指します。テキストエディタ/IDEなど Language Server Client から送信される「コード補完」や「リネーム」、「定義位置ジャンプ」といったエディタ固有の機能要求に対し、演算を行い結果応答を返す Language Server の 1:N の関係で構成されます。

![lsp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665/22078f79-866d-62c9-fa74-a64bf675c250.png)

Language Server はテキストエディタ/IDEから、扱うプログラミング言語毎に起動され、デフォルトでは標準入出力で JSON-RPC を使い通信します。

https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/

通信仕様として定義されている為、Language Server Client と Language Server の開発者は別であっても構いません。Go言語専用の Language Server「gopls」は Visual Studio Code からも使えますし、Vim や Emacs からも使えます。また Language Server は通信相手が Vim/Emacs なのか、はたまた Visual Studio Code なのかを問う必要もありません。

現在では色々なプログラミング言語に対応する Language Server が、そのプログラミング言語のコミュニティやその言語の開発者グループ自身によって開発されています。また Language Server Protocol を実装するテキストエディタやIDE(Language Client)も次第に増えて来ました。

2019年、現在の Language Server Protocol の[バージョン 3.14](https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/) で定義されている代表的な機能は以下の通りです。

|機能名           |説明            |
|-----------------|----------------|
|Code completion  |コード補完      |
|Diagnostics      |診断            |
|Hover            |ホバー          |
|Jump to def      |定義ジャンプ    |
|Workspace symbols|シンボル一覧    |
|Find references  |参照ジャンプ    |
|Code Action      |コードアクション|

これら全ての機能は、テキストエディタと Language Server との間で JSON-RPC を使い、ソースコード本体、コード補完候補、座標情報などを交換する事で実現されています。

![diagnostics.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665/37fbd37c-25a7-d6cf-a067-ba66537d93ff.png)

# 温故知新

実は Language Server Protocol は OmniSharp というソースコード補完サーバがベースとなっています。

https://github.com/microsoft/language-server-protocol/wiki/Protocol-History

OmniSharp は元々、Vim で C# のコードを補完する為に作られた Vim プラグインでした。当時は Vim が curl コマンドで通信できる様に REST サーバとして作られていました。それを Microsoft が双方向の通信を行える様に通信仕様を JSON-RPC に定め、汎用化の為に仕様として策定した物が現在の Language Server Protocol です。

Language Server Protocol は Visual Studio Code に実装された事をトリガに、色々なテキストエディタやIDEで実装され、Language Server も数多く登場しました。

https://microsoft.github.io/language-server-protocol/implementors/servers/

Language Server の良い所は、これらの Language Server がテキストエディタやIDEの独自仕様に依存していない事、Language Server のバグがそれ自身の修正のみで対応可能である事などがあります。そしてそのバグ修正や改良は、ただ1つのテキストエディタやIDEに還元されるのではなく、世界中のユーザに恩恵を与える事ができるのです。

# Vim における Language Server 事情

Vim にも Language Server Client を実装したプラグインが既に沢山あります。

* [vim-lsp](https://github.com/prabirshrestha/vim-lsp/)
* [vim-lsc](https://github.com/natebosch/vim-lsc)
* [LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim)
* [coc.nvim](https://github.com/neoclide/coc.nvim)
* [ale](https://github.com/dense-analysis/ale)
* [vim-go](https://github.com/fatih/vim-go)

各プラグインにより特色もあり、操作感が異なっていたり、機能の実装有無もあります。多くの Vim プラグインは、Vim script の貧弱な言語仕様を補う為に、Vim と Language Server とを中継するサーバを設けて通信しています。また一部のプラグインは Vim の言語拡張(Python や Ruby、Perl 等を使って Vim を拡張する仕組み)を使っています。そして幾らかのプラグインは、Vim script だけで書かれています。

筆者はこのうち Prabir Shrestha 氏が開発する vim-lsp のメンテナを担当しており、機能追加やバグ修正などを行っています。pull-request もお待ちしています。vim-lsp の大まかな特徴を書いておくと

* Pure Vim script (余計なインストール物がない)
* 非同期 (固まらない)
* テキストの差分送信 (速い)
* asyncomplete や asyncomplete-lsp 等と連携可能 (カスタマイズ度高い)

というウリがあります。

# Vim の Language Server 界が抱える問題

いずれの Language Server Client もそうなのですが、以下の様な似た問題を抱えています。

* Language Server のインストールそのものが難しい
* インストールした Language Server を Vim に登録するのが難しい

## Language Server のインストールそのものが難しい

特定のプログラミング言語に対応する Language Server はおおよそそのプログラミング言語自身で書かれています(そうでない物もあります)。ですので Language Server をインストールする為にはそのプログラミング言語自身のインストールと、Language Server のインストールの両方を行う必要があります。時には手間がかかる事もある為、こういった作業になれていない方には苦痛でしかありません。

## インストールした Language Server を Vim に登録するのが難しい

Language Server を Vim から使える様にする為には、Vim に Language Server を登録する必要があります。そしてその為には Vim script を書かなければなりません。Vim になれた人であれば問題ないのですが、慣れていない人には苦痛でしかありません。

これらの問題は、今後 Vim で Language Server を扱いたい人に常に降りかかってきます。

# Vim の未来

筆者は 2018 年に開催された VimConf 2018 のアンケートボードで、参加者の方の多くが Language Server に興味を持っている事を知りました。ちょうど同じ頃に Prabir Shrestha 氏からメンテナになる事を提案された筆者は、それから1年ほど vim-lsp の動作で問題になっていた Windows 固有の Vim 本体の問題を1つずつ修正していきました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">去年の VimConf 2018 で参加者の皆さんから vim の Language Server に対する期待の言葉を頂いてから、Windows に高速な channel が入り、popup が入り、vim-lsp も改良されて、あの頃の vim と比較して大きく変わった感がある。 <a href="https://t.co/jAkXTLBtsO">pic.twitter.com/jAkXTLBtsO</a></p>&mdash; mattn (@mattn_jp) <a href="https://twitter.com/mattn_jp/status/1169050678175485952?ref_src=twsrc%5Etfw">September 4, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

2年前の Vim ではこの速度が出せなかったのですから、随分と進捗したなぁと本記事を書きながら思いました。

これらの対応がなされたとしても、前述の問題が解決する訳ではありません。

> どうすれば Vim の Language Server が皆に使って貰える様になるんだろう


この問題について何日か考え「Visual Studio Code はなぜあんなに簡単に Language Server を扱えているのか」という疑問を自分なりにまとめました。それは Visual Studio Code が以下の機能を提供しているからだと考えました。

* ダウンロード可能な Language Server
    * 簡単にインストールでき
    * 設定ファイルを書く必要もない
* 特定のプログラミング言語のファイルを開いたら拡張を提案される

これらの機能が Vim には全くなかったのです。

そこで今回、vim-lsp-settings というプラグインを作る事になりました。

# vim-lsp-settings は設定ファイル要らず

https://github.com/mattn/vim-lsp-settings

今回作った Vim プラグインには、設定は必要ありません。ソースコードを開いたら「拡張がインストール可能である事」を提案され、コマンド1つ実行するとそれだけで Language Server が使える様にする為の物です。

まずは動画をご覧ください。

![vim-lsp-settings](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665/cf9f1866-a04c-ca57-499a-95a21a2c427a.gif)

ファイルを開くと拡張のインストールを提案され、コマンド1つ実行したらそのまま Language Server が使えています。これが「テキストエディタ Vim の進むべき道」だと筆者は考えました。

現在、以下の Language Server がインストール可能になっています。

| Language   | Language Server                                             | Local Install |
|------------|-------------------------------------------------------------|:-------------:|
| C/C++      | clangd                                                      | No            |
| C#         | omnisharp                                                   | Yes           |
| Clojure    | clojure-lsp                                                 | Yes           |
| TypeScript | typescript-language-server                                  | Yes           |
| JavaScript | javascript-typescript-langserver/typescript-language-server | Yes           |
| Python     | pyls                                                        | Yes           |
| Rust       | rls                                                         | No            |
| Go         | gopls                                                       | Yes           |
| Ruby       | solargraph                                                  | Yes           |
| PHP        | intelephense                                                | Yes           |
| Java       | eclipse-jdt-ls                                              | Yes           |
| Lua        | emmylua-ls                                                  | Yes           |
| Vim        | vim-language-server                                         | Yes           |
| Bash       | bash-language-server                                        | Yes           |
| Terraform  | terraform-lsp                                               | Yes           |
| Dockerfile | dockerfile-language-server-nodejs                           | Yes           |
| YAML       | yaml-language-server                                        | Yes           |
| XML        | lsp4xml                                                     | Yes           |
| Fortran    | fortls                                                      | Yes           |
| Scala      | Metals                                                      | Yes           |
| Elm        | elm-language-server                                         | Yes           |
| JSON       | json-languageserver                                         | Yes           |
| Swift      | sourcekit-lsp                                               | No            |
| COBOL      | cobol-language-support                                      | Yes           |


vim-jp slack におられる皆さんから、沢山コードを寄与して頂きました。ありがとうございます。

Local Install が Yes になっている物は、Language Server のインストールに必要なコマンド(npm や yarn、java、go 等それぞれ異なります)さえ入っていれば、環境を汚す事なくインストール可能になっています。これらは UNIX だけでなく、Windows でも使える様になっています。

現在、未だ絶賛開発中の為、今後しばらくはソースをガチャガチャと変更する事があると思いますが、安定する様になれば「Vim は Visual Studio Code の様に誰でも簡単に Language Server を使える様になる」と言って良いと思っています。

# おわりに

Language Server Protocol とはどんな物かを簡単ながら説明しました。また、テキストエディタやIDEが今後どの様に進化するのか、そして vim-lsp-settings が現状の Vim をどの様に変えるのかを説明しました。Vim を起源として生まれた Language Server Protocol が今度は Vim そのものを変えようとしています。この未来は Vimmer にとっても明るい物だと信じています。気が向いたらぜひ vim-lsp-settings の開発にご参加下さい。

今後予定している機能としては以下の物があります。

* Language Server のバージョンチェック
* Language Server の更新処理

さて、今年も無事 Vim Advent Calendar を完走する事が出来ました。お疲れさまでした。普段 Slack で話題を提供して下さったり質問に答えて頂いている皆さんにより来年も Vim コミュニティは活発であるに違いありません。来年もよろしくお願い致します。