読者です 読者をやめる 読者になる 読者になる

$ service ssh0 start

from everything import *

tmux関連の設定を晒す【自分のPCで使用しているソフトウェア,設定の紹介 #4】

自分のPCで設定しているソフトウェア,設定の紹介

前回前々回とタイル型ウィンドウマネージャxmonadについて,設定している点に関していくらか詳しく述べてきましたが,今回からはより具体的に使用しているソフトウェアの紹介と,それぞれの設定に関してコメントしていきたいと思います。

今回はターミナルマルチプレクサtmuxについて,そのユースケースと設定の紹介をしていきたいと思います。

tmuxを使うことの利点

tmux

tmuxとは何か,とか基本的な使い方などは他の方の説明がたくさんあるので詳しくは説明しません。

tmuxを使い始めたので基本的な機能の使い方とかを整理してみた - 完熟トマト

tmuxを使うことの利点は,個人的には

  • 意図せず端末を消してしまっても,セッションは生きているので何も考えずまた作業を再開できる
  • (上に関連して)端末上で起動しておいて,見なくてもいい端末を消しておける
  • 結果的に端末は大体いつも1つだけ起動した状態で,非常にスッキリする
    • choose-treeコマンドで端末内でセッションを切り替えて使える
  • 端末の機能で準備されている「タブ」の概念より気軽に新しいウィンドウorペインを作成できる
  • copyモードの存在により,標準出力のスクロールがショートカットから楽にできる
  • copyモードを活用すると,コピー・ペーストが楽になる

などがあげられると思っています。 タブ機能のついた端末を使っている時期があったり,あるいはxmonadというそもそものウィンドウを分割して並べて表示させられる環境にいるのですが,それでもtmuxという一つのレイヤーを重ねることでいろいろな作業がやりやすくなる,というのが今の実感です。

自分の場合,デフォルトのキーバインドがどうにも合わなかったので,どうせ触るのは自分だけだということで,完全なオレオレキーバインドを設定してしいました。 tmuxより低(高?)レイヤーのxmonadキーバインドに似た直感的なものに変更して使っています。

ということで,以下では役に立ちそうな設定の紹介をしていきたいと思います。

すでにQiitaなどで書いていることもありますが,変更したものもあるかと思いますので,改めて整理してみたいと思います。

tmuxの設定

設定ファイル全体は

github.com

を参照してください。

一般的な設定:

#------------------------------------------------------------------------------
# General settings
#------------------------------------------------------------------------------

# enable utf-8
setw -g utf8 on
# UTF-8による文字(漢字や絵文字など)が使われることを宣言

# max history limit
set -g history-limit 5000
# 各ペインで遡れる行数

# escape time
set -s escape-time 0
# エスケープキーを押した後にキー入力を受け付ける時間を設定(単位: ミリ秒)
# vimでの反応が遅くなるだけなので0にする

# `display-panes` コマンドを実行した時に数字が表示される時間(単位: ミリ秒)
# デフォルトだと短かったので,3秒間表示されるようにした
set -g display-panes-time 3000

# ウィンドウの番号,ペインの番号を0ではなく1から始める
set -g base-index 1
set -g pane-base-index 1

# ウィンドウを消したときに,自動で番号を詰める
set -g renumber-windows on

# automatic-rename-formatで指定した形式で端末のタイトルを自動で変更
setw -g automatic-rename on

#------------------------------------------------------------------------------

キーバインド:

tmuxでXmonadライクで直感的なキーバインドを設定する - Qiita

略記法として以下のように:

  • [key] と書いた場合はプレフィックスキーを押した後にkeyを押すことを意味し,
  • (key) と書いた場合には,Altキーを押しながらkeyを押すことを意味します
