VimにおけるLSPやデバッガの使い方
この記事はLayerX Tech Advent Calendar 2022 の16日目の記事です。LayerXのバクラク事業部で機械学習エンジニアをしている @yoppiblog です。 現在は、OCRチームで帳票を読み取る機械学習モデルの開発をしています。 今回は、主にOCRチームで使われている、バックエンド側のプログラミング言語における、Vimでの開発を効率化する
- Language Server Protocol
- デバッガ
周りの話を簡単に紹介できればと思います。
Language Server Protocol
LSP が策定されてからというものの、Vimでもその恩恵に預かり定義元へのジャンプやコード補完など、IDEと遜色ない機能を使えるようになりました。 VimでLSPを喋る場合、 vim-lsp がありますが、今回は、 coc-nvimについて紹介します。
coc.nvim
cov.nvim
は vim-lsp
と同様にLSPをサポートするプラグインです。
Vim Scriptではなく、Node.jsで実装されており、vim-lspより高速だと感じており個人的に一番のメリットだと思います。また、jsonファイルでプロジェクト毎に柔軟にカスタマイズ可能な点も使いやすいです。
加えて、オムニ補完をとくに設定を細かくすることもなく、いい感じに補完してくれるのも嬉しい点です。
.nvim
とsuffixがついていますが、Vimでも利用できます(nvim特有の機能に依存する機能は使えないですが...)。
環境構築
インストールは各々使っているプラグインマネージャで完結します。
" using vim-plug Plug 'neoclide/coc.nvim', {'branch': 'release'}
また、各言語のLanguage Serverはこちらを参考にインストールします。
https://github.com/neoclide/coc.nvim/wiki/Language-servers
Pythonでは coc-jedi
(裏ではjediが動く) を、Goだと coc-go
(裏ではgoplsが動く) が使いやすいプラグインになります。
:CocInstall coc-jedi coc-go
環境によってはうまく jedi-language-server
が動かない場合もあるため、その場合は手動でインストールして使うようにすると良いでしょう。
:CocConfig " coc.nvimの設定ファイルを開く
{ "jedi": { "enable": true, "startupMessage": false, "executable.command": "~/.pyenv/shims/jedi-language-server" } }
使い方
READMEに書いてある通り、 .vimrc
に記述すればすぐに使えるようになりますが、重要なポイントはKey mappingです。
プログラミング中、常にコード定義を見に行ったり、renameしたり、参照元を探したり、、、という作業を頻繁にするため自分の使いやすいKey mappingを定義すると良いでしょう。
" e.g. Key mappings nmap <silent> <C-]> <Plug>(coc-definition) nmap <silent> <C-[> <C-o> nmap <silent> gy <Plug>(coc-type-definition) nmap <silent> gi <Plug>(coc-implementation) nmap <silent> gr <Plug>(coc-references) nmap <silent> gn <Plug>(coc-rename) inoremap <silent><expr> <C-m> coc#pum#visible() ? coc#_select_confirm() : "\<C-m>"
デバッガ
ソフトウェアを開発する上で一番必要になるのは、個人的にデバッガだと思っています。 単純なprintデバッグで解決するシーンもあると思いますが、深く原因究明するためにはデバッガで状態を確認することで早期に解決できると考えています。
Pythonにおけるデバッガ
Pythonでは、 IPython が提供している機能を使うと一番楽です。 標準添付ライブラリに pdb があるのですが、より直感的で使いやすいものがIPythonになります。
ブレークポイントを設定したい場所に、
from datetime import datetime from dateutil import parser from IPython import embed def parse(arg: str) -> datetime: dt = parser.parse(arg) embed() return dt parse("2022-12-16")
と embed
関数を埋め込み、通常実行するだけで任意の場所でデバッグできるようになります。
# IPythonのreplが動く In [1]: dt Out[1]: datetime.datetime(2022, 12, 16, 0, 0)
Goにおけるデバッガ
Goでのデバッガは delve がよく使われています。
他のIDEでのデバッガもdelve
を元に実装されています。
Vimから使うためには vim-delve が使いやすくておすすめです。
delveのインストール後、
$ go install github.com/go-delve/delve/cmd/dlv@latest
vim-delve
をインストールします。
" using vim-plug Plug 'sebdah/vim-delve'
よく使うコマンドとして、
- :DlvAddBreakpoint ブレークポイントのセット
- :DlvRemoveBreakpoint ブレークポイントの解除
- :DlvClearAll 全てのブレークポイントとトレースポイントをクリア
- :DlvToggleBreakpoint ブレークポイントのon・offの切り替え
- :DlvDebug デバッグ実行
があります。
下記の例は、10行目に DlvAddBreakpoint
でブレークポイント設定したのち、 DlvDebug
で実行した場面です。
デバッガが起動し、変数の確認など可能になります。
> main.main() ./time.go:10 (hits goroutine(1):1 total:1) (PC: 0x1028bf9b0) 5: "time" 6: ) 7: 8: func main() { 9: date, err := time.Parse("2006-01-02", "2022-12-16") => 10: if err != nil { 11: panic(err) 12: } 13: fmt.Printf("date:%v\n", date) 14: } (dlv)
終わりに
Vimでの開発環境を少し紹介しました。IDEのほうが機能が盛りだくさんで使いやすいシーン(特にデバッグ周り)は多いと思いますが、 必要な機能を自分で取捨選択してカスタマイズできるエディタは、それはそれで使いやすいと感じています。