これに出てくる (*'-')b
この子です。
つくりかた
この子の挙動は次の通りです。
- 直前のコマンドが空なら何もしない
- 直前のコマンドが空でないなら、実行ステータスに応じて話す
まず、現在の状態を示す変数 state
を用意します。
この変数は次のように値が定められるとします。
standby
:コマンドの入力中かつ直前のコマンドは空executed
:コマンドの入力中かつ直前のコマンドは空でないexecuting
:コマンドの実行中
これは、特殊な関数 precmd
や preexec
を用いて管理します。特定のタイミング(コマンドの入力前や実行前)で実行される関数です。
また、PS1
に関して、psvar
と呼ばれる配列変数の要素数によって分岐できるので、executed
のときは (1)
、それ以外のときは ()
にするようにしておきます。
state=standby precmd() { if [[ "$state" == executing ]]; then state=executed psvar=(1) else state=standby psvar=() fi } preexec() { state=executing }
あとは、終了ステータスに応じて話させる関数を作るのと、PS1
を「psvar
の大きさが 1 以上なら該当のコマンドに $?
を渡して得た出力に、そうでなければ空文字列になる」ように設定すればいいです。
smart_exit_status() { if [[ "$1" == 0 ]]; then echo "%F{10}(*'-')b < Exited successfully.%f" return fi echo "%F{9}Exited with code $1" echo -n "(*'~')/ < " case "$1" in 1) echo -n 'Something went wrong?';; 127) echo -n 'Command not found?';; # よしなに 130) echo -n 'Received SIGINT, Interrupt.';; 134) echo -n 'Received SIGABRT, Aborted.';; 137) echo -n 'Terminated with SIGKILL, Killed.';; 139) echo -n 'Received SIGSEGV, Segmentation fault.';; # 何を示す値なのかを書いておくと、助かることが多いです。 # 自分で調べるなどして書きましょう。 *) echo -n '...';; esac echo '%f' }
setopt prompt_subst PS1+="%(1v_\$(smart_exit_status \$?)_)"
おまけ
ところで、Zsh だとコマンド入力時に C-c をしてもマーカーがつかないので、実際に実行したのか中断したのかわかりにくいですね。
上でつくった $state
を利用するといい感じにできます。
TRAPINT() { if [[ "$state" != executing ]]; then print -P '%B%S^C%s%b' fi return $((128+$1)) }
なんですが、isearch mode などでうまくいってくれなかったりするのに気づいて、やめにしました。泣いています。