tmux で XMonad ライクな幸せな開発環境を構築する方法


tmux

  • GNU screen 後継のターミナルマルチプレキサ
  • Windows 環境から SSH するときに、XMonad ライクに Unix 環境を操作できて便利
  • GNU Screen はよく固まるけど、tmux はマシな気がする

前提

  • sudo はパスワードの入力を不要とする設定をしている
  • ssh も .ssh/authorized_keys の設定をし、パスワードの入力を不要にしている
  • ssh の設定もちゃんと事前にしておく。aws001 とか aws002 とか。

やったこと

tmux の起動スクリプトの作成

  • tmux の中なら何もしない
  • tmux の中かどうかの判定はよく例にあるような TMUX 環境変数ではなく、 $TERM を使用。   ( ssh 先、 sudo した後でも正しく判定するため )
  • tmux のセッションが残っていれば、それにアタッチ
  • tmux のセッションがなければ新たにセッションを生成
  • tmux 起動時にウィンドウペインをいっぱい生成
    • 起動の手間を省くというより、毎回同じ順に作業中のペインがあるのがうれしい
  • main-vertical レイアウトを基本に

tmux の設定ファイルの作成

  • 定番の日本語、マウス、ステータスバーの設定を採用
  • キーバインドは vim ライクに
  • プレフィックスは C-j に
    • よく例にある C-t はシェル/Emacs の transpose-chars に使うので不採用
    • C-j には改行の役割があるが、 C-m でだいたい代用できる
    • 人差し指なんで押しやすい
  • 次のペインの C-j C-j のキーバインドは押しやすくかつ、覚えやすい
    • vim で j は下への移動を意味するため
  • C-j Enter がすごい便利
    • ペインの並び順を保持したまま、現在のペインをメインのペインにする
    • XMonad ライクな操作感で幸福度が急上昇
  • C-j Insert で、現在アクティブなペインの起動コマンドと同じコマンドで新たなペインを作成
    • レイアウトもいいかんじに。
  • C-j Delete で、現在アクティブなウィンドウを強制終了

どう嬉しいか

  • ペインを増やすときに sudo や ssh コマンドを改めてする手間を省ける
    • 起動中のペインに移動して、 C-j Insert で勝手に sudo や ssh をやってくれる
  • 作業中のペインを確認しつつ、広いメインのペインで作業できる。
    • main-vertical レイアウト便利
    • XMonad ライクな作業スタイルの実現
  • メインのペインを切り替えてもペインの並び順が保持される
    • いろいろ作業を続けても近くのペインが近くのまま。
    • 作業中のペインを場所を見つけやすい

具体的な設定

bin/tmuxx
#!/bin/sh
if [ $TERM = "screen" ]; then
  exit
fi

tmux=/usr/bin/tmux
if $tmux has-session ; then
  $tmux attach
  exit
fi

$tmux start-server
$tmux new-session -d -n local -s tmux

$tmux split-window -h "sudo su - user1"
$tmux send-keys  "cd ~/project1" Enter

$tmux split-window "sudo su - user2"
$tmux send-keys  "cd ~/project2" Enter

$tmux split-window "sudo su - user3"
$tmux send-keys  "cd ~/project3" Enter

$tmux split-window "sudo su - user4"
$tmux send-keys  "cd ~/project4" Enter

$tmux split-window "sudo su - user5"
$tmux send-keys  "cd ~/project5" Enter

$tmux select-layout main-vertical

$tmux new-window -n ssh "sudo su - ruby -c 'ssh aws001'"

$tmux split-window "sudo su - ruby -c 'ssh aws002'"
$tmux select-layout main-vertical

$tmux select-window -t local

$tmux attach-session -t tmux
.tmux.conf
# ctl-j でコマンドモードになるように設定
unbind-key C-j
set-option -g prefix C-j
bind-key C-j send-prefix

# 日本語環境なら今のところ必須。
set-window-option -g utf8 on

# マウス操作対応
set-option -g mouse-select-pane on
set-option -g mouse-select-window on
set-option -g mouse-resize-pane on
set-option -g mode-mouse on
set-option -g mouse-utf8 on

# ステータスバーの外観の設定
set -g status-fg cyan
set -g status-bg black
set -g status-left-length 30
set -g status-left  '#[fg=black,bg=cyan,bold] [#S]#[default]'
set -g status-right '#[fg=black,bg=cyan,bold] [%Y-%m-%d(%a) %H:%M]'

# window-status-current
setw -g window-status-current-fg black
setw -g window-status-current-bg cyan
setw -g window-status-current-attr bold#,underscore

# ペインのアクティブなウインドウの外観の設定
set -g pane-active-border-fg black
set -g pane-active-border-bg cyan

# コピーモードで vi キーバインドを使用する。
set-window-option -g mode-keys vi

# キーバインド
# C-j r で設定ファイルを再読み込み
bind r source-file ~/.tmux.conf

# C-j C-j で次のペイン。C-j C-k で前のペイン
bind C-j select-pane -t :.+
bind C-k select-pane -t :.-

# C-j Enter で、現在のペインをメインのペインに変更した上で、
# main-vertical レイアウトにする。
# rotate-window を使っているのがポイント
bind Enter run-shell "sh -c \"yes rotate-window -U \\; | head -n $(tmux display-message -p '#P' ) | xargs tmux ; tmux select-pane -t 0 \\; select-layout main-vertical \""

# C-j Insert で main-vertical レイアウトのまま、新たなペインを生成
bind IC run-shell "sh -c \"tmux split-window -v -t 0 \\\"$( tmux list-panes -F '#{pane_active} #{pane_start_command}' | egrep ^1 | sed 's/^1 //' )\\\" \\; select-layout main-vertical \""

# C-j Delete でウィンドウを強制終了
bind DC confirm-before -p "kill-window #W? (y/n)" kill-window

解説

tmux display-message -p '#P'

  • 現在のペインの番号を標準出力に出力する

tmux rotate-window -U

  • 左まわりにペインの並びを回転させる
  • 現在のペイン番号の回数、このコマンドを実行すると、現在アクティブなペインがメインなペイン(ゼロ番のペイン)になる。

yes

  • yes と出力し続けるコマンド
  • 引数を与えると、その引数の内容を出力し続ける
    • head と組合せて指定回数その文字列を表示できる。

xargs

  • 標準入力の内容を引数にして、コマンドを実行できる
  • xargs を使うことで、tmux の起動をうまく一度だけに。

ひとりごと

  • csh の repeat を使う案もあるんだけど、残念ながら bash 派なのでボツ
  • seq -f で指定回数表示できるかな、と思ったけど、%g とかなかったらエラーになった
  • perl の x 演算子使えば簡単だけど、なんかズルい気がしてボツ。

アクティブなペインの起動コマンドの取得

下記で、現在アクティブなペインの起動コマンドが取得できる

tmux list-panes -F '#{pane_active} #{pane_start_command}' | egrep ^1 | sed 's/^1 //'

ポイント

  • アクティブなペインのスタートコマンドを取得する API はない
  • list-panes でペインの一覧を表示できる
    • -F で指定した属性を表示できる
    • pane_active はアクティブなペインなら 1 になる
    • pane_start_command はそのペインのスタートコマンドを取得できる
  • grep 、sed を組み合せて、アクティブなペインのスタートコマンドをムリヤリ取得