neovimにLSPを使ったpython補完プラグインを導入してみた

2020.06.11

こんにちは、DA事業部の岩澤です。

数年前、neovimにLSPを使ったpython補完プラグインの導入をやってみたのですが、うまくいかず見なかったことにして一旦保留していました。
久しぶりに調べてみたら色々と導入方法が増えているようなので、再挑戦してみました。

LSPについて

言語サーバー プロトコルの概要 - Visual Studio | Microsoft Docs

言語サーバー プロトコル (LSP) は、開発ツールと言語サーバー プロセスの間で交換されるメッセージを標準化する製品です。 言語サーバーや悪魔を使用することは、新しいアイデアや斬新なアイデアではありません。 VimやEmacsのような編集者は、セマンティックオートコンプリートサポートを提供するためにしばらくの間これを行ってきました。 LSP の目的は、このような統合を簡素化し、言語機能をさまざまなツールに公開するための便利なフレームワークを提供することです。

テスト環境

  • Windows 10
  • WSL(Ubuntu 18.04.4 LTS)
  • neovim v0.5.0-539-g91e41c857 (neovimはdein導入済み(plugin定義はtoml))

python用の言語サーバのの導入

最初に言語サーバと必要なモジュールを導入します。
といっても特別なことは何もなく、pip等で以下のモジュールをインストールすればOKです。
(neovimの設定で仮想環境を参照するようにしている場合は、その仮想環境にインストールします)

  • python-language-server
  • pynvim

neovim側のプラグイン導入

次にneovim側の設定です。
いくつかのパターンがありますが、今回は以下の2パターン

  1. coc.nvimを使う
  2. vim-lspとasyncompleteを使う

を試してみました。

1. coc.nvimを使う

coc.nvimはvimをVSCodeのようなIDEにするためのプラグインです。
これひとつで大体そろうのが特徴となっています。

利点としては、導入が簡単でありvim側の設定が最低限ですむ上に、デフォルトでもいい感じに設定されることです。
欠点としては 動作にnode.jsが必要なのことでしょうか。

(1) node.jsのインストール

WSL上で動かすので、node.jsの公式よりlinux-x64版を取得してPATHを通します。
(私は本体を適当な場所に配置して、/usr/local/binにsymbolic linkを設定しています)

$ cd /usr/local/bin
$ sudo ln -nfs /mnt/c/work_iwa/home_ubuntu/dl_tools/nodejs/node-v12.18.0-linux-x64/bin/node

(2) vimのプラグインの設定

'neoclide/coc.nvim'を追加するだけでOKです。

[[plugins]]
repo = 'neoclide/coc.nvim'
on_ft = ['python']
merged=0
rev="release"
hook_source = '''
source ~/.config/nvim/plugins/coc.rc.vim
'''

coc.rc.vimには公式の設定サンプルを参考にkeymapを設定しています。

" Use `[g` and `]g` to navigate diagnostics
nmap <silent> [g <Plug>(coc-diagnostic-prev)
nmap <silent> ]g <Plug>(coc-diagnostic-next)

" GoTo code navigation.
nmap <silent> <C-]> <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
nmap <silent> gr <Plug>(coc-references)

nnoremap <silent> K :call <SID>show_documentation()<CR>

function! s:show_documentation()
  if (index(['vim','help'], &filetype) >= 0)
    execute 'h '.expand('<cword>')
  else
    call CocAction('doHover')
  endif
endfunction

(3) coc-pythonのインストール

インストール後、neovimでpython形式のファイルを開き。以下のコマンドを実行します。

:CocInstall coc-python

Linterについて聞かれますので、自分の環境に合わせて選択します。
(今回は1のインストールを選択しました)

これで環境構築完了です。これは簡単。

動作中の画面です。こんな感じで補完候補を出したりヘルプを出してくれたりします。便利!

2. asyncomplete.vim とvim-lspを使う

次に、aysncompleteとvim-lspを使った導入を試してみます。

(1) neovimにプラグインを導入する

neovimに数個プラグインを導入します。

[[plugins]]
repo = 'prabirshrestha/asyncomplete.vim'
on_ft = ['python']

[[plugins]]
repo = 'prabirshrestha/async.vim'
on_ft = ['python']

[[plugins]]
repo = 'prabirshrestha/vim-lsp'
on_ft = ['python']
depends = ['async.vim', 'vim-virtualenv']
hook_source = '''
source ~/.config/nvim/plugins/vim-lsp.rc.vim
'''

[[plugins]]
repo = 'ryanolsonx/vim-lsp-python'
on_ft = ['python']
depends = ['vim-lsp']

[[plugins]]
repo = 'prabirshrestha/asyncomplete-lsp.vim'
on_ft = ['python']

vim-lsp.rc.vimは以下の通りです。
※g:python3_host_progにはneovim用の仮想環境のpythonのパスを設定しています。

" vimrc
" vim-lspの各種オプション設定
let g:lsp_signs_enabled = 1
let g:lsp_diagnostics_echo_cursor = 1
let g:lsp_virtual_text_enabled = 1

let s:pyls_path = fnamemodify(g:python3_host_prog, ':h') . '/'. 'pyls'

if (executable('pyls'))
    " pylsの起動定義
    augroup LspPython
        autocmd!
        autocmd User lsp_setup call lsp#register_server({
      \ 'name': 'pyls',
      \ 'cmd': { server_info -> [expand(s:pyls_path)] },
      \ 'whitelist': ['python'],
      \ 'workspace_config': {'pyls': {'plugins': {
      \   'pycodestyle': {'enabled': v:true},
      \   'jedi_definition': {'follow_imports': v:true, 'follow_builtin_imports': v:true},}}}
      \ })
    augroup END
endif

nnoremap <C-]> :<C-u>LspDefinition<CR>
nnoremap K :<C-u>LspHover<CR>
nnoremap <LocalLeader>R :<C-u>LspRename<CR>
nnoremap <LocalLeader>n :<C-u>LspReferences<CR>
nnoremap <LocalLeader>f :<C-u>LspDocumentDiagnostics<CR>
nnoremap <LocalLeader>s :<C-u>LspDocumentFormat<CR>
set omnifunc=lsp#complete

以上で導入終了です。

動かすとこんな感じになります。

coc.nvimによる導入と比較すると、
利点としてはneovimのプラグインおよびpythonのモジュールの導入でOKなこと、
欠点としてはneovimに複数のプラグイン導入が必要で設定ファイルが膨らむこと、設定が最低限のためカスタマイズ必須なことでしょうか。
(ここら辺は好みに分かれるところ)

あとがき

というわけで、複数パターンでneovimにlspサーバによるpython補完を導入してみました。
これでneovimでの快適なプログラミングライフがさらに愉快に過ごせそうで楽しみです。
なお他のパターンもあったのですが設定に失敗してしまったので再挑戦予定です。

それから、導入に失敗するととことんはまるので、時間に余裕があるときに導入することをおすすめします。
(何時間かかったっけな...?)

参考文献

coc.nvimを使ってvimをもっと強くする - Qiita
NeovimでモダンなPython環境を構築するv2(LSPを添えて) - Qiita
Install coc.nvim · neoclide/coc.nvim Wiki
neoclide/coc-python: Python extension for coc.nvim, fork of vscode-python