Help us understand the problem. What is going on with this article?

fzfとvimで少ない労力で作業効率を引き上げた話 (fzf入門)

概要

fzfをインストールして、vimgitと組み合わせて作業効率をバク上げ(当社比)した話。
全体的にfzfを活用してTerminalの作業効率を高めるの後追いになりますが、自分用に知見を整理することが主目的。

vimを使ってない方も、fzf単体でもかなりはかどります。

fzfとは

fzf is a general-purpose command-line fuzzy finder.

  • CLIツール
  • 標準出力に対して、曖昧検索しながら一つ以上の行を選択して標準出力する
  • go製

fzfコマンドのみ実行すると、デフォルトではカレントディレクトリからのfindコマンドの実行結果を検索対象にする。検索をしながら任意の行を選択してEnterを押すと、対象の行が標準出力される。
1.gif

標準出力をパイプすることで、任意のテキストを対象にすることができる。また、-mオプションを付けることで、複数選択が可能になり、TABキーなどで複数選択後にEnterを押すと、選択した行が全て標準出力される。
2.gif

基本的にはコレだけなのだが、「任意のテキストを対象にできる」「柔軟な検索ができる」「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で開くことができる。
3.gif

ざっくり解説すると、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
}

ファイルにどんな差分があるのかを見ながら、ステージングするファイルを選択できるようになる

4.gif

この辺はもっと自分好みにカスタマイズしていかないと、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単体でやったやつ。

gfiles.png

実務では起動中のvimでファイルを検索して開くことがほとんどなので、基本的にはfzf単体でなく、これを使うことが多い。

GFiles?

git status で表示される対象となる、差分があるファイルと新規追加されたファイルのみを対象としたGFiles
こちらは何故かファイルのプレビュー付き。現在のブランチで修正するファイルが多い場合に、さっと直感的にファイルを開けるので地味に役立つ。

gfiles?.png

Bufferes

ファイルを簡単に検索できるからって調子に乗ってバッファが増えすぎても大丈夫。現在開いているバッファを対象に、ファイル名を検索して切り替えることができる。

スクリーンショット 2019-02-21 23.07.08.png

BLines

バッファで開いているファイルの全行を対象に検索をかけ、選択肢行にジャンプすることができる。vim標準の検索コマンドだと一覧性に欠けたりする場面でもこれなら大丈夫。

スクリーンショット 2019-02-21 23.10.07.png

History

最近読み込まれたファイルから検索する。vimを閉じてしまって、またさっきのファイル編集したいなと思ったときに役立つ。

スクリーンショット 2019-02-21 23.07.40.png

Marks

マークの一覧をファイル名で検索してジャンプできる。マーク自体を活用できてれば捗るかも。これはそこまで使ってない。

スクリーンショット 2019-02-21 23.10.36.png

キーバインド設定して爆速に

以上のコマンドは、ファイルを開きたいと思ってからタイプしてたら時間がかかりすぎるので、キーバインドを設定する。ここは好みで良いが、私は以下のように、,をプレフィックスに、特定のアルファベットを叩くことで頻繁に使うコマンドを気軽に呼び出せるようにしている。

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とかだいぶ違うものまでヒットしてしまっている。

スクリーンショット 2019-02-21 23.23.57.png

そういうときは検索ワードの先頭に'を付けて、'use.rbとする。こうすると、単語レベルで検索してくれるので、ちゃんとuser.rbとなっている文字列だけがヒットする。

スクリーンショット 2019-02-21 23.26.09.png

このように、検索ワードに絞り込み方を指定した文字を含めることで、より柔軟に検索することができる。以下がその例なので覚えておくと捗る。

検索対象
hoge h o g e の順で登場する文字列
'hoge hogeを含む文字列
^hoge hogeが先頭にある文字列
hoge$ hogeが末尾にある文字列
!hoge hogeを含まない文字列
!^hoge hogeが先頭にはない文字列
!hoge$ hogeが末尾にはない文字列
Sa2Knight
下の上ぐらいの伸び悩んでるWebプログラマ。色々な記事を読んで勉強しつつ、自ら学んだことを投稿して整理したりしているので誤った情報を発信してるかもしれません。お気づきの際はご指摘頂ければ幸いです。
https://github.com/Sa2Knight/Curriculum-Vitae
studist
「伝えることを、もっと簡単に」をミッションにビジュアルSOPマネジメントプラットフォームのBtoB SaaS「Teachme Biz」を開発・運営するスタートアップ
https://medium.com/studist-dev
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした