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

## 対象とする人

まず、前提として以下の様な人を対象にしています。

- vimライクなキーバインドが体に染み付いている人
- ペインの並び替え、ウィンドウ間の移動、ウィンドウの移動を多く行い、直感的な操作が好みの人(ペインを作ってしまってからウィンドウに配置したい人とも言う)
- tmuxのキーバインドの再設定を考えている人

## キーバインドに関して考えるべきこと

tmuxにかかわらず、キーバインドに関して考えるべきことは以下の要素だと考えています。

- プレフィックスキーは押しやすく、他のアプリケーションのキーバインドと競合しないこと
- ウィンドウとペイン、ペインの配置の関係を直感的に理解できるキーバインド
- 操作とキーの意味の対応がつけられるようにしてあること

個人的にはさらに以下の条件をつけます。

- Prefix + キー という2段階のキー入力(しかもプレフィックスはキーの同時押し)ではなく、(メタキー+キー)の組み合わせで操作できるものは、できる限りこの形式でキーを登録する。

以上の条件を満たすように、キーバインドを考えていきましょう。

## プレフィックスキー

プレフィックスキーの設定にはその人の性格というか好みが現れるような気がします。つまり、何を重視しますか、ということです。僕の場合、先程の条件であげたように、押しやすい位置にあり、他のアプリケーションのキーバインドと競合しないことを条件としているので、ターミナル上でよく使うアプリケーションであるVimのキーバインドと競合しないか、ということを考える必要があります。

ググって見る限り、よくある設定としては、`C-a`、`C-z`、`C-t`、`C-o`、"\`"などがあるかもしれません。押しやすさを考えるなら、ホームポジションに近い方がいいでしょう。ただし、これらは既にキーバインドがある場合があるので、もし設定する場合には、Vimで`:help CTRL-T`などとしてデフォルトの設定を確認しておくといいでしょう。僕の場合、押しやすさと、キーバインドの使用率を考慮して、プレフィックスは`C-g`に割り当てました。Vimでは現在のファイル名とカーソルの位置の行番号や文字数を表示するキーバインドに割り当てられていますが、`:set ruler`してあるので、全く使うことはないので問題ありません。他のキーの問題点は

- `C-a`  
   shellの行頭に移動のキーバインドと競合。よく使うので駄目。
- `C-z`  
   シェルをバックグラウンド処理にするのに使うキーバインドなので駄目。
- `C-t`  
   自分はこのキーをVimで新しいタブを開くのに使っているので使えない。"t"muxであることと押しやすさからすれば次候補だった。
- `C-o`  
   Vimで以前カーソルのあった位置に戻るのに`C-i`とセットで使うので。
- `C-h,j,k,l`  
   Vimのインサートモードでのカーソル移動に使うので駄目。
- "\`"  
   押しにくくないですか？それとVimではmark全般はこのキーに依っているので駄目。

というわけで、押しやすさと、他のアプリケーションと競合しないことから`C-g`をプレフィックスにします。`~/.tmux.conf`に以下を追記。

```conf
unbind-key C-b

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

## ウィンドウ・ペインの作成・削除、ペインの分割・移動、ペイン間の移動

以下に設定ファイルに書いた説明をのせ、それぞれに関してキーバインドの説明をしていきます。

```conf

