【fzf】ターミナル上でファイル名検索と全文検索をPreview付でやりたい



エディタ・IDE等によくある検索機能をfzfでつくってみよう記事

ファイル名検索は fzfで用意されているKeyBind(**Ctrl＋T**)をカスタマイズします
 `$(brew --prefix)/opt/fzf/install` したときに自動で設定してくれるあれです
widget関数の詳細は `/usr/local/opt/fzf/shell/key-bindings.zsh` で確認できます



**注書きみたいなの**

- 記事内で外部コマンド( `bat`,`rg`, `fd`)使ってます
- `macOS`, `zsh`での動作しか確認してないです

[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>)  ![zsh-5.8](https://img.shields.io/badge/zsh_version-5.8-<COLOR>)

## その前に :tea:

私のfzf default optionです。
`--height` は指定ありのほうが見やすくて好きです。

```shell:.zshrc
export FZF_DEFAULT_OPTS="
    --height 90% --reverse --border
    --prompt='➜  ' --margin=0,1 --inline-info
    --tiebreak=index --no-mouse --filepath-word
    --color fg:-1,bg:-1,hl:33,fg+:250,bg+:235,hl+:33
    --color info:37,prompt:37,pointer:230,marker:230,spinner:37
    --bind='ctrl-w:backward-kill-word,ctrl-x:jump,down:preview-page-down'
    --bind='ctrl-z:ignore,ctrl-]:replace-query,up:preview-page-up'
    --bind='ctrl-a:toggle-all,?:toggle-preview'
"
```

bindkeyの設定については [ :point_right_tone2: こちら](https://qiita.com/sho-t/items/1ec7419b50e20dd0457e)

改行ありTextが個人的に嫌だったので実際には配列、連想配列を使って記述してます
つまりこう↓

```shell:.zshrc
# fzf
export FZF_COMPLETION_TRIGGER=','
typeset -Tgx FZF_DEFAULT_OPTS fzf_default_opts " " 
fzf_default_opts=(
  '--height=90%'
  '--reverse'
  '--border'
  '--inline-info'
  '--prompt="➜  "'
  '--margin=0,2'
  '--tiebreak=index'
  '--no-mouse'
  '--filepath-word'
)

() {
  local -A color_map=(
    [fg]='-1'
    [bg]='-1'
    [hl]='33'
    [fg+]='250'
    [bg+]='235'
    [hl+]='33'
    [info]='37'
    [prompt]='37'
    [pointer]='230'
    [marker]='230'
    [spinner]='37'
  )

  for x in "${(k)color_map[@]}"; do
    fzf_color_opts+=("${x}:${color_map[${x}]}") 
  done
  fzf_default_opts+=( '--color="'"${(j.,.)fzf_color_opts}"'"' )
}

() {
  local -a fzf_bind_opts=()
  local -A bind_map=(
    [?]='toggle-preview'
    [ctrl-a]='toggle-all'
    ['ctrl-]']='replace-query'
    [ctrl-w]='backward-kill-word'
    [ctrl-x]='jump'
    [ctrl-z]='ignore'
    [up]='preview-page-up'
    [down]='preview-page-down'
  )

  for x in "${(k)bind_map[@]}"; do
    fzf_bind_opts+=("${x}:${bind_map[${x}]}")
  done
  fzf_default_opts+=( '--bind="'"${(j:,:)fzf_bind_opts}"'"' )
}
```

連想配列の記述がversion5.5以上のzshじゃないと読み込めないです
普通に平文でもおｋ

**見た目はこんな感じ**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138236/2ace3d65-601d-5659-0f49-5132a294f239.png)


## ファイル名検索 :memo: 

デフォルトの動きは「カレントディレクトリ配下のファイル・ディレクトリを検索」です

今回は以下のようにカスタマイズしたいと思います

- デフォルトコマンドを`fd`に変更。検索対象はファイルのみに
- 選択なかったら自動終了、1件のみの場合は自動で選択
- プレビューの表示 （`bat`コマンド使う）
- 開く (できれば別ペインで) 
- 隠しファイルの表示切替

**記述がこちら**

```zsh:.zshrc
export FZF_CTRL_T_COMMAND="fd --type f "
export FZF_CTRL_T_OPTS="
    --select-1 --exit-0
    --bind 'ctrl-l:execute(tmux splitw -h -- nvim {})'
    --bind '>:reload($FZF_ALT_C_COMMAND -H -E .git )'
    --bind '<:reload($FZF_ALT_C_COMMAND)'
    --preview 'bat -r :100 --color=always --style=header,grid {}'"
```

**こんな具合になります**
![ctrl-t.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138236/57b1bd68-2090-96e6-0f63-9911a9f51bc3.gif)

## 全文検索 :mag:

カレントディレクトリ配下のファイルを全文検索。選択したファイルをコマンドラインに貼り付ける

manにある記述を参考にしてます
queryを変更するたび `rg` で検索が走ります


**作ったもの**

```shell:fzf-ripgrep-widget
#!/usr/bin/env zsh

main() {
  LBUFFER="${LBUFFER}$(__fzf_ripgrep)"
  local ret=$?
  zle reset-prompt
  return $ret
}

__fzf_ripgrep() {
  emulate -L zsh
  rg_cmd="rg --smart-case --line-number --color=always --trim" 
  selected=$(FZF_DEFAULT_COMMAND=":" \
      fzf --bind="change:top+reload($rg_cmd {q} || true)" \
          --bind="ctrl-l:execute(tmux splitw -h -- nvim +/{q} {1} +{2})" \
          --ansi --phony \
          --delimiter=":" \
          --preview="bat -H {2} --color=always --style=header,grid {1}" \
          --preview-window='down:60%:+{2}-10')

  local ret=$?
  [[ -n "$selected" ]] && echo ${${(@s/:/)selected}[1]}
  return $ret
}

main 
```

```shell:.zshrc
autoload -Uz fzf-ripgrep-widget

zle -N fzf-ripgrep-widget
bindkey '\ef' fzf-ripgrep-widget
```

**動き**
![alt-f.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138236/5d591fa0-1eb5-9c88-13ba-9715bfce46e3.gif)

検索結果がpreview内で追えて満足
ただハイライトが少し微妙なのと、 検索結果windowのformatが残念

## 感想 :speech_balloon: 

いくつか課題が残ってますが、これが現状MAX :grimacing:
Rust関連のコマンドに触れてRustすげーとなっております

:wave_tone1: