Pythonの補完環境をjedi-vimからvim-lspに移行した話¶
VimでPython書いてますか?
長らくPythonの補完用プラグインとして davidhalter/jedi-vim を使用してきましたが、 あの mattn (@mattn_jp) さんがCollaboratorになった prabirshrestha/vim-lsp や palantir/python-language-server がいよいよ実用的になってきたので移行してみました。
とはいえ実際に使うにはまだ設定するところもちょこちょこあるので、一度まとめておこうと思います。
前提とする環境¶
Vim: 8.0以上、かつコンパイルオプションで jobs, timer, channel, lambda が有効になっている
Python: 2.7もしくは3.4以降 (pyenvやAnacondaでインストールしたPythonは考慮しない)
Note
VimでPython/Python3インターフェースを有効にする必要があるかもしれませんが、少なくともドキュメントには記載されていませんでした。もし必要な場合は以前書いたVimとPythonの補完についてのメモを参照してください。
その後Python/Python3インターフェースを無効にした状態で試したところ、問題なく動作しました。外部インターフェイスに依存せず補完や定義ジャンプができるのはいいですね。
LSP(Language Server Protocol)とは¶
ざっくりいうと自動補完や定義ジャンプ、ドキュメントのホバー表示などエディタごとに実装していた機能を、言語Serverを用意して複数の開発ツールで使えるようにしましょうというものです。LSPを活用することでエディタのプラグインなどは最小限の労力で言語をサポートできるようになります。
各エディタ用にLSPを使うプラグインや機能を用意する必要がありますが、補完機能をサポートするサーバーが共通化できるのでそのServerが便利になると1つのエディタだけでなく複数のエディタで活用できるメリットがあります。
どのようなプロトコルでどのように通信しているのかは、 Microsoftが公開しているドキュメント が詳しいのでそちらを参照してください。 Software Design 2018年3月号 にも詳しく書いています。(残念ながら紙の書籍は2019/01/26現在在庫がないようです)
LSP導入¶
Python用のLanguage ServerとClientとなるVimプラグインを導入します。ServerとClientは以下になります。
Language Server: palantir/python-language-server
Client: prabirshrestha/vim-lsp
Language Serverの導入¶
python-language-server
をpipコマンドを使ってインストールします。
どこからでも使えるようにグローバルな環境に入れますが、macOSやLinuxを使っている人は注意する必要があります。
OSが使うPythonに様々なライブラリが入っており、無理やりインストールしようとすると後で困る可能性があるからです。
ここではユーザーディレクトリにインストールすることでその問題を回避します。
以下のPATHにインストールされるので、予め ~/.bash_profile
などに PATH
の設定を追加しておいてください。
インストールされる箇所は site.USER_BASE によって決まります。
Windows:
%APPDATA%\Python
macOSで www.python.org からPythonをインストールした場合:
~/Library/Python/X.Y/bin
(X.YはPythonのバージョン)macOSでHomebrewを使いPythonをインストールした場合:
~/.local/bin
Ubuntuの場合:
~/.local/bin
ターミナルを開き以下のコマンドを使いインストールします。
$ pip install --user python-language-server
インストールが完了したら $ which pyls
などでLanguage ServerにPATHが通っていることを確認してください。
インストールに失敗したり、whichコマンドで何も出力されない場合、 PATH
の設定がうまく言っていない可能性があるので確認してみてください。
pipコマンドを実行した結果でもわかりますが、 python-language-server
はこれまでもPythonの自動補完や静的解析で使われていた davidhalter/jedi をLSPで使えるようにしたものです。フォースの魂は脈々と受け継がれるようですね。
Clientの導入¶
vim-lspは依存で prabirshrestha/async.vim が必要なので合わせてインストールします。 私は junegunn/vim-plug を使用しているので、以下のようにvimrcに記述します。
" vimrc
Plug 'prabirshrestha/vim-lsp'
Plug 'prabirshrestha/async.vim'
Vimを開いたまま :so $MYVIMRC のようにして設定の変更を読み込み、 :PlugIntall するとプラグインをインストールできます。
Vimプラグインの設定¶
ServerとClientとなるVimプラグインは導入しましたが、実際に連携するには設定が必要です。以下のようにvimrcに追記します。
" vimrc
" デバッグ用設定
let g:lsp_log_verbose = 1 " デバッグ用ログを出力
let g:lsp_log_file = expand('~/.cache/tmp/vim-lsp.log') " ログ出力のPATHを設定
" 言語用Serverの設定
augroup MyLsp
autocmd!
" pip install python-language-server
if executable('pyls')
" Python用の設定を記載
" workspace_configで以下の設定を記載
" - pycodestyleの設定はALEと重複するので無効にする
" - jediの定義ジャンプで一部無効になっている設定を有効化
autocmd User lsp_setup call lsp#register_server({
\ 'name': 'pyls',
\ 'cmd': { server_info -> ['pyls'] },
\ 'whitelist': ['python'],
\ 'workspace_config': {'pyls': {'plugins': {
\ 'pycodestyle': {'enabled': v:false},
\ 'jedi_definition': {'follow_imports': v:true, 'follow_builtin_imports': v:true},}}}
\})
autocmd FileType python call s:configure_lsp()
endif
augroup END
" 言語ごとにServerが実行されたらする設定を関数化
function! s:configure_lsp() abort
setlocal omnifunc=lsp#complete " オムニ補完を有効化
" LSP用にマッピング
nnoremap <buffer> <C-]> :<C-u>LspDefinition<CR>
nnoremap <buffer> gd :<C-u>LspDefinition<CR>
nnoremap <buffer> gD :<C-u>LspReferences<CR>
nnoremap <buffer> gs :<C-u>LspDocumentSymbol<CR>
nnoremap <buffer> gS :<C-u>LspWorkspaceSymbol<CR>
nnoremap <buffer> gQ :<C-u>LspDocumentFormat<CR>
vnoremap <buffer> gQ :LspDocumentRangeFormat<CR>
nnoremap <buffer> K :<C-u>LspHover<CR>
nnoremap <buffer> <F1> :<C-u>LspImplementation<CR>
nnoremap <buffer> <F2> :<C-u>LspRename<CR>
endfunction
let g:lsp_diagnostics_enabled = 0 " 警告やエラーの表示はALEに任せるのでOFFにする
vim-lspは警告やエラーの表示などもできますが、そちらは w0rp/ale に寄せているため機能を無効化しています。 ALEについては 2018年版Life ChangingだったVimプラグインTOP3 に書きましたのでそちらを参照してください。
vimrcに記載したら保存、終了します。
使用感について¶
jedi-vimと比べたときのメリット/デメリットを書いていきます。
メリット¶
高速化されたのが一番大きいですね。
Vimの起動が高速化できた(Ubuntu環境で100〜150ms、macOS環境でも200〜300ms短縮)
補完候補がでる時間が高速化できた
発展途上の技術なので進化を体験していける
他の言語と使用できるプラグインを共通化できるため、vimrcからプラグインを減らせた
デメリット¶
まだ発展途上というところからきてると思うのですが、少しだけ今までできていたことができない感じがあります。
言語用のServerが別途インストールが必要なので環境を壊さわないようにするのに気を使う。
jedi-vimはjediを
git submodule
で独立して入れていたので楽だった。
Vimを起動後に
:setf python
しても補完や定義ジャンプが動かない。既存のPythonファイルを開いたり、
$ vim hoge.py
などすると動くが、少し気になる。
リネームが不安定(動かない?)
動かすには python-rope/rope が必要という情報もあるがそれでも動かない
jedi-vimはじゃじゃ馬だったり、マルチバイト文字が対象行に混じっていると動かなかったりしたが….