Neovimでpopup-menuを実装できるプラグイン


Neovim用のpopup-menuを実装できるプラグインを作りました

Vim8にはpopup_menu()という関数があり、ユーザー独自のpopup-menuを利用した機能を作ることができるのですが、これまで残念ながらNeovimには同じ機能は実装されていませんでした。

これは時々問題になることがあります。例えば、プラグイン作者が軽い気持ちでpopup_menu()を利用すると、Neovimではpopup_menu()に相当する機能がないため、Neovimで全く同じ機能を実装するのは一苦労することになります。

今回これを解決すべく、popup-menu.nvimというプラグインを作成しました。

利用イメージ

見た目はこんな感じです。

さほどVimのpopup-menuと見た目は遜色ないかと思います(実装者の主観入り)

使う場合はこんな感じです。

let l:list = ['aaa', 'bbb', 'ccc', 'ddd', 'eee']
call popup_menu#open(l:list, {selected -> s:my_callback(selected)})

コールバックの指定にはlambdaを利用してください。

細かくカスタマイズしたい場合には第3引数にnvim_open_win()と同じ第3引数で利用するconfパラメータを渡すことが可能です。

call popup_menu#open(
        \ l:list,
        \ {selected -> s:my_callback(selected)},
        \ {
        \   'relative': 'editor',
        \   'width': 30,
        \   'height': 7,
        \   'col': 5,
        \   'row': 5
        \ })

Vimのpopup_menu()との使い方

このプラグインはVimのpopup_menu()をいい感じに呼んでくれるようなことはしていないので、ifなどでVim用とNeovim用で処理を分けてください。
自分は下記のようにVimとNeovimで処理を分けています。

if exists('*popup_menu')
    " Vim
    call popup_menu(...)
elseif has('nvim') && exists('g:loaded_popup_menu_plugin') 
    " Neovim
    " popup-menu.nvimの中で g:loaded_popup_menu_plugin が定義されています
    call popup_menu#open(...)
else
    " Old vim/neovim
    let l:selected = inputlist(...)
    " callbackを呼ぶ
endif

プラグインの中身の話

実装には一部Golangを利用しています。
github.com/marcusolsson/tui-goを利用しており、Neovimのfloating-windowで起動したterminalを通してGolangのバイナリを実行して、選択肢を実現しています。

選択肢を実現するためのライブラリは色々試したのですが、一番見た目がpopup_menu()に近い実装ができたのがTUIライブラリであるtui-goでした。
(他のライブラリだとSelect >みたいなpromptが出ていて消せなかったり、CLI用の配慮で余計に最下行に空行が入ってしまったりで結構ライブラリ選択に詰まったりしてました...)

というわけで、プラグインの利用に際してなにかNeovimでセットアップが必要になるわけではないのですが、作者がバイナリを用意していないアーキテクチャについては動作しませんので、必要に応じてIssueなりプルリクなりたてていただければ助かりますmm

現状、Mac、Linux、Windowsに対応しています。(※手元にWindowsが無いため、Windowsでは未検証...)
https://github.com/kamykn/popup-menu.nvim/blob/5390df3e281cea1f229c773c40d72f7165f663cd/src/Makefile

Vimのpopup-menuと違う点

  • 見た目の差異は多少あります(ボーダーとか)。
  • あとは、「スペースキーで選択」できないというのも地味に本家とは異なります。
  • floating-windowの中でterminalが起動しているという点で、壊そうと思えば壊れてしまうので優しく扱ってあげてください...🥺

自分が解決したかったこと

ちなみになぜこれを作ったかというと、冒頭で述べたとおりまさにプラグインでpopup-menu()を利用してNeovimで対応できない問題に悩んでいました...。(Neovim早くpopup_menu()実装してくれーと願いつつ)

というわけで、もしNeovimでpopup_menu()が実装されれば即このプラグインはdeplecatedになるわけですが、その日まではこのプラグインでしのいでもらいましょう。

というわけで、同じ悩みをお持ちであればぜひ本プラグインを使ってみてください〜✌️