おい、peco もいいけど fzf 使えよ

  • 392
    Like
  • 0
    Comment

peco 便利ですよね。正直、使い始めてしまうと使わない日はありません。最近の CLI 界隈では選択的インターフェイスやインタラクティブフィルタなどと呼ばれるツールが盛んに開発されています。特に peco は ghq との連携で一躍人気が出た気がします。

こんなやつですね。以下は ghq のリポジトリへのアクセスを簡単にするためにスクリプトです。

# Require Bash 4.0+
peco-src() {
    local selected
    selected="$(ghq list --full-path | peco --query="$READLINE_LINE")"
    if [ -n "$selected" ]; then
        READLINE_LINE="builtin cd $selected"
        READLINE_POINT=${#READLINE_LINE}
    fi
}
bind -x '"\C-]": peco-src'

よく zsh との連携を取り沙汰されますが、peco + ghq は zsh 専用というわけではなく上記のように bash でも利用できます。ただ、bash は 4.0 以上必須というのと、zsh で利用したほうが便利であるという事実はありますが。

peco-src() {
    local selected
    selected="$(ghq list --full-path | peco --query="$LBUFFER")"
    if [ -n "$selected" ]; then
        BUFFER="builtin cd $selected"
        # zle accept-line
    fi
    zle reset-prompt
}
zle -N peco-src
bindkey '^]' peco-src

しかし、peco 自体が percol という python ツールの Go 実装であり日本製であるためか、日本ではダントツで有名ですがパイオニアというわけではありません。

そんな peco ですが、確かにカスタマイザブルでとても便利な peco ですが、ここで fzf という peco と同様のツールについて紹介したいと思います。また、fzf は peco と同じく Go 製です。

選択的インターフェイスの小歴史

以下の記事を見てみると、作者 @lestrrat さんが peco を開発した動機が percol の存在と @mattn さんからの追い込みによるらしく、@mattn さんが作った gof というツールのクローンから開発をスタートしたとあります。そんな @mattn さんが gof を作ったのは fzf というツールが Windows で芳しくなかったからとありました。

実はあまり有名でないだけで、fzf は結構前から存在しているようです(有名か有名ではないかの基準について、Google にて日本語記事で検索したときのヒット数で相対比較したものです)。

ここで有名な絞り込みツール(インタラクティブフィルタ)のスター数を初コミット日時を見てみます。

ツール 初コミット スター数 実装言語
zaw 2011/02/10 264 Zsh
percol 2011/02/27 1,843 Python
selecta 2013/10/10 976 Ruby
fzf 2013/10/23 2,883 Go
gof 2013/12/09 76 Go
sentaku 2014/01/12 78 Bash
peco 2014/06/06 2,611 Go
pick 2014/08/13 321 C
hf 2015/05/23 253 Go

※スター数は2015年10月28日現在のものです

意外にも percol 以上に zaw がこの中では最古参のようです(この手のツールのパイオニアは percol だとばかり思っていました)。ちなみに GitHub のファーストコミットのコミット日時を元にしています。

それと 2012 年に目立った動きがないのも気になるところです。他に有名なインタラクティブフィルタってありましたっけ…?また、実装言語としては Go が大人気ですね。今のトレンドとマッチしてとのことでしょうかね。よくはわかりません。

そしてなんといってもスター数ですが 4 桁を超えたリポジトリが 3 件あり、fzf>peco>percol です。2 位と 3 位には 1,000 stars 近い差があるため実質 fzf と peco が圧倒的な人気ツールといった感じです。

fzf/peco

peco と(スター数では)双璧をなす fzf ですが、日本での知名度は高いようには思えません(例えば、Qiita の peco タグには 135 件の投稿があるのに対し、fzf タグには 1 件しかありません; それも 1 年以上前の fzf が ruby だった時代)。

peco、便利です。しかし同じくらいに fzf も便利です。また peco とは違うベクトルで便利さがあるのがまたいいところの一つです。

fzf のいいところ

  • 連携がすごい(tmux や vim との連携が図りやすく、公式の Wiki が充実している)
  • スクリプトに組み込まれることが前提となった設計(1つしかない場合起動しない --select-1 や 逆順して表示する --tac などがある)
  • ANSI がイケる(--ansi で色が反映される)
  • ファジーマッチすごい(githubfzf で github.com/junegunn/fzf にマッチする)
  • 読み込み行数が大量にあっても、読み込みながら絞り込みがかけられ、読込中のローディングマーグがいい感じにカッコいい

peco のいいところ

  • カスタマイザブルがすごい(JSON で設定ファイルが書け、キーバインドからそのコンビネーションからカスタムマッチャーもイケる)
  • マルチバイトな文字列をパイプしても表示が崩されない(絵文字とか)
  • マッチ用のフィルタが選択でき(IgnoreCase、Regexp など)、スペース区切りで AND 検索ができる
  • 日本製
  • ペコ。言いやすい(fzf...エフズィーエフ...?)

fzf の使い方

すべて man に書いてあることですが、とても便利な機能についていくつか抜粋して紹介します。

--ansi

意外と便利です。いや、めっちゃ便利です。こんな感じになります

color.gif

--select-1

fzf に通した時に候補が 1 つしかない場合、選択的に絞り込む必要ないですよね。そんなときはこのオプション。fzf によるインターフェイスは起動せず選んだものとして出力されます。

select1.gif

追記
2015/10/29 に @mattn さんによって peco に --select-1 が実装されました!!
これでまた、peco が便利になりました。便利のいいとこ取りは便利しか生まないので便利ですね。

--exit-0

絞り込む候補すらないとき、--select-1 同様に fzf インターフェイスを立ち上げずに終了します。

exit0.gif

--multi

Tab(Ctrl-i)にて複数選択できます。

--tac

入力内容を反転させてから fzf インターフェイスを起動します。事前に tac 処理をしなくてよくなります。実は、tac コマンドは意外と厄介で環境に大きく依存するため、このオプションがとても助かったりします。

tac.gif

--reverse

プロンプト含め、fzf インターフェイスを上下逆にします。ちなみに fzf はデフォルトで下です。

reverse.gif

--bind

もちろんキーカスタマイズできます。スクロールを C-u の当てたり、などです。毎回 fzf --bind ... とするのは面倒なので、次で紹介する $FZF_DEFAULT_OPTS に登録しておきましょう。

$FZF_DEFAULT_OPTS

常用するオプションを登録しておくことで、いちいちオプション指定をしなくてよくなります。$LESS$GREP_OPTS のようなものです。

0.10.5 では以下がデフォルトオプションになっています。

$ export FZF_DEFAULT_OPTS="--extended --cycle"

--bind などによってオプションが増えるととても長くなるのが欠点ですが、環境変数で挙動を変更できるため場合によってローカルな使い方($ FZF_DEFAULT_OPTS="--sync" fzf ...)ができ便利です。

fzf を使ったスクリプト

公式の Wiki が充実しています。

# fshow - git commit browser (enter for show, ctrl-d for diff)
fshow() {
  local out shas sha q k
  while out=$(
      git log --graph --color=always \
          --format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" |
      fzf --ansi --multi --no-sort --reverse --query="$q" \
          --print-query --expect=ctrl-d); do
    q=$(head -1 <<< "$out")
    k=$(head -2 <<< "$out" | tail -1)
    shas=$(sed '1,2d;s/^[^a-z0-9]*//;/^$/d' <<< "$out" | awk '{print $1}')
    [ -z "$shas" ] && continue
    if [ "$k" = ctrl-d ]; then
      git diff --color=always $shas | less -R
    else
      for sha in $shas; do
        git show --color=always $sha | less -R
      done
    fi
  done
}

公式から引用した上記 fshow 関数(コマンド)を用いると git log が効率的に view できます。色付きで見られるほか、fzf 上で C-d を押すことで git diff が見られます。Enter で git show です。tig みたいに便利でしょう?

6265b4ae-d26c-11e4-87de-5421a1be8f31.gif

もうひとつ、fzf を便利に呼び出すハックです。fzf や peco やその他の選択的インターフェイスを使用しているときに、アレがないときコレといった記述が必要になります(例えば peco が無いなら fzf を使う)。

available () {
    local x candidates
    candidates="$1:"
    while [ -n "$candidates" ]
    do
        x=${candidates%%:*}
        candidates=${candidates#*:}
        if type "$x" >/dev/null 2>&1; then
            echo "$x"
            return 0
        else
            continue
        fi
    done
    return 1
}

このような関数を設定しておき、

$ export FILTER="peco:fzf:/path/to/old-version/peco"
$ available $FILTER
fzf

$PATH のようなコロン区切りのリストを渡してやると、使用できるフィルタを返してくれます。これを利用すれば、よしなに使用できるインタラクティブフィルタをサジェッションしてくれます。

fzf と連携する

作者ブログにも以下の解説が載っています。

また、公式の README にもあるとおり、vim からも利用でき、

:FZF

とすることで、呼び出せます。

また、fzf-tmux というコマンドもバンドルされていて tmux を利用中ならば使用できます。

# usage: fzf-tmux [-u|-d [HEIGHT[%]]] [-l|-r [WIDTH[%]]] [--] [FZF OPTIONS]
#        (-[udlr]: up/down/left/right)

# select git branches in horizontal split below (15 lines)
git branch | fzf-tmux -d 15

# select multiple words in vertical split on the left (20% of screen width)
cat /usr/share/dict/words | fzf-tmux -l 20% --multi --reverse

fzf_tmux.gif

自動でペインを割ってくれて、使い終わるとうまい具合に消滅してくれます。縦割りにするか、横割りにするかなども自由に決めることができます。

まだまだあるよ

もう公式の README をみたほうがはやいでしょう。

:cherry_blossom: まとめ

fzf について紹介しました。fzf について贔屓目に紹介していますが回し者でもないですし、peco も大好きです。これら選択的インターフェイスは UNIX ライクな設計を持ちつつ、なおかつモダンなテイストを CLI にもたらしてくれるのでイージーにライフチェンジングできます。

  • peco 便利
  • fzf 便利
  • どっちも便利
  • peco ユーザは fzf も使ってみるべきで、fzf ユーザは peco も使ってみるべき
  • fzf のことも知ってあげて
  • CLI の選択的インターフェイスは総じて便利

Let's fzf, let's peco.