# あるセッションは複数のウィンドウから構成され,一つのウィンドウの中には
# 複数のペインが含まれる
#
# === 概略図とキーバインド ===
#
#         +----------------+
#         |    (←,→,h,l)   ↓(num) OR click status bar       ↓ (Enter)
#      window1 <------> window2          window3         新規 window4
#   ===============================================================
#       pane1            pane1            pane1           pane1
#         ↕ (j,k) フォーカス
#       pane2     + - -  pane2 - 移動 -> |pane2|
#                 |移動           (L)
#      |pane3| <- +      pane3
#                (H)       ↓ (c)                            ↓ (C)
#                      ペイン削除                     ウィンドウ削除
#
#
# === ウィンドウ内の操作 ===
#
#   +---------------+------------+
#   |pane1          |pane3       |
#   |               |            |
#   |               |            |
#   +---------------+            |
#   |pane2          |            |
#   |               |            |
#   |               |            |
#   +---------------+------------+
#
# ペイン分割:
#   - 左右に分割         : (|)
#   - 上下に分割         : (-)
# フォーカスを動かす     : (j),(k) OR マウスでクリック
# ペインの順序を入れ替え : (J),(K)
# ペインを削除           : (c)
# レイアウトを変更       : (Space)
# 1つのペインを全画面に  : (f)
# ペイン境界を動かす:
#             (a)
#              ↑
#        (,) ← + → (.)
#              ↓        OR マウスで境界をドラッグ
#             (z)
# 隣のウィンドウにペインを結合           : (H),(L)
# 指定した番号のウィンドウにペインを結合 : (Shift+num)

ノーマルモードでのキーバインド

#------------------------------------------------------------------------------
# Keybind (normal mode)
#------------------------------------------------------------------------------

# prefix key ^b -> ^g
set -g prefix C-g
bind-key C-g send-prefix

# vi like key binding
# もとから準備されているセットを使う
setw -g mode-keys vi
bind-key -t vi-copy v begin-selection

# (c): ペインを削除する
# ただし,ウィンドウ内に1つだけしかないときには確認メッセージを出す
bind-key -n M-c if "tmux display -p \"#{window_panes}\" | grep ^1\$" \
    "confirm-before -p \"Kill the only pane in the window? It will kill this window too. (y/n)\" kill-pane" \
    "kill-pane"

# (C): ウィンドウを削除する
# ただし,セッション内に1つだけしかないときには確認メッセージを出す
bind-key -n M-C if "tmux display -p \"#{session_windows}\" | grep ^1\$"\
    "confirm-before -p \"Kill the only window in this session? It will kill the session too. (y/n)\" kill-window" \
    "kill-window"

# (-): 上下に分割, (|): 左右に分割
bind-key -n M-- split-window -v -c "#{pane_current_path}"
bind-key -n M-| split-window -h -c "#{pane_current_path}"

# [s]: 上下に分割,[v]: 左右に分割
bind-key s split-window -v -c "#{pane_current_path}"
bind-key v split-window -h -c "#{pane_current_path}"

# (j)/(Down): フォーカスを次に,(k)/(Up)フォーカスを前に
bind-key -n M-j select-pane -t :.+
bind-key -n M-k select-pane -t :.-
bind-key -n M-Down select-pane -t :.+
bind-key -n M-Up select-pane -t :.-

# (m): マスターペイン(ペイン番号1)にフォーカス
bind-key -n M-m select-pane -t :.1

# (M): 選択したペインをマスターペインに移動
bind-key -n M-M swap-pane -d -t :.1

# (J)/(K): ペインの順番入れ替え
bind-key -n M-J swap-pane -D
bind-key -n M-K swap-pane -U

# (H)/(L): 選択したペインを左右のウィンドウに移動させる
bind-key -n M-L join-pane -t :+
bind-key -n M-H join-pane -t :-

# (Shift + number): 指定した番号のウィンドウにペインを移動
bind-key -n M-! join-pane -t :1
bind-key -n M-'"' join-pane -t :2
bind-key -n M-'#' join-pane -t :3
bind-key -n M-'$' join-pane -t :4
bind-key -n M-% join-pane -t :5
bind-key -n M-& join-pane -t :6
bind-key -n M-"'" join-pane -t :7
bind-key -n M-( join-pane -t :8
bind-key -n M-) join-pane -t :9

