🥧

Neovimでパイメニューを実現する

2021/09/25に公開

Neovimでパイメニューを実現するプラグイン piemenu.nvim を作成した。

https://github.com/notomo/piemenu.nvim

パイメニュー?

項目が円形に並ぶメニューのこと。
角度で項目を選択できる。

世に存在するパイメニューの挙動を動かして確認したい場合、
3DCGソフトのBlenderにアドオンとして存在するので参考になる。
他には https://github.com/payne911/PieMenu も参考になった。
デモページがあったり、ゲームでの使用例のgifがあったりで嬉しい。

動機

気楽なコードリーディング時には両手をキーボードに置くのが面倒で、
マウスだけを持つシーンが個人的に割とあった。
しかし、Neovimにコンテキストメニューはないのでマウスのみでは完結しない。
(キーボードで操作するエディタなので当然)

じゃあメニューバーを出せる機能(:help menus)を使うのはどうだろうと考えると、
GUI依存だし、わざわざ実装してるNeovimのGUIも見かけない。
現状neovim-qtにもない。 https://github.com/equalsraf/neovim-qt/issues/395
そもそも小さい要素を狙ってクリックするのが苦手なので雑に選択できるUIがほしい。

パイメニューだとメニューに割り当てられた角度の範囲内が全てクリック可能なので雑に選択できる。
また、以前作ったマウスジェスチャプラグイン gesture.nvim との相性も良く、
マウスジェスチャのアクションとしてパイメニューを使えば楽にマウスのみでの行動の幅を増やせるようになる。

実装

Neovim特有のテクニックはあまりなく、
エディタの領域内に含まれる範囲の円周にメニューをうまく配置するのが大変なだけ。
ただ、ちゃんと円形にするためにセルの縦横比が(等幅フォント想定で)2:1なのを考慮する必要はある。

あとインターフェースの話として、
piemenu.nvimではメニューの登録、表示のために名前を受け取るようにした。
(以下の例の場合はexample)

require("piemenu").register("example", {
  menus = {
    {
      text = "📚 help",
      action = function()
        vim.cmd("help " .. vim.fn.expand("<cword>"))
      end,
    },
  },
})

require("piemenu").start("example")

gesture.nvimではグローバルかバッファローカルなジェスチャを登録可能にしたが、
piemenu.nvimだと自由なネームスペースで登録できたほうが拡張性が高いなと考えた。
例えばファイルタイプで使いたいメニューのセットが1種類とは限らないので。

感想

Discussion