💻

tmuxのstatus lineの色をpane modeとhost名に合わせて変える

に公開

tmuxのstatus lineの色をpane modeとhost名に合わせて変える

っていう話は誰かがすでにまとめてくれている気がするんですが検索してもなかなかたどりつけず、結構苦労をしたのでまとめておきます。

最近sshでサーバーに入って作業することが増えたんですが、ssh先が増えるに伴って自分がどこにいるかがよくわかなくなってしまいます。
また、neovimでよく作業するため、pane分割を行わないことがよくあります。その時、自分がどのpane modeにいるのかよくわからなくなってしまうんですね。
そのため表題のようなことをしました。

ちなみにTmux Plugin Managerは使いません。

前提知識

tmuxの一通りの使用方法

環境

$ uname -srvm
Linux 5.15.167.4-microsoft-standard-WSL2 #1 SMP Tue Nov 5 00:21:55 UTC 2024 x86_64
$ tmux -V
tmux 3.4

カラーコードを使用する部分がtmux 3.3aでは動作しなかったので工夫するよりアップデートしてしまえという感じで筆者は手元で最新(3.5a)をビルドして$HOME/.local/binに送り込んで使っています。記事執筆環境では3.4が入っていますのでこれはそのままになっています。
サーバーに既に古いtmuxが入っている場合、それを上書きするとスクリプトが動かなくなるとかあるので自分の使用するやつだけ変えるようにしましょう。

完成品がこちらです

以下のような感じ。
左からpane mode, prefix-is-pressed, session name, window name, host name, clockとなっております。

tmuxprefixを押すと左から二番目のOFFが明るい紫色のONになり、

COPYモードに入ると青系の表示に変更します。

設定

dotfilesにまとめたいので~/.config/tmux/tmux.confで設定しています。

tmuxのstatus lineはstatus left, window status, status rightで構成されます。
それぞれ以下のように設定しています。

~/.config/tmux/tmux.conf
# status line

set-option -g status-bg "colour238"
set-option -g status-fg "colour255"

run-shell "$SHELL ~/.config/tmux/set_status_left.sh"

setw -g window-status-format "| #I: #W |"
setw -g window-status-current-format "#[fg=colour254,bg=colour67]| #I: #W |"

## set status right based on $(uname -n)
## Using color code(#000000) directly seems requiring tmux 3.4 or above.
run-shell "$SHELL ~/.config/tmux/set_status_right.sh"
  • run-shellを使うと/bin/sh -cで渡された文字列を評価します。
    • $SHELLを渡すとログインシェルでスクリプトを実行できるのでこうしておいています。
  • できるならtmux.confの中で完結したかったですが、bashの分岐処理を使いたかったためshell scriptとして切り分けました。
~/.config/tmux/set_status_left.sh
# display mode
STATUS_LEFT_MODE_VIEW="#[fg=#cdeccd,bg=#5fab5b] VIEW "
STATUS_LEFT_MODE_COPY="#[fg=#bdc1ee,bg=#5b62ab] COPY "

# prefix key is pressed or not
prefix_on_color="#[fg=colour254#,bg=colour127]"
prefix_off_color="#[fg=colour254#,bg=colour53]"
STATUS_LEFT_PREFIX="#{?client_prefix,${prefix_on_color} ON  ,${prefix_off_color} OFF }#[default]"

# display session
STATUS_LEFT_SESSION="#[fg=colour254, bg=colour241] Session: #S #[default]"

STATUS_LEFT_VIEW=${STATUS_LEFT_MODE_VIEW}${STATUS_LEFT_PREFIX}${STATUS_LEFT_SESSION}
STATUS_LEFT_COPY=${STATUS_LEFT_MODE_COPY}${STATUS_LEFT_PREFIX}${STATUS_LEFT_SESSION}

STATUS_LEFT="if -F \"#{==:copy-mode,#{pane_mode}}\"\
  \"set-option -p status-left \\\"${STATUS_LEFT_COPY}\\\"\"\
  \"set-option -p status-left \\\"${STATUS_LEFT_VIEW}\\\"\"\
"

tmux set-option -g status-left-length 100
tmux set-option -g status-left "${STATUS_LEFT_VIEW}"
tmux set-hook -g session-changed "${STATUS_LEFT}"
tmux set-hook -g session-window-changed "${STATUS_LEFT}"
tmux set-hook -g window-pane-changed "${STATUS_LEFT}"
tmux set-hook -g pane-mode-changed "${STATUS_LEFT}"
  • staus leftの文字列をくみ上げ、set-option -g status-leftと各種イベントにフックとして登録します。
  • prefix_on_color, prefix_off_colorの文字列を見るとわかる通り、#{?A,B,C}のような分岐処理の中にカンマを含んだ文字列を入れるには#でエスケープが必要なようです。
  • STATUS_LEFTの部分、if -F #{==:copy-mode,#{pane_mode}}でpane modeに対するマッチングを行います。
    • ==:は見てわかる通りA == Bで判定を行います。
    • mならglob pattern, m/rならregular expressionで判定できますが、
    • ソースコードをたどらないとわからないですが、pane modeは現状二つしかない(copy-mode, view-mode)ため、それらはオーバーキルです。
  • tmuxは各種イベント発生時にコマンドを実行するHOOKS機能を提供します。
  • pane mode切り替え時のみならず、session切り替え時、window切り替え時、pane切り替え時をそれぞれフックすることで表示がdesyncするのを防ぎます。
    • しないと切り替えをまたいでも表示が保持されて矛盾した状態になります。
~/.config/tmux/set_status_right.sh
HOST_COLOR="$(uname -n | sha256sum | awk '{print substr($1, 1, 6)}')"

r=0x${HOST_COLOR:0:2}
g=0x${HOST_COLOR:2:2}
b=0x${HOST_COLOR:4:2}
brightness=$(((r*299 + g*587 + b*114)/1000))

HOST_FG_COLOR=#FFFFFF
if [ $brightness -gt 128 ]; then
  HOST_FG_COLOR=#000000
fi
HOST_BG_COLOR=$HOST_COLOR

tmux set-option -g status-right-length 100
tmux set-option -g status-right "#[fg=${HOST_FG_COLOR},bg=#${HOST_BG_COLOR}] #H #[fg=colour254,bg=colour241]| %Y-%m-%dT%H:%M:%S #[default]"
  • さて、status rightですが、host名と時計を表示しています。
    • ごくまれにssh先の時計がずれるため、時計を表示すると役に立つことがあります。
  • uname -nでhost名を表示し、sha256sumの先頭6文字をとることでhost名に対して一意なカラーコードを得ます。
  • host名から計算されたカラーコードのbrightnessを計算し、暗い色には白文字、明るい色には黒文字を表示します。
    • この方法自体はchatgptに考案させて出てきたものですが、出てきた設定そのものは動かなかったのでだいぶ手直ししています。
    • chatgptがこう提案しなかったら文字色はhost名から計算された色の補色にしようと思っていましたが、シンプルに白黒のほうが見やすい気がするのでこのほうがよかったなと思います。

終わりに

pane modeに対応した色の変更は視界の端でも割と見えるため便利になりました。

host名から計算された色は偏るかと思いきや筆者の環境ではいい感じにばらけているため見やすくて非常によくなりました。
status line一部ではなく全体をこの色にしたり、背景色を変更したりするとより気づきやすいかもしれません。

GitHubで編集を提案

Discussion