fzfのkey bindingまとめてみた


## :first_quarter_moon_with_face: はじめに

fzf起動中の `Ctrl-j` 押したら `選択カーソル下移動`。とかのキーバインドについてまとめる記事です

[junegunn/fzf: A command-line fuzzy finder](https://github.com/junegunn/fzf)
[man page](https://www.mankier.com/1/fzf#)

![fzf-0.22.0](https://img.shields.io/badge/fzf_version-0.22.0-<COLOR>)

## :memo: 仕組み
[man](https://www.mankier.com/1/fzf#Key/Event_Bindings)にある通り `Key/Evnet`（Ctrl-A）に対して、`Action`（行頭に移動）が設定されている
zshのwidgetみたい

設定可能なKeyに関しては [こちら](https://www.mankier.com/1/fzf#Key/Event_Bindings-Available_Keys:_(Synonyms))
`--bind` オプションで`KEY:ACTION` または `EVNET:ACTION`形式で記述することでカスタマイズが可能
複数指定の場合はカンマ区切り

```shell:
fzf --bind=ctrl-j:accept,ctrl-k:kill-line
```
また `ACTION`を `+` で繋げて記述することで、複数のACTIONをチェーンすることができる


## :evergreen_tree: Event
Key以外にも `Event` をバインドすることができる。利用可能なEventとして `change`と `backward-eof`がある

### change
検索文字(以下query)が変更されるたびにトリガーされる

```shell
# queryを変更するたびにtopアクションを実行
fzf --bind change:top
```

### backward-eof
query が空のときに、後方削除を実行しようとしたときにトリガーされる

```shell
fzf --bind backward-eof:abort
```


## :musical_keyboard: Key Bindings

デフォルトで割り当てられてるKeyとActionの一覧
おなじみのemacs風キーバインドなので、慣れてる人は読み飛ばし推奨
toggle系に関しては複数選択mode（--multi）時のみ有効

#### 基本操作

| Bind Keys                   | Action      | 説明                                 |
| --------------------------- | ----------- | ------------------------------------ |
| Enter (Double-click)        | accept      | 選択実行                             |
| C trl-c (Ctrl-g Ctrl-q Esc) | abort       | fzfを閉じる                          |
| Ctrl-j (Ctrl-n  Down)       | down        | 選択カーソルを下に移動               |
| Ctrl-k（Ctrl-p  Up）        | up          | 選択カーソルを上に移動               |
| Ctrl-i  (Tab)               | toggle+down | 行をマークして選択カーソルを下に移動 |
| Shift-Tab                   | toggle+up   | 行をマークして選択カーソルを上に移動 |



#### 移動

| Bind Keys            | Action            | 説明                    |
| -------------------- | ----------------- | ----------------------- |
| Ctrl-b（Left）       | backward-char     | カーソルを左に移動      |
| Ctrl-f（Right）      | forward-char      | カーソルを右に移動      |
| Ctrl-a（Home）       | beginning-of-line | カーソルを先頭に移動    |
| Ctrl-e（End）        | end-of-line       | カーソルを行末に移動    |
| Alt-b（Shift-left）  | backward-word     | カーソルを1単語左へ     |
| Alt-f（Shift-right） | forward-word      | カーソルを1単語右へ移動 |



#### 削除

| Bind Keys        | Action               | 説明                                                   |
| ---------------- | -------------------- | ------------------------------------------------------ |
| Ctrl-h（Bspace） | backward-delete-char | カーソル前の文字を削除                                 |
| Ctrl-u           | unix-line-discard    | カーソルから行頭までを削除                             |
| Ctrl-w           | unix-word-rubout     | カーソル前の単語を削除                                 |
| Ctrl-d           | delete-char/eof      | カーソル上の単語を削除<br>queryが空の場合はfzfを閉じる |
| Alt-Bspace       | backward-kill-word   | カーソル前の単語を削除                                 |
| Alt-d            | kill-word            | カーソル上の文字から単語末尾までを削除                 |
| Del              | delete-char          | カーソル上の単語を削除                                 |



#### 画面操作

| Bind Keys  | Action       | 説明                           |
| ---------- | ------------ | ------------------------------ |
| Ctrl-l     | clear-screen | 画面をクリアに(これ動いてんのか？)        |
| PgDn       | page-down    | 下向きにスクロール             |
| PgUp       | page-up      | 上向きにスクロール             |
| Shift-up   | preview-up   | プレビュー画面を上にスクロール |
| Shift-down | preview-down | プレビュー画面を下にスクロール |

## :flag_ac: Actionの紹介
デフォで割り当てられてないAction達
色々ありますが、いくつか抜粋してみる


### jump, jump-accept
EasyMotionのような選択カーソルの移動ができる
![jump.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138236/6aa2e240-487d-cf83-5d55-70b407925750.gif)

### toggle-all
全件選択/全件解除 のtoggle。select-allだと解除したいとき困るよ
![toggle-all.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138236/a92adbfb-3c94-e750-3faf-a644151e9ed2.gif)


### execute(...)、 execute-silent(...)
fzfを閉じずに任意のコマンドを実行する。 `{}` で選択行を引用できる
`execute-silente`は画面切り替えなしでコマンドを実行

```shell
fzf --bind "enter:execute(less {})"
```
これで、 「`ctrl+v`でvimで開く, `ctrl+o`でopen」 みたいに実行を振り分けたかったけどできない


### preview, toggle-preview
`--preview` で指定したコマンドに加えて、別のプレビューコマンドを指定できる

```shell
# デフォルトプレビューウィンドウで ls -lの結果を表示。?でファイル内容を表示
fzf --preview 'ls -l {}' --bind '?:preview:cat {}'
```
![preview.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138236/bf0be472-e325-2d29-d8e5-658847a4479e.gif)
※ `--preview`を指定しない場合は プレビューウィンドウが空で表示される

**toggle-preview** ではプレビューウィンドウの表示/非表示の切替を行う
こっちのほうが使い勝手がいいかも

### reload

リストを**動的に**更新する
manで紹介されているコマンドが中々良さげだった

```shell
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
INITIAL_QUERY="foobar"
FZF_DEFAULT_COMMAND="$RG_PREFIX '$INITIAL_QUERY'" \
  fzf --bind "change:reload:$RG_PREFIX {q} || true" \
      --ansi --phony --query "$INITIAL_QUERY"
```

queryを変更したら都度 `rg` コマンドが実行される
検索ブラウザのできあがり。検索結果、検索文字のハイライトが動的に更新される

## :speech_balloon: ひとこと
この記事では触れてないけど `--preview` も奥が深めです
独自に関数作ったり、組み込みwedgetをカスタマイズしたとき等 参考になれば幸いです