はじめに
popup_menu()
のコールバックに(globalに置くような無茶な渡し方などをせずに)上手く追加で値を受け渡す方法を探していて、一つ答えが見つかったのでそのシェアになります。
自分が困ったケース
Vim scriptで選択肢のユーザーインターフェースといえばinputlist()
があったと思いますが、最近の機能追加でpopup_menu()
が追加され、ポップアップメニューの中からユーザーに選ばせるという選択も増えました。
自分のプラグイン(spelunker.vim)もこれまでinputlist()
を使っていたのですが、今回新たにpopup_menu()
も利用できるように修正を行おうと思ったのですが、下記のような問題があり、これまでのinputlist()
をそのまま置き換えるような修正はできなさそうでした。
これまでのinputlist()の実装例
" ユーザーが選ぶfunction select(arg)letl:list =['111','222','333']letl:selected = inputlist(l:list)" このあとl:selectedを使ってなんかするendfunction
popup_menu()を使う場合の実装例
function select(arg)" ユーザーが選ぶとコールバックが呼ばれるletl:list =['111','222','333']call popup_menu(l:list, #{ \ callback:'callbackFunction', \ pos:'topleft', \ line:'cursor+1', \col:'cursor' \})endfunctionfunction calbackFunction(id, selected)" a:selectedを使ってなんかするendfunction
ポップアップメニュー選択後、コールバックが呼び出されるようになります。
こうなってくるとselect()
の関数内で持っている変数で(a:arg
など)、このあとの処理でも使いたい変数はどうやってcalbackFunction()
に受け渡せばいいのか...などなど、これは設計にも影響してきそうです。
コールバックに追加で引数を渡す
こちらの記事のクロージャの項目の内容的なアプローチを取ってみます。
https://vim-jp.org/vim-users-jp/2010/08/13/Hack-167.html
" argをコールバックに渡したい!functions:select(arg)" 記事中のクロージャの項目の内容的なアプローチ" https://vim-jp.org/vim-users-jp/2010/08/13/Hack-167.htmlletl:callback ={'arg':a:arg}functionl:callback.funcall(id, selected) dict
call Popup_callback(a:id,a:selected, self.arg)endfunctionletl:list =['111','222','333']call popup_menu(l:list, #{ \ callback:l:callback.funcall, \ pos:'topleft', \ line:'cursor+1', \col:'cursor' \})endfunctionfunction Popup_callback(id, selected,arg)" ここでもs:select()のarg(a:arg)を使える!endfunction
引数が上手く追加できましたね。
また、これは簡単にするとこうにもなります。
functions:select(arg)letl:callback ={'arg':a:arg}functionl:callback.funcall(id, selected) dict
" callbackとしてやりたかった内容をここに移動します" self.argもa:id, a:selectedも使えますendfunctionletl:list =['111','222','333']call popup_menu(l:list, #{ \ callback:l:callback.funcall, \ pos:'topleft', \ line:'cursor+1', \col:'cursor' \})endfunction
これで一応、popup_menu()
の呼び出し元のスコープにある変数の受け渡しができました🙌