Denopsでプラグインを作るときのTips
はじめに
DenopsはJavaScript/TypeScriptのランタイムであるDenoを利用してVim/Neovim双方で動作するプラグインを作るためのエコシステムです。
簡単な概要についてはありすえさんの記事を読んでほしいのですが、この記事ではDenopsを利用してプラグインを作るときに役立つTipsをいくつか紹介したいと思います。
Tips
クライアントのメタデータを取得する
今プラグインが動いているのがVimかNeovimかで分岐することはよくあるパターンでしょう。
Vim scriptではhas('nvim')
で判定しますが、Denopsでは関数を呼ぶための通信が発生するので良くありません。
かわりにdenops.meta
からメタデータを参照できます。
標準モジュールで静的型の支援を受ける
Vimの関数や変数にはdenops.call()
やdenops.eval()
からアクセスできますが、これらの戻り値はunknown
になっているためそのままでは型エラーで参照できません。
型をnarrowingするためにas
でのキャストやtypeof
演算子などを使う必要がありますが、より安全にnarrowingを行う方法があります。
Denopsの標準モジュールにはより高レベルにVimの機能を使うための関数がそろっています。
その中のfunction
モジュールはVimの組込み関数を型安全に扱うためのモジュールです。
たとえば、getreginfo()
関数は引数と戻り値に型が付いていて、結果を安全に扱えます。
また、すべての関数にはhelpから自動的に生成されたjsdocが付与されていて、helpを開かなくても説明を読むことができます。
ユーザーが定義したautoload関数の戻り値はunknown
のままですが、unknownutil
というライブラリを使うと楽に型のnarrowingができます。
Luaを経由するコードを書くときの注意
NeovimではVim scriptのかわりにLuaを使ってプラグインや設定を書くことができ、Denops製のプラグインを作るときもNeovim特有のAPIを使うために一部のコードでLuaを利用するかもしれません。
しかし、Luaで書かれた関数をDenopsから呼ぶとエラーが起きる可能性があります。
DenopsはVim/Neovimとやりとりするためにchannelというしくみを使っています(:h channel
で詳しい方法を参照できます)。
このため、Vim/NeovimとDenopsの間はJSONに変換可能なオブジェクトしか行き来ができません。
しかし、以下のようにLuaでは真偽値や関数などのnil
を除くすべての型がtable
のキーになりえます。
JSON互換でないオブジェクトを関数が返してしまうと、JSONへ変換するときにエラーが起きてしまいます。
Luaを使ったコードでよくわからないエラーが起きたら、変数の中身を確認してみてください。
local tbl = {
"number",
hoge = "string",
["fuga"] = "string",
[42] = "number",
[true] = "boolean",
[function() end] = "function",
[{ foo = false }] = "table",
[vim.NIL] = "userdata",
[coroutine.create(function() end)] = "thread",
}
tbl[tbl] = "loop"
vim.print(tbl)
まとめ
Denopsはいいぞ。
Discussion