ハイパーマッスルエンジニア

Vim、ShellScriptについてよく書く

vim-fzfで自作関数を実行する

vim-fzf超便利。vimを使っていてまだ入れてない人は今すぐ入れたほういい。

github.com

何ができるようになるかってvim内でfzfが使える。例えばファイルを開きたい場合にめちゃくちゃ早く開ける。
こんな感じ↓(私はCtrl-pにキーバインドして使っています)

f:id:rasukarusan:20181015152034g:plain

fzf-vimに標準で入っている関数だけでも十分便利だが、自分で作った関数にfzfで選択したものを食わせたいと思ったのでやってみる。

やりたいこと

現在開いているファイルの別ブランチ版を別タブで表示したい。例えば今のブランチがtestでhoge.phpを開いている時、masterのhoge.phpを見たい場合、今までは以下のような手順を踏んでやっていた。

  1. Ctrl-zでシェルに戻る(vimから抜ける)
  2. git checkout masterでmasterブランチに移動
  3. fgvimに戻ってLで開く

動作的にはこんな感じ。

f:id:rasukarusan:20181015151507g:plain

めちゃくちゃ面倒くせえ....ただmasterブランチのファイルを見たいだけなのに一々shellに戻るのが非常にナンセンス。
理想の動きは「shellに戻らず、vim内でブランチを選ぶだけ」。
ということで実現のために必要なことをまとめてみる。

  1. ブランチ名を指定したら今開いているファイルをそのブランチ版で開く自作関数を作る
  2. 任意のコマンドの結果をvim内のfzfで表示
  3. fzfで選択した結果をvim自作関数に突っ込む

1. ブランチ名を指定したら今開いているファイルをそのブランチ版で開く自作関数を作る

これはvimプラグインtpope/vim-fugitiveを入れてたら余裕でした。

:Gtabedit ブランチ名:%

で現在開いているファイルを別ブランチ版で開くことができます。
作った関数はこちら。

.vimrc

" Gtabeditを簡単に実行できるようにした関数 "
function! s:alias_Gtabedit(...)
    if a:0 == 0
        let branch_name = 'master'
    else
        let branch_name = a:1
    endif
    execute ':Gtabedit '.branch_name.':%'
endfunction

" :Co ブランチ名 でそのブランチのソースをタブ表示 "
command! -nargs=? Co call s:alias_Gtabedit(<f-args>)

これで:Co hoge_branchのようにブランチを指定するだけで現在開いているファイルを別ブランチ版で見ることが可能に。
ちなみにCocheckou-outの略です。masterブランチを参照することが多かったので引数に何も指定しない場合は自動でmasterブランチを指定するようにしました。

2. 任意のコマンドの結果をvim内のfzfで表示

さてここからが本番です。vim-fzfにどうやって任意のコマンド結果を食わせることができるのか調べてみました。

READMEを見た限り割とシンプルでした。 他にも色々とオプションがあるようですが、以下のものだけ知っておけばとりあえず実現できそうです。

  call fzf#run({
    \ 'source': '任意のshellコマンド',
    \ 'sink': '選択したものに対して行いたいvimコマンド',
    \ 'down': '40%'  " fzfを表示させる場所・幅。up / down / left / rightを指定可能。
    \ })

例えば:call fzf#run({ 'source': 'ls', 'sink': 'tabedit', 'down': '40%' })と打てばlsの結果がfzfで表示され、選択するとそのファイルを別タブで開くことができます。

3. fzfで選択した結果をvim自作関数に突っ込む

ということであとはsourceにブランチを表示するコマンドを指定し、sinkに1で作った自作関数を指定させてやればフィニッシュです。

  call fzf#run({
    \ 'source': 'git branch -a',
    \ 'sink': function('s:alias_Gtabedit'),
    \ 'down': '40%'
    \ })

さらに:Coで呼び出したいので以下のように設定。(1で書いたcommand! -nargs=? Co call s:alias_Gtabedit(<f-args>)は削除しておく)

function! s:fzf_alias_Gtabedit()
  call fzf#run({
    \ 'source': 'git branch -a',
    \ 'sink': function('s:alias_Gtabedit'),
    \ 'down': '40%'
    \ })
endfunction
command! Co call s:fzf_alias_Gtabedit()

実行画面

f:id:rasukarusan:20181015160339g:plain

まとめ

fzfになんでも食わせられるようになって一気に幅が広がった気がする。
vim-shellとかvim-fzfとか色々疎通ができるようになってくるとアイデアが湧き出てきて本当に楽しい。