ここでzshの発表の続きをやる

Webteko(ウェブテコ)っていう勉強会に参加してzshについて発表した(発表資料)。発表したんだけど、時間の都合とかで(zshにとっては)基本的なところしか紹介できなかった。

「うおー! 俺のzsh好きっぷりはこんなもんじゃないぜ!」というわけで、ここでその続きを書くことにした。主にコマンドライン編集の機能について説明するよ。

smart-insert-last-word について

まず、zshには insert-last-word と言う機能がある。これを使うと、一つ前のコマンドの最後の単語を挿入できる。

これをもっとスマートにしたのが smart-insert-last-word。設定の仕方はこんな感じ。

autoload smart-insert-last-word
zle -N insert-last-word smart-insert-last-word
bindkey '^]' insert-last-word

こうやっておくと、 [a-zA-Z], /, \ のうち少なくとも1文字を含む単語だけが対象となるよ。

% make > buildLog.txt 2>&1  # とりあえずコマンド実行
% less   # 次のコマンド入力中に ^] を押す
% less buildLog.txt  # 最後の単語を挿入。2>&1 は出てこない

さらに、この「単語としてマッチさせる条件」の設定もできるみたい。まあ、それはやりすぎだろう。

^Xg をもっと使いやすくする

list-expand って機能があって、デフォルトで ^Xg に割り当てられている。これは *.bak とかのワイルドカード指定を展開して、「ビヨッ」っと下に表示する機能だ。便利なんだけど、なんだか押しにくいね。2ストロークキーなんて疲れるね。

なので他のキーに割り当てるんだけど、キーがあんまり余ってない。そこで ^D に「カーソルが行末だったら1文字削除。そうじゃなかったらlist-expand」という動作を割り当てることにした。こんな感じ。

function _delete-char-or-list-expand() {
    if [[ -z "${RBUFFER}" ]]; then
        # the cursor is at the end of the line
        zle list-expand
    else
        zle delete-char
    fi
}
zle -N _delete-char-or-list-expand
bindkey '^D' _delete-char-or-list-expand

% rm *.bak
#         ^カーソルがここのときに ^D を押す
% rm *.bak
test1.bak  test2.bak
# こんな風に、下に候補が展開される

% rm *.bak
#      ^カーソルがここのときに ^D を押す
% rm *.ak
# b が削除される

OKOK。押しやすくなった。

undo, redo のキーバインド

zshコマンドラインでは、もちろんundo, redoができる。できるんだけど、undoのキーバインド^_ または ^Xu だ。押しにくいよ。それに、redoはデフォルトで割り当てられていない。

なので、もうちょっとましな設定にすることにした。

bindkey "^[u" undo
bindkey "^[r" redo

undoを ESC-u 、redoを ESC-r にしたよ。こんな時に便利。

% rm *.bak  # ここでタブを押すと、
% rm test1.bak test2.bak testX.bak  # * が展開される
# その後 ESC-u を押すと、
% rm *.bak  # 元に戻る

コマンドライン中に改行を入れる

zshを使ってると、ちょっとしたシェルスクリプトぐらいはコマンドラインで済ませてしまいたいと思う。当然コマンドライン中で改行したくなるよね。

改行する(でも実行はしない)っていうのは、以下のどれかでできる。

  • ^V^J
  • ESC-^J
  • ESC-^M
  • ESC-RETURN

4つもあるけど全部押しにくいので、これもキーバインドを変えた。

bindkey '^J' self-insert-unmeta

こんな感じで使うよ。

% for i in $(ls *);do  # ここで ^J

% for i in $(ls *);do
  echo $i  # 改行できる

実はfor文の途中とかは普通にRETURNで改行できる。

% for i in $(ls *);do  # ここで 普通に RETURN

% for i in $(ls *);do
for>                   # こんな感じに改行できる

でもこのやりかただと、^P とか上矢印とか押しても1行目に移動できない。

% for i in $(ls *);do
for> ls                # ^P を押しても前の履歴が出てきてがっかり

self-insert-unmeta を使うとちゃんと1行目に移動できて便利だよ。

最後に

とりあえずここまで。まあ、全部細かいネタで、別に知らなくてもいいことばっかりだと思う。でも、設定ファイル書いてたらもう楽しくて、何か止まらなくなってくる(よね)。みんなも man zshzle とか読みまくって色々試してみるといいよ。