ryota2357

denops.vimでvimscriptの関数をtypescriptに渡したかった

投稿日:

vim プラグインを作ってる時、vimscript で作った匿名関数を typescript に渡して任意のタイミングで typescript から実行したい時があった。
他の変数と同じように denops#notify() とかで渡すと、関数は null になってしまう。

結論から言うと、直接関数を渡す方法はわからなかった。しかし、denops#callback#register()denops#callback#call() を用いると、id を経由することやりたいことはできた。

それぞれ、help を引用しておく。

denops#callback#register()
denops#callback#register({callback}[, {options}])
       Register {callback} to internal callback map as an anonymous function
       and return an unique {id} to call the {callback} later.
       The following attributes are available on {options}.
denops#callback#call()
denops#callback#call({id}[, {args}...])
        Find a callback of {id} from internal callback map and call it with
        given {args} and return a result. It throw an error when no {id}
        callback exists.
        Note that the callback called is automatically removed from the
        internal callback map if "once" option had specified.

こんな感じで使える。

typescript 側は次のように id を受け取る。

export function main(denops: Denops): void {
  denops.dispatcher = {
    async addFunc(funcId: unknown): Promise<void> {
      const id = unknown.ensureString(funcId);
      const ret = await denops.call("denops#callback#call", id, "hoge");
      console.log(ret);
    },
  }
}

vimscript 側では、id を生成して渡す。

function! somePlug#addFunc(func) abort
  let l:id = denops#callback#register(a:func)
  call denops#notify('somePlug', 'addFunc', [l:id])
endfunction

次のように期待通りの動作をする。

:call somePlug#addFunc({ arg -> arg . '!!'})
[denops] hoge!!