# (,)/(.): 左右にペイン境界を動かす
# (a)/(z): 上下にペイン境界を動かす
bind-key -n M-',' resize-pane -L 1
bind-key -n M-z resize-pane -D 1
bind-key -n M-a resize-pane -U 1
bind-key -n M-'.' resize-pane -R 1

# (f): 選択したペインを最大化表示
bind-key -n M-f resize-pane -Z

# (q): 各ペイン番号を表示
bind-key -n M-q display-panes

# (h)/(Left): 左のウィンドウにフォーカス
# (l),(Right): 右のウィンドウにフォーカス
bind-key -n M-Right next-window
bind-key -n M-Left previous-window
bind-key -n M-l next-window
bind-key -n M-h previous-window

# (Space): ペインレイアウトを変更
bind-key -n M-Space next-layout

# (number): 指定した番号のウィンドウにフォーカス
bind-key -n M-1 select-window -t 1
bind-key -n M-2 select-window -t 2
bind-key -n M-3 select-window -t 3
bind-key -n M-4 select-window -t 4
bind-key -n M-5 select-window -t 5
bind-key -n M-6 select-window -t 6
bind-key -n M-7 select-window -t 7
bind-key -n M-8 select-window -t 8
bind-key -n M-9 select-window -t 9

# [W]: ウィンドウ名を指定してフォーカス
bind-key W command-prompt "select-window -t '%%'"

# (Enter): 新しいウィンドウを作成
bind-key -n M-Enter new-window -c "#{pane_current_path}"

# [t]: ツリー表示モード(今あるセッション,その中のウィンドウにアタッチ)
bind-key t choose-tree

# [Ctrl + C]: フォーカスされているペインの内容をコピーして新しいウィンドウでvimで開く
bind-key C-c run 'tmux capture-pane -S -10240 -p > /tmp/tmux-capture.txt'\;\
             new-window "vim + /tmp/tmux-capture.txt"

# F11: ステータスバーの表示をトグルする
bind-key -n F11 set status

# ^b + r: 設定ファイルを再読み込み
bind-key r source-file ~/.tmux.conf \; display "Reloaded!"

#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# Keybind (copy mode)
#------------------------------------------------------------------------------

# v: 選択開始
bind-key -t vi-copy v begin-selection

# V: 行選択
bind-key -t vi-copy V select-line

# C-v: 選択モードを矩形選択の間でトグル
bind-key -t vi-copy C-v rectangle-toggle

# y: 選択範囲をコピー
bind-key -t vi-copy y copy-selection

# Y: 行をコピー
bind-key -t vi-copy Y copy-line

#------------------------------------------------------------------------------

その他見た目の設定

一応落ち着いてきてはいますが,まだちょくちょく変更してしまう部分です。

f:id:ssh0:20160527012749p:plain

のような見た目になります。

#------------------------------------------------------------------------------
# Color
#------------------------------------------------------------------------------

# use 256colors
set -g default-terminal screen-256color

# pane border
set -g pane-active-border-fg colour242
set -g pane-active-border-bg colour238
set -g pane-border-fg colour239
set -g pane-border-bg colour235

# window list
setw -g window-status-fg white
setw -g window-status-bg colour235
setw -g window-status-attr dim

# message line
set -g message-fg white
set -g message-bg colour235
set -g message-attr bright

#------------------------------------------------------------------------------
# WM window title
#------------------------------------------------------------------------------

# enable wm window titles
set -g set-titles on

# wm window title string (uses status bar variables)
set -g set-titles-string "#S - #I: #W"

#------------------------------------------------------------------------------
# Status line
#------------------------------------------------------------------------------

# status on
set -g status on

# color
set -g status-fg white
set -g status-bg colour235

# enable utf-8
set -g status-utf8 on

# status bottom
set -g status-position bottom

