長いワンライナーを打っていると編集が面倒くさい
ワンライナーじゃなくてもいいのだが、Terminalでコマンドを打っているときに、修正するときのカーソル移動が結構面倒くさい。コマンド履歴をさかのぼり、真ん中の方のコマンドだけ編集したいときなど地獄の作業だ。この世で最も無駄な時間だと言ってもいい。
Vimに入ってしまえば慣れたキーバインド、テキストオブジェクトやプラグインを駆使して爆速で編集できるのに...
Terminalの現在行をVimで編集できればいい
そう、つまり現在行をそのままVimに持っていき、編集し終わったら内容がTerminalに打たれた状態であればいい。 出来上がったのがこれ。
キーバインドCtrl-w
にzleのウィジェットを登録して呼び出せるようにしている。
zle(Zsh Line Editor)を使って実現できる
下記を.zshrc
に書けば終了。Ctrl-w
を押せば現在行をVimで編集できる。Vimを終了すれば編集した内容がTerminalに打たれている。
edit_current_line() { local tmpfile=$(mktemp) echo "$BUFFER" > $tmpfile vim $tmpfile -c "normal $" -c "set filetype=zsh" BUFFER="$(cat $tmpfile)" CURSOR=${#BUFFER} rm $tmpfile zle reset-prompt } zle -N edit_current_line bindkey '^w' edit_current_line
やっていることは簡単
- 一時ファイル作る
- 現在行(
$BUFFER
)を一時ファイルに書き込んでVimで開く - 現在行を一時ファイルの内容で書き換える
これだけ。
zle
については昨日の記事でも触れたので詳しくはそちら。
Vimで一時ファイルを開く際に
vim $tmpfile -c "normal $" -c "set filetype=zsh"
としているのは行末に移動するためと、VimのSnippetを効かせるためにFiletypeをzshに設定している。
fcコマンドでいいんじゃないの?
似たような挙動をするものでfc
コマンドというものがある。
これは直前に実行したコマンドをVimで開いて編集することができるもの。保存して終了すれば編集した内容が即実行される。
直前のコマンドを編集したい場合だったらfc
コマンドでいい。ただ直前のコマンドを編集したいケースはあまりなく、よくあるのはコマンド履歴から遡ってそれを編集といったことが多い。また編集が終わったら即実行されるのもちょっと心臓に悪い。
そういう場合に今回のは使えると思う。
終わり
一時ファイル作るのにmktemp
を使って、あとで削除(rm
)するのはもうちょっとスマートになると思う。たぶん一時ファイル作らずにプロセス置換とかを駆使すればいけるかなあ。
とはいえgit commit
とかfc
とかと似たような挙動になったのでまあいい。