#前置き
最近書いた,これでも言ったけれど,
(tmuxのペインのステータスラインにgitのブランチとかディレクトリとか表示する(プロンプトはもう古い))
とりあえず,何より大事なのは,tmuxではペインごとにステータスラインが表示できるようになったという事実である.これは本当に大事件である.
2年前ぐらいから、"tmuxってssh接続とかたくさんやるとどれがどのホストにログインしてんだかワカンネ〜〜ナ〜〜"とは思っていたので,すでに表題のアイディア自体はあった.だから上の記事を書く時にもそれは考えていたんだけど,なかなか実装が思いつかなかった,が,今日,とりあえず突貫工事ではあるがそれっぽいものはできたので書く.
いろいろ言っといてアレだが,僕はインフラエンジニアを名乗れるほどこの分野に明るくないので,何かしらの不備はあるかもしれない,そういう時は編集リクエストなりコメントなり送ってくれると非常にありがたい.
#機能
tmux
のセッション内でssh
でログインすると,ログイン先のusernameとhostnameをtmuxのペインのステータスラインに表示する.それだけ.
上のスクリーンショットのvagrant@192.168.33.10
がその部分.(その左の0
はペインのインデックス)
#実装
まず,.tmux.conf
機能の本質ではない色とかそういうやつは省いて書く.
以下のコードを.tmux.confにコピペ.
set-option -g pane-border-status bottom
set-option -g pane-border-format "#P #(tmux-pane-border #{pane_current_command} #{pane_pid})"
次に,tmux-pane-border
,これは自作コマンドで,別に名前はなんでもいい.ご自分でファイルを作り,パスの通ったディレクトリに置き,実行属性を付与するなどしてコマンドとして使える状態にしていてください.「tmuxのペインのステータスラインにgitのブランチとかディレクトリとか表示する(プロンプトはもう古い)」の方の記事で既にtmux-pane-border
コマンドを作っている方は後述の設定がオススメです.
(.zshrcにシェル関数として書いておいても動くか,と思ったが.tmux.confからは呼び出せなかった.)
#!/bin/zsh
if [[ $1 = "ssh" ]]; then
pane_pid=$2
info=$({ pgrep -flaP $pane_pid ; ps -o command -p $pane_pid; } | xargs -I{} echo {} | awk '/ssh/' | sed -E 's/^[0-9]*[[:blank:]]*ssh //')
port=$(echo $info | grep -Eo '\-p ([0-9]+)'|sed 's/-p //')
if [ -z $port ]; then
local port=22
fi
info=$(echo $info | sed 's/\-p '"$port"'//g')
user=$(echo $info | awk '{print $NF}' | cut -f1 -d@)
host=$(echo $info | awk '{print $NF}' | cut -f2 -d@)
if [ $user = $host ]; then
user=$(whoami)
list=$(awk '
$1 == "Host" {
gsub("\\\\.", "\\\\.", $2);
gsub("\\\\*", ".*", $2);
host = $2;
next;
}
$1 == "User" {
$1 = "";
sub( /^[[:space:]]*/, "" );
printf "%s|%s\n", host, $0;
}' ~/.ssh/config
)
echo $list | while read line; do
host_user=${line#*|}
if [[ "$host" =~ $line ]]; then
user=$host_user
break
fi
done
fi
ssh_hostname=" ssh:$user@$host "
fi
echo $ssh_hostname
#解説
いじって見ればわかるが,.tmux.conf
のpane-border-format
の動きはwindow-status-format
とはだいぶ違う動き方をする.その辺の動き方がコードを煩雑にしている感がある(#{pane_current_command}とかを引数で渡すのが気持ち悪すぎる).どう違うのかは説明がめんどくさいので割愛.
全体の実装を簡単にいうと,tmuxから渡されるペインのpid
を元にホスト名とかを探している感じ.
#よりオススメの設定
上のgifでは,ssh
接続をする前にはディレクトリやブランチが表示されているのがわかるだろうか.
これは「tmuxのペインのステータスラインにgitのブランチとかディレクトリとか表示する(プロンプトはもう古い)」の設定をssh接続しているかどうかで切り替えているからこういう挙動になっている.
ssh接続している時はペインのステータスラインにホスト名,していない時はカレントディレクトリやgitの情報を表示する,ということだ.
#!/bin/zsh
if [[ $1 = "ssh" ]]; then
pane_pid=$2
info=$({ pgrep -flaP $pane_pid ; ps -o command -p $pane_pid; } | xargs -I{} echo {} | awk '/ssh/' | sed -E 's/^[0-9]*[[:blank:]]*ssh //')
port=$(echo $info | grep -Eo '\-p ([0-9]+)'|sed 's/-p //')
if [ -z $port ]; then
local port=22
fi
info=$(echo $info | sed 's/\-p '"$port"'//g')
user=$(echo $info | awk '{print $NF}' | cut -f1 -d@)
host=$(echo $info | awk '{print $NF}' | cut -f2 -d@)
if [ $user = $host ]; then
user=$(whoami)
list=$(awk '
$1 == "Host" {
gsub("\\\\.", "\\\\.", $2);
gsub("\\\\*", ".*", $2);
host = $2;
next;
}
$1 == "User" {
$1 = "";
sub( /^[[:space:]]*/, "" );
printf "%s|%s\n", host, $0;
}' ~/.ssh/config
)
echo $list | while read line; do
host_user=${line#*|}
if [[ "$host" =~ $line ]]; then
user=$host_user
break
fi
done
fi
ssh_hostname=" ssh:$user@$host "
git_info=""
directory=""
else
if git_status=$(cd $3 && git status 2>/dev/null ); then
git_branch="$(echo $git_status| awk 'NR==1 {print $3}')"
case $git_status in
*Changes\ not\ staged* ) state="#[bg=colour013,fg=black] ± #[fg=default]" ;;
*Changes\ to\ be\ committed* ) state="#[bg=blue,fg=black] + #[default]" ;;
* ) state="#[bg=green,fg=black] ✔ #[default]" ;;
esac
if [[ $git_branch = "master" ]]; then
git_info="#[underscore]#[bg=black,fg=blue] ⭠ ${git_branch} #[default]${state}"
else
git_info="#[underscore]#[bg=black,fg=colour014] ⭠ ${git_branch} #[default]${state}"
fi
else
git_info=""
fi
ssh_hostname=""
directory="$3"
fi
echo "#[bg=colour013,fg=black]$ssh_hostname#[default]#[bg=black,fg=cyan]#[underscore]$directory#[default]$git_info"
set-option -g pane-border-format "#[fg=black,bg=blue] #P #[default]#(tmux-pane-border #{pane_current_command} #{pane_pid} #{pane_current_path})"
function precmd() {
if [ ! -z $TMUX ]; then
tmux refresh-client -S
fi
}
上の設定をすると,今までプロンプトに表示していたディレクトリなどの情報が全く無駄になることに気づくだろう(あるいはもともとのがあるから上の設定はいらない,となるかもしれないが).そうなると,.zshrc
などに記述していたプロンプトの設定を削除したくなるかもしれない.現に僕はそうした.
しかし,人類がtmuxの上でしか生活しなくなってからずいぶん長い時間が経ったというものの,やはり素のターミナルを扱う場面においてカレントディレクトリなどの情報がないのは困る.そこで,tmuxの内外でプロンプトの表示をきりかえるとよい.参考までに僕の.zshrc
のその部分を載せておく.
#前略
function precmd() {
if [ ! -z $TMUX ]; then
tmux refresh-client -S
else
dir="%F{cyan}%K{black} %~ %k%f"
if git_status=$(git status 2>/dev/null ); then
git_branch="$(echo $git_status| awk 'NR==1 {print $3}')"
case $git_status in
*Changes\ not\ staged* ) state=$'%{\e[30;48;5;013m%}%F{black} ± %f%k' ;;
*Changes\ to\ be\ committed* ) state="%K{blue}%F{black} + %k%f" ;;
* ) state="%K{green}%F{black} ✔ %f%k" ;;
esac
if [[ $git_branch = "master" ]]; then
git_info="%K{black}%F{blue}⭠ ${git_branch}%f%k ${state}"
else
git_info="%K{black}⭠ ${git_branch}%f ${state}"
fi
else
git_info=""
fi
fi
}
#後略
#その他
・tmuxのアタッチとかセッションの管理を奇跡的に簡略化するtmuximumというプラグインがある,是非使ってほしい.
・tmuxのステータスバーにssidとかバッテリーとか音量とかload averageとか出す方法もあるらしい,是非みてほしい
・やはりtmuxは無限の可能性を秘めていると思った.
・tmuxの公式のマニュアルを読むと知らないことがいっぱい書いてある,様々な発見があったので読んでみてほしい.
・最後に,コードはsoyuka/tmux-current-pane-hostnameを大いに参考にした.これと違うのはペインのステータスラインに表示するかウィンドウのステータスラインに表示するかだけである.
・License:MIT