この記事は Go の編集環境について書いていません。昨日書いた、ぼくがかんがえたさいきょうの Vim のこうせい 2019年 年末版は、僕個人の好みに依存するため一緒に書くべきではないですし、おすすめするつもりも無いです。IDE 機能の説明だけ欲しいと思う方もいるでしょうし、また純粋に Go の編集環境だけの説明が欲しいと思う方もいると思ったからです。
はじめに
以前からも「Vim はテキストエディタではない IDE だ」と言われる事は割と多かったのですが、昨今 Language Server Protocol の登場により本当に Vim を「テキストエディタ」と呼べなくなってきてしまう状況になりつつあります。
これまで Vim は、ctags でタグを生成し、Vim から定義位置ジャンプを行い、フォーマットコマンドを使ってファイルを整形してきました。これはとてもうまく行きました。ctags は多くの各種プログラミング言語をサポートしていますし、taglist の様なプラグインを使えば tags ファイルを読み込んでシンボルリストを表示する事もできます。Vim 標準の機能を伝えばタグスタックも使えます。対応していない言語についてはそれ専用の tags 生成プログラムを探せば良いですし、フォーマットコマンドもそれ専用の物を探してくればよかったのです。
しかしこれをずっと繰り返してきた Vim の設定ファイルは一体どの様な物になっていったでしょうか。個々のプラグイン専用の設定項目が散乱し、プラグイン毎にスタイルの異なった設定を行う必要があり、それ専用のタグ生成コマンド、整形コマンドを用意する時間を捻出しなければなりませんでした。入力補完については色々な言語毎に異なる仕様に悩まされるばかりでした。
結局、僕が行き着いた先は「消しやすい Vim の構成」でしたが、この消しやすい Vim の構成であっても、各プログラミング言語毎に用意すべきツール類をまとめる事は出来ませんでした。
Language Server Protocol の登場
そこにやってきたのが Language Server Protocol です。Language Server を導入する事で、各言語に対する定義位置ジャンプや入力補完のインタフェースが統一され、Vim の設定はある程度統一される様になりました。元々の Vim を「昭和」、各プログラミング言語向けのプラグインが氾濫していた頃を「平成」と例えるなら、ようやく Vim は「令和」になったと言って良いと思います。それでも問題が全て消え去った訳でありません。Language Server を導入する為にはその言語に対する知見が必要です。「このプログラミング言語を触ってみたいな」と思った人が定義位置ジャンプや入力補完、ソースファイル整形といった、最近の IDE であればあって当然の機能を得るには、Language Server を導入する為の知見が必要でした。そこで筆者は先日、vim-lsp-settings というプラグインを作りました。
vim-lsp の導入コストを下げるプラグイン vim-lsp-settings を書いた。 - Qiita
これら全ての機能は、テキストエディタと Language Server との間で JSON-RPC を使い、ソースコード本体、コード補完候補、座標情報などを交換する事で実現されています。 温故知新 実...
https://qiita.com/mattn/items/e62b9f16bc487a271a7f
vim-lsp を利用するには
このプラグインを導入する事で、そのプログラミング言語について詳しくない人でもコマンド1発で入力補完や定義位置ジャンプやソースコード整形といった「IDE 機能」を得る事ができる様になります。やるべき事は2つ
- vim-lsp とその動作に必要なプラグインを入れる事
- vim-lsp-settings を入れる事
ファイルを開いて拡張機能のインストールを提案されたら :LspInstallServer
を実行するだけなのです。これだけで以下のプログラミング言語の IDE 機能が得られるのです。
Language | Language Server | Local Install |
---|---|---|
C/C++ | clangd | No |
C# | omnisharp | Yes |
Clojure | clojure-lsp | Yes |
TypeScript | typescript-language-server | Yes |
JavaScript | typescript-language-server | Yes |
JavaScript | javascript-typescript-stdio | 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 |
Reason | reason-language-server | Yes |
TeX | texlab | Yes |
TeX | digestif | No |
Nim | nimls | No |
D | dls | No |
Elixir | elixir-ls | Yes |
Groovy | groovy-language-server | Yes |
Go 言語の IDE 機能を得る為に何か知る必要はありません。Java の IDE 機能を得る為に何か知る必要はありません。HTML の IDE 機能をインストールする為に npm コマンドの使い方を覚えたり、LaTeX の IDE 機能をインストールする為に、配置場所を考える必要もありません。もしインストールを実行しても動かなかったら、それは vim-lsp-settings のバグです。
以前まででれば vim-lsp を導入すると Language Server の登録が必要でした。
if executable('gopls')
au User lsp_setup call lsp#register_server({
\ 'name': 'gopls',
\ 'cmd': {server_info->['gopls']},
\ 'whitelist': ['go'],
\ })
autocmd BufWritePre *.go LspDocumentFormatSync
endif
その為、新しい Language Server を導入する度に以下の様な設定が増えていき、設定ファイルがどんどん増えてしまっていました。それが vim-lsp-settings の導入により、その殆どを消し去る事ができました。以下が僕の ~/.vim/_config/200-lsp.vim
です。
if empty(globpath(&rtp, 'autoload/lsp.vim'))
finish
endif
function! s:on_lsp_buffer_enabled() abort
setlocal omnifunc=lsp#complete
setlocal signcolumn=yes
nmap <buffer> gd <plug>(lsp-definition)
nmap <buffer> <f2> <plug>(lsp-rename)
inoremap <expr> <cr> pumvisible() ? "\<c-y>\<cr>" : "\<cr>"
endfunction
augroup lsp_install
au!
autocmd User lsp_buffer_enabled call s:on_lsp_buffer_enabled()
augroup END
command! LspDebug let lsp_log_verbose=1 | let lsp_log_file = expand('~/lsp.log')
let g:lsp_diagnostics_enabled = 1
let g:lsp_diagnostics_echo_cursor = 1
let g:asyncomplete_auto_popup = 1
let g:asyncomplete_auto_completeopt = 0
let g:asyncomplete_popup_delay = 200
let g:lsp_text_edit_enabled = 1
サーバ登録に関する物は無くなりました。let を設定している箇所は、vim-lsp およびそれに必要なプラグインの動作を変更する物です。人によっては好ましくない物もあるので皆さんの好きな様に変更頂くのが良いです。
lsp_diagnostics_enabled
はファイルの変更に伴いリアルタイムにエラー表示する機能 Diagnostics を有効にする設定、asyncomplete_auto_popup
および asyncomplete_auto_completeopt
は自動で入力補完ポップアップを表示する設定、asyncomplete_popup_delay
はポップアップを表示するまでのディレイ、lsp_text_edit_enabled
は LSP の仕様である textEdit を有効にする設定です。この lsp_text_edit_enabled
に関しては少し実験的な実装になっている為、もし誤動作する様であれば 0 に設定するのが良いです。
vim-lsp-settings も合わせて vim-lsp を使いたいのであれば以下を vimrc に記述します。
Plug 'prabirshrestha/asyncomplete.vim'
Plug 'prabirshrestha/asyncomplete-lsp.vim'
Plug 'prabirshrestha/vim-lsp'
Plug 'mattn/vim-lsp-settings'
Plug 'mattn/vim-lsp-icons'
Plug 'hrsh7th/vim-vsnip'
Plug 'hrsh7th/vim-vsnip-integ'
vim-lsp-icons
はソースコードにエラーがあった際にアイコンでエラー表示をしてくれる為のプラグインです。また Language Server の中には、穴あき形式で補完候補を返してくる物もあり、これをうまく対応してくれるのが vim-vsnip
です。
これだけ設定して、上記の 200-lsp.vim
を有効にしておけば、おおよその Language Server が正しく動作し、F2 キー(または :LspRename
)でシンボルのリネーム、gd で定義位置ジャンプ、:LspDocumentFormat
でソースコード整形、gVim を起動したらアイコンでエラー表示がされる様になります。
これを導入する事で、これまで C# の補完の為に導入していた omniSharp-vim や、tags ファイルで定義位置ジャンプを行っていた rust.vim の様な言語専用のプラグイン、それに必要な rustfmt といったツール類を消し去る事ができました。
僕が現在、言語専用に入れているプラグインは Vim のデフォルト syntax では対応しきれていない物に対応させる為に入れている数種類のプラグインだけになりました。
おわりに
昨日書いた、ぼくがかんがえたさいきょうの Vim のこうせい 2019年 年末版とは別に Vim をモダンな IDE にする為の設定を説明しました。人によっては、Vim の設定管理方法が僕とは違うが IDE 機能は欲しいと思われる方もいるだろうと思いましたので、別記事で書かせて頂きました。
昨今、僕が Vim に望んでいるのはこういった氾濫してしまった設定ファイル類をプラグイン等により減らす方向に向かって欲しいという事です。これらの整理なくしては、次の時代に対応できなくなってしまいます。できればプラグイン固有の設定すら書かなくても良い時代になる事を願っています。
最後に、これとは別に僕が「Go 言語の編集でこれだけは外せない」と思っている物を後日書きたいと思います。
さて、あと数時間で 2019 年も終わりです。今年も色々な方にお世話になり、色々な活動をする事ができたと思っています。皆さまに感謝しつつ、来年もまた皆さんのお役に立てられる情報を発信して行けたらと思います。来年も宜しくお願い致します。