zshでwidgetを定義して、コマンドライン編集で任意のzsh関数を呼び出す

初めに

またzshネタです。今回は、コマンドライン編集中に好きなzsh関数を呼び出せるようにします。これで、エディタのマクロのようなことが出来るようになります。

今まで困っていたこと

zshでは、WORDCHARSで単語の区切りにならない文字を指定できます。僕の設定はこんな感じです。

WORDCHARS='*?_-.[]~=&;!#$%^(){}<>'

詳しいことはここのWORDCHARSの解説なんかを読んでもらうとして(もう知ってる人多いよね)、要するに^Wでディレクトリ一つ分削除できるようになります。

これはこれで便利なのですが、やっぱりスペース区切りで削除したいこともあります(viで言うdB)。なのでmanでそれっぽいのないかなー、と探していました。で、結論として、ない。vi-backward-blank-wordっていう惜しいのはあったけど、それは移動するだけで削除は出来ませんでした。残念。

解決方法

じゃあどうするか。結論から言うと、以下を.zshrcに書いておけばOKです。

function _kill-backward-blank-word() {
    # 現在位置から左のスペースまでをkillする
    zle set-mark-command
    zle vi-backward-blank-word
    zle kill-region
}
zle -N _kill-backward-blank-word
bindkey '^Y' _kill-backward-blank-word

これで、こんな使い方ができるようになります。

ls /home/mollifier/work  # ここまで入力して
ls /home/mollifier/      # ^W でディレクトリ1つ分削除
ls                       # ^Y でスペースまで全部削除 

OKOK、いい感じだ。

何をやっているか

man zshzleを読んでたら、widget というのを見つけました。どうやら、コマンドラインで行うエディタ操作のことをそう言うみたいです。例えば、zshはbackward-kill-wordというwidgetを初めから持っています。これは(emacsモードでは)^Wに割り当てられていて、カーソル左の単語が削除できます。

この初めから持っているwidgetを、built-in widgetと言います。それ以外にuser-defined widgetと言うのがあって、自分で勝手にwidgetが作れます。なので、built-in widgetを組み合わせてuser-defined widgetとして登録しておけば、元にはない凝った機能が追加出来るようになります。

作り方は以下です。

関数を定義する

まずは自作の関数を作ります。上の例では function _kill-backward-blank-word という所です。その中でbuilt-in widgetを3個呼び出しています。こんな風にzle widgetという形式でwidgetを呼び出せます。

user-defined widget を定義する

その下の zle -N という所で、user-defined widgetを定義しています。これはzsh -N widget [ function ] という形式です。上の例ではfunctionを省略していますが、少し補足しておきます。

widgetを呼び出したとき、functionで指定された関数が呼び出されます。この指定は省略可能で、その場合はwidgetと同じ名前の関数が呼び出されます。まあ、2回書くのもなんなので省略しておきました。

キーバインドとして設定する

その下の bindkey '^Y' ... という所で、定義したwidgetを好きなキーに割り当てています。ここは別に'^Y'でなくても、適当に余っているキーを指定すればOKです。割り当てても良い余っているキーは前回調べました。

最後に

こんな感じで、みんなも好きなwidgetを作りまくるといいよ。コマンドライン編集だけでもカスタマイズしまくりなzshが大好きだ。