🐜

Denopsでプラグインを作るときのTips

2023/06/26に公開

はじめに

DenopsはJavaScript/TypeScriptのランタイムであるDenoを利用してVim/Neovim双方で動作するプラグインを作るためのエコシステムです。
簡単な概要についてはありすえさんの記事を読んでほしいのですが、この記事ではDenopsを利用してプラグインを作るときに役立つTipsをいくつか紹介したいと思います。

https://zenn.dev/lambdalisue/articles/b4a31fba0b1ce95104c9

Tips

クライアントのメタデータを取得する

今プラグインが動いているのがVimかNeovimかで分岐することはよくあるパターンでしょう。
Vim scriptではhas('nvim')で判定しますが、Denopsでは関数を呼ぶための通信が発生するので良くありません。
かわりにdenops.metaからメタデータを参照できます。

https://github.com/vim-denops/denops.vim/blob/v5.0.0/denops/%40denops/denops.ts#L13-L27

標準モジュールで静的型の支援を受ける

Vimの関数や変数にはdenops.call()denops.eval()からアクセスできますが、これらの戻り値はunknownになっているためそのままでは型エラーで参照できません。
型をnarrowingするためにasでのキャストやtypeof演算子などを使う必要がありますが、より安全にnarrowingを行う方法があります。

Denopsの標準モジュールにはより高レベルにVimの機能を使うための関数がそろっています。
その中のfunctionモジュールはVimの組込み関数を型安全に扱うためのモジュールです。
たとえば、getreginfo()関数は引数と戻り値に型が付いていて、結果を安全に扱えます。
また、すべての関数にはhelpから自動的に生成されたjsdocが付与されていて、helpを開かなくても説明を読むことができます。

ユーザーが定義したautoload関数の戻り値はunknownのままですが、unknownutilというライブラリを使うと楽に型のnarrowingができます。

https://deno.land/x/unknownutil@v3.2.0

Luaを経由するコードを書くときの注意

NeovimではVim scriptのかわりにLuaを使ってプラグインや設定を書くことができ、Denops製のプラグインを作るときもNeovim特有のAPIを使うために一部のコードでLuaを利用するかもしれません。
しかし、Luaで書かれた関数をDenopsから呼ぶとエラーが起きる可能性があります。

DenopsはVim/Neovimとやりとりするためにchannelというしくみを使っています(:h channelで詳しい方法を参照できます)。
このため、Vim/NeovimとDenopsの間はJSONに変換可能なオブジェクトしか行き来ができません。

https://github.com/vim-denops/denops.vim/wiki/Sequences

しかし、以下のように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はいいぞ。

GitHubで編集を提案

Discussion