bs.el を拡張してミニバッファを見やすくする

# はじめに

その昔，`cycle-buffer.el` がありました．`(buffer-list)` で得られるバッファリストを対象として， `M-[` や `M-]` の押下でバッファを高速に切り替えることができる，とても便利なパッケージでした．このパッケージのおかげで，タブを常用せずに済んでいました．

しかし，時は流れ，ビルトインの `bs.el` に同等の機能が実装されていることから，現在はあまり使われていないようです．私も移行したユーザの一人です．

# 問題

`bs.el` を使用する場合は，`bs-cycle-previous` と `bs-cycle-next` に `M-[` と `M-]` など，好みのキーをアサインすると幸せになれます．

```emacs-lisp
(global-set-key (kbd "M-]") 'bs-cycle-next)
(global-set-key (kbd "M-[") 'bs-cycle-previous)

(with-eval-after-load "bs"
  (custom-set-variables
   '(bs-cycle-configuration-name "files-and-scratch")
   '(bs-max-window-height 10))
```

ところが，ミニバッファに表示されるリストが非常にわかりにくい．特に，たくさんのバッファを開いている時には，とても辛くなります．「5つくらい先のバッファだから，`M-]`を5回連打して，あ，押しすぎた」という悲しい出来事を幾度となく経験しました．

![Screen Shot 2019-12-07 at 3.47.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12232/aa8e1ca4-ea00-e9ed-78cd-376e663fb66a.png)
↑ 開いている17バッファ全部見せの図

# bsv.el を使う

ということで，`bs.el` のミニバッファの表示を少し見やすくするパッケージを作りました．

[bsv.el](https://github.com/takaxp/bsv)

正式リリース前ですが，安定しています．基本的に，`bs.el` の関数に advice をかけるパッケージですので，読み込みは次のようにします．

```emacs-lisp
(with-eval-after-load "bs"
  (when (require 'bsv nil t)
  ;; bsv の設定を記述する
  ))
```

`bsv.el` を無効化するには，`M-x bsv-disable-advices` とします．`bs.el` の素の振る舞いに戻ります．また再度 `bsv.el` を有効にする場合は，`M-x bsv-enable-advices` とすればOKです．

そして，`bsv.el` が有効の状態で以前と同様に `M-]` (bs-cycle-next) を押下すると，次のようになります．

![Screen Shot 2019-12-07 at 3.47.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12232/2fa98f86-8818-41ef-3e3a-482f9af9a2cf.png)

`M-[` (bs-cycle-previous) だと，こうです．格段に見やすくなった！（個人の感想です）

![Screen Shot 2019-12-07 at 3.47.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12232/ae1cab94-5de0-db26-59cc-65eb8a7a8ca6.png)

このように，`bsv.el` を読み込むことで，`ivy-mode` のような縦方向のリスト表示になります．ミニバッファに表示されるリストには，番号が付いています．これは，もう一度同じ方向にずらす時の順位を表しています．例えば上の例では，あと3回 `M-[` を連打すれば， `.emacs` が表示されます．

## ダイレクト選択

先程の例では， `M-[` を3回連打で `.emacs` を表示できるとしましたが， `bsv.el` では `3` 押下でダイレクトに `.emacs` を表示することができます．ミニバッファにリストが表示されている間は， `1` から `9` までの数値キーとバッファの番号が紐付けられます．したがって，例えばリストに「5. init.el」とある場合に，`M-[`または`M-]`を5回連打しなくても良く，`5`を1回押下するだけでバッファを切り替えられます．下のアニメーションはダイレクト選択機能のデモです．

![a.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12232/c469658e-fc14-5e0a-0b34-b411bf515095.gif)

## オプション

色々と好みが分かれそうなので，いくつかを `defcustom` に引き出しておきました．

| 変数 | デフォルト値 | type | 説明 |
|-----|----|----|----|
| bsv-message-timeout | 5 | integer | この秒数後にミニバッファの表示が無効化します |
| bsv-slant | t | boolean | バッファ名を斜めにリスト表示します |
| bsv-max-height | 9 | integer | ミニバッファに表示するリストの最大数です．10以上を指定しても，9に補正されます |
| bsv-switch-by-key | 'number | symbol |ダイレクト選択の方法です．デフォルトは数値キーですが，この変数を 'function にすると，`<f1>`や`<f2>`等のファンクションキーの押下でバッファを選択できます． `nil` 指定で，ダイレクト選択機能をオフにできます |
| bsv-lighter | "Bsv" | string | ライターです．bsv-message-timeout の時間が経過すると，モードラインから自動的に消えます |
| bsv-show-countdown | t | boolean | 表示が無効化するまでの時間をモードラインでカウントダウンします |

なお実際にミニバッファに表示するバッファ数は，`bsv-max-height` の値に依らず，フレームの高さに応じて自動的に調整しています．フレームの高さが低い時は，1-2個程度しかミニバッファに表示されないかもしれません．これもユーザオプションにしても良いかもしれませんね．

# 今後の改良

次のような機能追加を考えています．

- [ ] もっとジョグダイアルのようにする（現在のバッファを表示リストの中心に持ってくる）
- [ ] all-the-icons に対応して，ファイルアイコンを出してもっと見やすくする
- [X] バッファが消えるまでの時間をモードラインでカウントダウンする

# まとめ

`bs.el` を拡張する `bsv.el` を紹介しました．