OSC 133という仕様があります。 これはシェルやREPLでプロンプトと実行結果の出力を一まとまり単位として扱うためのマークを決まったエスケープシーケンスで行うことで、ターミナルエミュレーターが解釈できるようにしようという提案です。
Bashでもやりたいけど、bashには preexec
や precmd
がないので無理かなあと半分諦めていた。
が、ふとした時にやり方を発見したので早速やってみた。
iTerm2 では、以下のようなことができる。
- Toolbelt -> Show Toolbelt (⌘ + Shift + b) の Command History に実行コマンドの履歴が出る(上図)
- ⌘ + Shift + ↑ (Edit -> Marks and Annotations -> Next Mark) で前のコマンド実行行へジャンプ
- ⌘ + shift + ↓ (Edit -> Marks and Annotations -> Previous Mark) で次のコマンド実行行へジャンプ
- ⌘ + Shift + a (Edit -> Select Output of Last Command) で直前コマンドの実行結果を選択
# See: https://github.com/rcaloras/bash-preexec
source ~/var/bash-preexec/bash-preexec.sh
_prompt_executing=""
function precmd() {
local ret="$?"
if test "$_prompt_executing" != "0"
then
_PROMPT_SAVE_PS1="$PS1"
_PROMPT_SAVE_PS2="$PS2"
PS1="\e]133;P;k=i\a"$PS1"\e]133;B\a\e]122;> \a"
PS2="\e]133;P;k=s\a"$PS2"\e]133;B\a"
fi
if test "$_prompt_executing" != ""
then
# FTCS_COMMAND_FINISHED
printf "\033]133;D;%s;aid=%s\007" "$ret" "$$"
fi
# FTCS_COMMAND_START
printf "\033]133;A;cl=m;aid=%s\007" "$$"
# コマンド実行中Flag -> off
_prompt_executing=0
}
# Enterを押してコマンド実行直前
function preexec() {
PS1="$_PROMPT_SAVE_PS1"
PS2="$_PROMPT_SAVE_PS2"
# FTCS_COMMAND_EXECUTED
printf "\033]133;C;\007"
# コマンド実行中Flag -> on
_prompt_executing=1
}
eval "$(starship init bash)"
bash-preexec.sh の発見
Starship でプロンプト設定をしているが、eval $(starship init bash)
の中身ってどうなっているの?
という疑問が湧いて、 /usr/local/bin/starship init bash --print-full-init
を実行してななめ読みしたところ、 bash-preexec を発見。
(略)
# If the user appears to be using https://github.com/rcaloras/bash-preexec,
# then hook our functions into their framework.
if [[ "${__bp_imported:-}" == "defined" || $preexec_functions || $precmd_functions ]]; then
# bash-preexec needs a single function--wrap the args into a closure and pass
starship_preexec_all(){ starship_preexec "$_"; }
preexec_functions+=(starship_preexec_all)
precmd_functions+=(starship_precmd)
else
(略)
これぞ求めていたもの。
Bash用にちょい修正
ZshでOSC 133に対応する の zsh設定をほぼ丸パクリしつつ、bash用に書いたのが上のコード