Neovimとcoc.nvim構成でコード保存時にdeno fmtを実行する
はじめに
自分はTypeScript(Node.js)でサーバサイドをNeovimで書くことが多く、補完やコード整形にcoc.nvim
とそのプラグインであるcoc-tsserver
やcoc-prettier
を利用しています。
最近趣味でNeovimでDenoを書いていると、.ts
拡張子が同じため、保存時にPrettierが実行されてしまう問題がありました。これは自分のNeovimの設定の影響です。DenoはCLI自体にビルドインのフォーマッターが搭載されており、保存時にdeno fmtが実行されて欲しいです。
vim.api.nvim_command("autocmd BufWritePre *.ts,*.tsx :Prettier")
command! -nargs=0 Prettier :CocCommand prettier.forceFormatDocument
coc.nvimは、以下のようにプロジェクトルートに設定ファイルを用意すれば、tsserverやprettierを無効にしてdenoのLSPを有効にすることが出来ます。これでPrettierが実行されることは無くなります。
{
"deno.enable": true,
"deno.lint": false,
"deno.unstable": true,
"deno.config": "deno.json",
"tsserver.enable": false,
"prettier.enable": false
}
もちろんこれではコード整形が何も走らないので開発体験が悪いです。本記事ではこの状態からdenoのファイル保存時にdeno fmt
が走るようにするところを目指します。
プラグイン開発
shuntaka9576/deno-fmt.vimというプラグインを作ってみました。これはcoc.nvimのLSPの利用状態をチェックして、denoのLSPが引っ掛かったら、deno fmt
を実行するというものです。denops.vimを利用しています。
この処理で、deno
が存在しない場合は何もしません。なので普通にTS(Node.js)でコードを書いている場合は何もしません。(実行すらしないのが理想ですが、方法がわからず、こうしています)
denoのLSPの起動が確認できたら、バッファの内容を取り出しtmpファイルに書き出しdeno fmtで整形します。
整形済みのdenoファイルと整形していないdenoファイルでdiffをとり、差分をもとにバッファを書き換えます。undo redoログが変にならないように、batch.collect
でアトミックかつシーケンシャルに処理します。
こんな感じで整形されます。
そのほか
-
echo 'ソースコード' | deno fmt -
で標準入力を使う方法を考えましたが、おそらくエスケープまわりで苦戦し見送りました。 -
NO_COLOR=0 deno fmt --check
差分出力が可能ですが、表示が正しくないケースがあり、見送りました。 -
.vim/coc-settings.json
がモノレポに対応しているわけではないので、フロントエンドとDenoのプロジェクトが混合している場合は、手間ですが、オプションを都度反転させる必要があります。
cat .vim/coc-settings.json | jq '.["tsserver.enable"] = (.["tsserver.enable"] | not) | .["prettier.enable"] = (.["prettier.enable"] | not) | .["deno.enable"] = (.["deno.enable"] | not)' | tee .vim/coc-settings.json
最後に
TS(Node.js)を書いているときの保存時のオーバーヘッドが高くなった気もしており、改善の余地がありそうです。また、もっと楽にできる方法はありそうな気はしています。。
参考
vim-goimportsから、diffをとってバッファを書き換える方法を知りました。他にもいろんな配慮があり、よりソースを読んで理解を深めたいです。
余談
DenoFestに参加してからDenoのモチベーションが高く、自分のブログのサーバサイド(APIGateway Lambda構成)をDeno Deployに置き変える活動をしようとしていました。
Discussion