概要
fzf
をインストールして、vim
やgit
と組み合わせて作業効率をバク上げ(当社比)した話。
全体的にfzfを活用してTerminalの作業効率を高めるの後追いになりますが、自分用に知見を整理することが主目的。
vim
を使ってない方も、fzf
単体でもかなりはかどります。
fzfとは
fzf is a general-purpose command-line fuzzy finder.
- CLIツール
- 標準出力に対して、曖昧検索しながら一つ以上の行を選択して標準出力する
- go製
fzf
コマンドのみ実行すると、デフォルトではカレントディレクトリからのfind
コマンドの実行結果を検索対象にする。検索をしながら任意の行を選択してEnterを押すと、対象の行が標準出力される。
標準出力をパイプすることで、任意のテキストを対象にすることができる。また、-m
オプションを付けることで、複数選択が可能になり、TABキーなどで複数選択後にEnterを押すと、選択した行が全て標準出力される。
基本的にはコレだけなのだが、「任意のテキストを対象にできる」「柔軟な検索ができる」「1つ以上の選択した行を出力できる」というシンプルなインタフェースを活用することで、幅広い作業を効率化することができる。
fzfのインストール
fzf
はgithubからリポジトリをクローンして簡単に導入可能
$ git clone https://github.com/junegunn/fzf.git
インストーラが入ってるのでそれを実行するだけ
$ ./fzf/install
途中、オートコンプリートやキーバインドを有効にするのか、.bashrc
などに設定を追記するかを聞かれるが、特にこだわりが無い限りはy
としておけば幸せになれるかもしれない。
Do you want to enable fuzzy auto-completion? ([y]/n) y
Do you want to enable key bindings? ([y]/n) y
Do you want to update your shell configuration files? ([y]/n) n
これで冒頭のgifのようにfzf
コマンドが使えるようになる
$ fzf --version
0.17.5 (b46227d)
vimでリポジトリ以下のファイルを検索して開く
おもむろに.bashrc
などに以下のコードを追加する。
fvim(){files=$(git ls-files)&&selected_files=$(echo"$files" | fzf -m--preview'head -100 {}')&&
vim $selected_files}
bashrc
を再読込
source ~/.bashrc
fvim
コマンドが使えるようになる。このコマンドは、リポジトリで管理されているファイルを一覧し、検索やプレビューしながら任意のファイルを選択し、vimで開くことができる。
ざっくり解説すると、fzf
を活用した以下のような処理を行っている。
git ls-files
でリポジトリで管理されてるファイルの一覧を標準出力- 標準出力を
fzf
で受け取って、検索できるように - その際、
--preview
オプションを指定することで、現在カーソルが当たっているファイルに対して任意の処理を実行した結果を右側に表示することができるので、head
コマンドを使って対象ファイルの先頭100行をプレビューできるように - 選択したファイルは標準出力されるので、それをvimで開く
もちろん -m
オプションを指定しているので、複数ファイルを選択してまとめてvimのバッファに読み込むことも可能。
と言っても、実際は後述するvimプラグインのほうでfzf
を活用するので、このような使い方はそんなに多くないが、--preview
の無限の可能性を感じることはできた。
gitで差分を確認しながらステージングする
例えば適当にコードをイジって、以下のような差分があるとき
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)
modified: activerecord/test/models/job.rb
modified: activestorage/test/models/preview_test.rb
no changes added to commit (use "git add" and/or "git commit -a")
おもむろに以下のようなコードを.bashrc
に追加して再読込する
fga(){modified_files=$(git status --short | awk'{print $2}')&&selected_files=$(echo"$modified_files" | fzf -m--preview'git diff {}')&&
git add $selected_files}
ファイルにどんな差分があるのかを見ながら、ステージングするファイルを選択できるようになる
この辺はもっと自分好みにカスタマイズしていかないと、tig
使えば良いじゃんと言われかねないけど、標準入力から検索、選択して標準出力するという単純なツールながら、自分好みに色々な使い方が模索できることがわかる。
vimプラグインを導入する
fzf
を使って、vim
をさらに使いやすくするためのプラグイン fzf.vimが公式で公開されている。
インストールは各々使ってるプラグインマネージャで以下のようにすれば良い(以下はdeinの例)
call dein#add('junegunn/fzf',{'build':'./install --all','merged':0})call dein#add('junegunn/fzf.vim',{'depends':'fzf'})
これだけで、READMEに書いてある通り、Files
Colors
Bufferes
などのコマンドが使えるようになる。
すべて知りたい人はREADMEを読めば良いので、ここでは私が個人的によく使っているコマンドについて紹介する
GFiles
git ls-files
で表示されるファイルを対象に、ファイルを選択してバッファに読み込む。つまり本記事の最初の方でfzf
単体でやったやつ。
実務では起動中のvimでファイルを検索して開くことがほとんどなので、基本的にはfzf
単体でなく、これを使うことが多い。
GFiles?
git status
で表示される対象となる、差分があるファイルと新規追加されたファイルのみを対象としたGFiles
。
こちらは何故かファイルのプレビュー付き。現在のブランチで修正するファイルが多い場合に、さっと直感的にファイルを開けるので地味に役立つ。
Bufferes
ファイルを簡単に検索できるからって調子に乗ってバッファが増えすぎても大丈夫。現在開いているバッファを対象に、ファイル名を検索して切り替えることができる。
BLines
バッファで開いているファイルの全行を対象に検索をかけ、選択肢行にジャンプすることができる。vim
標準の検索コマンドだと一覧性に欠けたりする場面でもこれなら大丈夫。
History
最近読み込まれたファイルから検索する。vimを閉じてしまって、またさっきのファイル編集したいなと思ったときに役立つ。
Marks
マークの一覧をファイル名で検索してジャンプできる。マーク自体を活用できてれば捗るかも。これはそこまで使ってない。
キーバインド設定して爆速に
以上のコマンドは、ファイルを開きたいと思ってからタイプしてたら時間がかかりすぎるので、キーバインドを設定する。ここは好みで良いが、私は以下のように、,
をプレフィックスに、特定のアルファベットを叩くことで頻繁に使うコマンドを気軽に呼び出せるようにしている。
nnoremap <silent>,f:GFiles<CR>
nnoremap <silent>,F :GFiles?<CR>
nnoremap <silent>,b:Buffers<CR>
nnoremap <silent>,l:BLines<CR>
nnoremap <silent>,h:History<CR>
nnoremap <silent>,m:Mark<CR>
検索を柔軟に行う
fzf
はその曖昧検索がウリだが、時として意図しないモノまでヒットしてしまうことがある。例えば以下はuser.rb
を検索しているのに、duration_serializer.rb
とかだいぶ違うものまでヒットしてしまっている。
そういうときは検索ワードの先頭に'
を付けて、'use.rb
とする。こうすると、単語レベルで検索してくれるので、ちゃんとuser.rb
となっている文字列だけがヒットする。
このように、検索ワードに絞り込み方を指定した文字を含めることで、より柔軟に検索することができる。以下がその例なので覚えておくと捗る。
例 | 検索対象 |
---|---|
hoge | h o g e の順で登場する文字列 |
'hoge | hogeを含む文字列 |
^hoge | hogeが先頭にある文字列 |
hoge$ | hogeが末尾にある文字列 |
!hoge | hogeを含まない文字列 |
!^hoge | hogeが先頭にはない文字列 |
!hoge$ | hogeが末尾にはない文字列 |