Vim でテストコード書きながらその場でテスト流すのを tmux の send-keys で超快適にやる

  • 23
    いいね
  • 0
    コメント

Vim でテストコードを書きながら、Vim を抜けずその場でそのファイルとかその行のテストを流したい

send-keys.gif

そういうとき Emacs とか Atom だとプラグインでやってたけど、いまいち Vim だとそういうやり方がしっくりこないなと思っていたところで「もう tmux で別ペイン開いといて send-keys するのでいいのでは」という結論になった。

この方法だとテストの種類によって変えるのも実行コマンドを変えるだけで簡単にできるし、実際にテストを流すのが Docker コンテナの中、とかいうときにもそのまま応用できるのでなかなかよい。

具体的にどういうことができるかというと、これから書く例では、tmux を左右の2ペインに分割しておいて、

  • 左ペインに Vim
  • 右ペインにテストコマンドを実行したい場所

が設定された状態で、Vim でテストコードを書きながら右ペインでテストを実行するというもの。

send-keys を実行するスクリプト

まずは send-keys を実行するスクリプトを用意する。

tmux-send-keys-to-right-pane

#!/usr/bin/env sh

session=$(tmux display-message -p '#S')
window=${session}:$(tmux display-message -p '#I')

args=""

for arg in $@; do
  args="${args}""${arg} "
done

tmux send-keys -t right C-z "${args}" C-m

かなり雑だけどこんな感じとか。

これに実行権限をつけてパスの通るところに置くなりした上で、tmux のウィンドウ上で右ペインを起動して、例えば左ペイン側で

$ tmux-send-keys-to-right-pane ls -la

とすると右ペインで ls -la が実行されると思う。

これで実行する対象をテストのコマンドにすれば、当然右ペインではテストが実行される。

Vim の中から↑のスクリプトを実行する

ここからは Vim の設定になります!

とりあえず .vimrc に直接設定を書いて参ります!また、私事で大変恐縮なのですが、今私が Ruby on Rails で Minitest を書いており、それを実行したいという気持ちがあることから、Ruby on Rails で Minitest を実行するのを例として説明したいと思います!大変申し訳ございません。

よろしいでしょうか。では .vimrc に以下を記載してください!

.vimrc

command! RailsTest echo s:rails_test(expand('%'), getpos('.'))

function! s:rails_test(file, pos)
  let l:cmd = printf('tmux-send-keys bin/rails test %s:%d', a:file, a:pos[1])
  return system(l:cmd)
endfunction

nnoremap <Leader>rt :<C-u>RailsTest<Return>

簡単に説明しますと、これでやりたいことができるやつです!簡単すぎましたかね?もう少しだけ説明しますと、これは Vim のバッファ上で実行するもので、バッファのファイルとカーソル位置を Rails (5) のテストコマンドに渡しまして、そしてテストを実行する、そういうものであります。

ここでは RailsTest というコマンドが定義されておりまして、そして <Leader>rt がバインドされておりますので、つまりこれを読み込んだ後に左ペインの Vim で Minitest のファイルを開き、そして右ペインでは Rails のルートディレクトリをカレントディレクトリとした状態で <Leader>rt とキーをストローキングしますと、右ペインの方で bin/rails test <バッファのファイル名>:<行番号> が実行されまして、はい、実行されます。もちろん Vim 内部で同期的に実行するわけではございませんので、テストの実行中に Vim の動作がブロックされるということはないのでご安心ください。先ほど申し上げました通り、右ペインで Docker コンテナの bash とかを実行しておけばそのままコマンドを書き換えることなく Docker コンテナでテストが実行できますし、上記をコピペしてコマンド名と関数名、そして

  let l:cmd = printf('tmux-send-keys bin/rails test %s:%d', a:file, a:pos[1])

ここの行を書き換えれば任意のコマンドを実行することができるので便利に使っていただけると思います。ちなみに tmuxinator とかそういうやつは一度も使ったことがありません。あと参考にしました thanks to http://superuser.com/questions/492266/run-or-send-a-command-to-a-tmux-pane-in-a-running-tmux-session すごーいフレンズ