Neovimでバッファを管理するプラグインを作った
こんにちは!皆さんはVimのマルチバッファ機能は使っていますか?今回は、Neovimのバッファをファジーファインダで管理するプラグインを作ったので、その紹介をします。
VimのBuffer機能
Neovimには、バッファを管理するためのコマンドがいくつか用意されています。例えば、:ls
でバッファ一覧を表示したり、:b
コマンドでバッファを切り替えたりできます。これらのコマンドは大変シンプルで、バッファが少ないうちは使えると思います。
しかし、大規模なプロジェクトの開発をしているとバッファは増えてしまうものです。気付いたらバッファが数十個になっていた、なんてザラですよね。Vim以外のエディタを使ったことがある人ならタブ機能がよく使われると思いますが、Vimにおいてはバッファ機能がメジャーです。タブよりもUIが煩雑にならないシンプルな仕組みで、個人的には気にいっていますが、
- 一覧されることがなく、自然にバッファが増えていく
- 切り替えや整理にIDを覚える必要がある
といった使いにくさが残っています。
「残っています」と言ったのは、そもそもバッファの仕組みはタブに比べて、ユーザー寄りというよりは設定でプログラムしやすい方に寄っているものだからです。他のVim標準機能と同様、そもそも設定で各ユーザーが使いやすい仕組みにしやすいことが強みです。
既存のプラグイン
整理しやすくするための既存のプラグインも以下のように沢山あります。今回作成したプラグインはこういったものの1つということになります。
これらではなく、今回新規に作成した理由です↓
- 自分が普段使っているファジーファインダ
gw31415/fzyselect.vim
を使いたかった-
telescope.nvim
は入れたくない
-
- バッファを削除するオペレータが欲しかった
- 別にタブのような表示をしたい訳ではない
上記の gw31415/fzyselect.vim
については、以前にも記事を書いていますので、興味があればご覧ください。
実装
実装したこと/しなかったこと
今回実装したのは以下の通りです。基本的な機能ですね。
- バッファの一覧表示
- バッファを選択して開く
- バッファを削除するオペレータ
一方、以下の機能や設計では実装していません。
- ファジーファインダを入れ替え可能な設計
- 自身が普段使っていないファジーファインダのAPIを知らないため
-
vim.ui.select
のAPIのみでの実装ができなかったため、自身でfzyselect
のAPIを拡張して作っています
- バッファのグループ化
- 自身はバッファ管理の基本機能のみで十分なため
- タブのような表示
- 自身が必要としていないため
実装内容
プラグイン本体はこちらです↓
fzyselect#start
の引数は基本的に vim.ui.select
のスーパーセットとして作っています。頭の整理のために、実装に必要な機能を以下のように分けましょう。
-
vim.ui.select
でできる機能- 呼び出し前に事前処理する
- 標準引数で指定する
-
vim.ui.select
でできない機能- 独自機能で実装する
事前処理
まず、 fzyselect#start
を呼び出す前にできることをリストアップします。
- 操作するウィンドウのIDを取得する
- バッファの一覧を取得する
- バッファリストを並べ替える
bufmanager#open
を呼び出す部分の実装は以下のようになっているのですが、44-46行目でこれらの処理をしています。
標準引数で指定する内容
先ほどのコードの49-52行目で、fzyselect#start
に渡す引数を指定しています。
これらは、vim.ui.select
の引数とほぼ同じで、 bufnr
から表示する行へのフォーマット、バッファ選択後のバッファ移動コールバックを指定しています。
- 第一引数
-
s:bufs
: 事前処理でフィルター&ソートしたbufnr
のリスト
-
- 第二引数
-
format_item
:bufnr
から表示する行へのフォーマット - (
prompt
:fzyselect
独自; 今回は無視してください)
-
- 第三引数
- バッファ選択後のバッファ移動コールバック
独自機能でしかできないこと
最後に、vim.ui.select
で実現できなかった機能について説明します。
残った機能はバッファの削除ですが、これは vim.ui.select
には用意されていない以下の機能がファジーファインダー側に必要になります。
- UI表示中のアイテム取得
- UI表示中のアイテム更新
削除用オペレータを実装する際、各行に何のアイテムがあるか逆引きする必要があります。また、バッファ一覧がUIを閉じる前に変更されますが、この時に更新が必要になります。これらは一般的な vim.ui.select
には用意されていないため、ファジーファインダー毎に実装を変更する必要があります。
fzyselect
においては、これらはそれぞれ fzyselect#getitem
および fzyselect#refresh
という関数で用意しています。
オペレータの実装は以下の通りです。
そして、オペレータを fzyselect
バッファが開いた autocmd
で設定することで実現しているわけです。
最後に
今回は自分の需要に合わせてバッファ管理プラグインを作成しましたが、よかったら今回の記事の内容を元にあなたオリジナルのバッファ管理機能を作成してみてください。オペレータの作成部分や、vim.ui.select
の部分、バッファ管理周辺のNeovim APIは流用しやすいと思います。Vimの良いところは自分の好みに合わせてカスタマイズできるところですからね。
Discussion