# remove space between window titles (>tmux 2.0)
set -g window-status-separator ''

# No need to update status line
set -g status-interval 0

# window name is aligned left | centre | right
set -g status-justify "centre"

# left component
set -g status-left-length 20
set -g status-left '#[fg=colour255,bg=colour235,bold] #S #[fg=colour26,bg=colour235,nobold]'

# right component
set -g status-right-length 3
set -g status-right '#[fg=white,bg=colour235,bold]#{?client_prefix,^g ,}'

# window status
setw -g window-status-format " #[fg=colour234,bg=colour242,bold] #I#[fg=colour242]:#[fg=colour245,bg=colour235,nobold] #{=20:window_name} "
setw -g window-status-current-format " #[fg=colour234,bg=colour40,bold] #I#[fg=colour40]:#[fg=colour40,bg=colour235] #{=20:window_name} "

#------------------------------------------------------------------------------

シェルとの関係

tmuxを意識することなく自然に使いたい,ということで,端末ではzshを使用しているのですが,以下のtmux.zshが読み込まれるようにすることで便利になります。

github.com

#=#=#=
# set tmux aliases and start up behavior
#
# > [Start a new session from within tmux with ZSH_TMUX_AUTOSTART=true - Super User](http://superuser.com/questions/821339/start-a-new-session-from-within-tmux-with-zsh-tmux-autostart-true)
#
# Auto start tmux when the terminal launched.
#=#=

tmux-new-session() {
  if [[ -n $TMUX ]]; then
    tmux switch-client -t "$(TMUX= tmux -S "${TMUX%,*,*}" new-session -dP "$@")"
  else
    tmux new-session "$@"
  fi
}

# Aliases
if [[ -n $TMUX ]]; then
  alias ta='tmux switch-client -t'
else
  alias ta='tmux attach-session -t'
fi
alias ts='tmux-new-session -s'
alias tl='tmux list-sessions'
alias tksv='tmux kill-server'
alias tkss='tmux kill-session -t'

# Autostart if not already in tmux.
if [[ ! -n $TMUX ]]; then
  # get the IDs
  if ! ID="$(tmux list-sessions 2>/dev/null)"; then
    # tmux returned error, so try cleaning up /tmp
    /bin/rm -rf /tmp/tmux*
  fi
  create_new_session="Create New Session"
  ID="${create_new_session}:\n$ID"
  ID="$(echo $ID | $PERCOL | cut -d: -f1)"
  if [[ "$ID" = "${create_new_session}" ]]; then
    tmux new-session
  elif [[ -n "$ID" ]]; then
    tmux attach-session -t "$ID"
  else
    :  # Start terminal normally
  fi
fi

やっていることは,既にセッションがあればそれをリストにしてfzfを使って表示し,新しくセッションを開始することもできるようにしてあります。

また,tmuxセッション外からts <セッション名>とコマンドを打つと,その名前で新しくセッションを追加できますが,同じコマンドをtmuxセッション内で打つと,別のプロセスからセッションを作成し,そこに対してswitch-clientコマンドを実行するように設定しています。

これで新しくセッションを作成したいときにも,端末を新たに立ち上げたり,一旦デタッチしたりする手間がなくなるので,便利かと思います。

まとめ

今回,よく使っているtmuxについて,設定内容をまとめました。また,zshrcに設定を追加しておくことで,さらに便利に使うことができるようになっていると思います。

現状不満といったら,ペインの境界をうまく表示する方法はないのか,ということくらいですかね。

1行じゃなくて2行にしたりできたら便利だと思うんですけどね。

たしか,そういうPythonで書かれた端末多重化ソフトウェアはあったんですが,まだ試してないです。いずれやってみたいですね。

(追記: これです)

github.com

今回は24時に間に合わなかったですが,ちゃんと続けていきますよ。

明日はtmux.zshのようなzshで読み込んでいるいくつかの設定ファイルについて紹介してみたいと思います。よろしくお願いします。