# Prefix key: ^g
#
# Abbreviation:
# - [key]
# - {key} <- with Prefix key
# - (key) <- with Alt (or in MacOS, Command key)
```

略記は"[]"で囲ったキーはそのキーそのものを表しており、"()"は、メタキー(Linux、WindowsならAlt、MacならOpt)プラス何かキーを押すことを表しています。
基本的にはAltキーを押しながら操作する形にしており、Prefix + 何かキーという2段階の操作にはしていません。これは特にペイン間の移動やリサイズ時に威力を発揮するので、これだけでも設定する価値はあるかもしれません。

### 1セッション内のウィンドウとペインの構造関係

```conf
#
# Structure in one session:
#
#         ------------------
#         |  (Left,Right)  ↓(num) OR click status bar       ↓ (Enter)
#      window1 <------> window2          window3         window4
#   ===============================================================
#       pane1            pane1            pane1           pane1
#         ↕ (j,k)
#       pane2     - - -  pane2  - - - -> (pane2)
#                 |          [Shift+Right]
#      (pane3) <- -      pane3
#            [Shift+Left]  ↓ (x)                            ↓ (X)
#                          x                                x
#
```

ペイン間の移動は(j),(k)で行います。Vimと同じように{h},{j},{k},{l}でも移動できます。

```conf
# move between panes
# (xmonad like)
bind-key -n M-j select-pane -t :.+
bind-key -n M-k select-pane -t :.-
# (vim window like)
bind-key h select-pane -L
bind-key j select-pane -D
bind-key k select-pane -U
bind-key l select-pane -R
```

ウィンドウ間の移動は(Left),(Right)か(num)で移動します。

```conf
# move between window
bind-key -n M-Right next-window
bind-key -n M-Left previous-window
```

新しいウィンドウを作成するには(Enter)です。

```conf
# create new window
bind-key -n M-Enter new-window
```

ペインを削除するには(x)、ウィンドウを削除するには(X)です。if文を使うことで、最後のペイン、最後のウィンドウであるときにだけ確認メッセージを表示させることができます。

```conf
# if session has > 1 windows in current, kill-pane without confirmation.
# But confirm before killing pane when it is the last pane in the window.
bind-key -n M-x 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"

# if session has > 1 windows in current, kill-window without confirmation.
# But confirm before killing window when it is the last window in the session. 
bind-key -n M-X 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"
```

アクティブなペインを隣のウィンドウに移すのは[S-Left],[S-Right]です。新しいウィンドウに移す場合、デフォルトの通り{!}です。

```conf
# join pane
bind-key -n S-Right join-pane -t :+
bind-key -n S-Left join-pane -t :-
```

アクティブなペインをある番号のウィンドウに移すには(S-num)です。

```conf
# switch windows Alt+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
```

### ウィンドウ内でのペインの操作

```conf
#
# In a window:
#
#   +---------------+------------+
#   |pane1          |pane3       |
#   |               |            |
#   |               |            |
#   +---------------+            |
#   |pane2          |            |
#   |               |            |
#   |               |            |
#   +---------------+------------+
# 
# split pane:
#   - vertically         : (|)
#   - horizontally       : (-)
# select pane            : (j,k) OR click the pane with mouse
# shift pane             : (J,K)
# kill pane              : (x)
# change layout          : (Space)
# fullscreen             : (f)
# resize pane:
#             (a)
#              ↑
#        (h) ← + → (l)
#              ↓        OR drag pane-border with mouse
#             (z)
# join to another window : [Shift+Left/Right]
# join to another window : (Shift+num)
#

```

ウィンドウの分割は(-),(|)でそれぞれ文字の形の通りに分割します。またVim的に{s},{v}でも分割できます。tmuxとVimで見かけのオプションの文字が違うのは混乱のもと。

```conf
# split window (easily remember)
bind-key -n M-- split-window -v
bind-key -n M-| split-window -h
# vim like
bind-key s split-window -v
bind-key v split-window -h
```

ペインのスワップ(ペイン番号をずらす)は、(J),(K)

```conf
# swap pane
bind-key -n M-J swap-pane -D
bind-key -n M-K swap-pane -U
```

アクティブなペインを最大化するには(f)

```conf
# maximize pane ("f"ull screen)
bind-key -n M-f resize-pane -Z
```

ペインのレイアウトを変更するには(Space)

```conf
# next layout
bind-key -n M-Space next-layout
```

ペインのリサイズをするには、(a),(z),(h),(l)で上下左右に境界を動かすことができます。

```conf
# resize panes (xmonad like)
bind-key -n M-h 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-l resize-pane -R 1
```

## まとめ

直感的なキーバインドを設定し、tmuxを使った作業が捗るようになりました。ぜひ現在のキーバインドに引っ掛かりを感じている人は、これを機に設定を見なおしてみるといいかもしれません。

こちらにあげてありますので、参考にしてください。
(**この記事を書いた時点から変更されています**)

- [dotfiles/tmux.conf at master · ssh0/dotfiles](https://github.com/ssh0/dotfiles/blob/master/tmux/tmux.conf)