Workflow Changes

Yesterday I was reading through my Ruby Weekly email and got sucked into a tmux workflow video. Although I have used tmux remotely, this video inspired me to add tmux to my local workflow. The following is a run down of my configuration, what I find awesome and what I find annoying.

Environment

I assume these are installed and configured.

Tmux

Before getting started I wanted to checkup on iTerm2’s native support of tmux. In the past, support was only available via a custom build of tmux. This was awkward and weird so I never tried it out. Now they support the official version of tmux. Whoop!

brew install tmux

In order to get iTerm2 tmux integration, you have to keep a window open that acts as the session communication channel for the tmux windows and panes. I agree with Dan and find that this will become annoying fast. Instead, I am not using the iTerm2 integration and using tmux as is.

I had to start somewhere, so I yanked Chris Hunt’s .tmux.conf and put it in my home directory.

Copy-Paste

To use this config and fix copy-paste issues with tmux on a mac, install reattach-to-user-namespace:

brew install reattach-to-user-namespace

Basically, tmux has it’s own pasteboard and is not able to read or write to the user’s pasteboard. This app reattaches tmux to the user’s pasteboard.

Prefix Keybinding

Back in the day I used ^Z and ^B as my tmux prefix key. I’m not a fan of finger gymnastics and changed it to ^A. Many people suggested this and I found it to be much easier to work with. However, after a few programming escapdes, I found that ^A was getting in my way.

When I am in tmux with vim, I am not able to increment numbers with ^A. It’s a small thing but I’d rather not retrain my brain to implement a longer key sequence.

I am also conditioned to being able to go to the beginning of the line in bash or zsh with ^A. (I could leverage vi-mode but I don’t feel like retraining my brain for that just yet.)

Chris' choice to use ^J as a prefix has made things flow quite nicely. I haven’t found any conflicts yet and I hope I don’t find any!

Pane Keybindings

I like rebinding to characters that match the split action:

# window splitting
unbind %
bind | split-window -h
unbind '"'
bind - split-window -v

I also like to map vim navigation to pane resizing:

# resize panes
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5

Mouse Configuration

After trying this configuration out for awhile, I began to realize that I kept trying to scroll back with the mouse. So, I needed my mouse to function according to my habits:

set -g mode-mouse on
set -g mouse-resize-pane on
set -g mouse-select-pane on
set -g mouse-select-window on

Dan’s mouse mode post has a pair of useful mouse toggle shortcuts:

bind m \
  set -g mode-mouse on \;\
  set -g mouse-resize-pane on \;\
  set -g mouse-select-pane on \;\
  set -g mouse-select-window on \;\
  display 'Mouse: ON'

bind M \
  set -g mode-mouse off \;\
  set -g mouse-resize-pane off \;\
  set -g mouse-select-pane off \;\
  set -g mouse-select-window off \;\
  display 'Mouse: OFF'

I am a huge proponent of keeping your fingers on the home row and using the mouse as little as possible. However, every once in a while I just want to resize a pane with my mouse or scroll back with my mouse. Having that extra nicety just feels good.

There is one draw back: mouse mode does not support selection.

When I scroll back to find something and select it, the mouse up event causes the buffer to jump back to the command prompt and deselects the selection.

There are two ways around this:

  1. Disable mouse mode before selecting text: ^J M
  2. Hold down the option key while selecting text

Both are not ideal but tolerable, given the benefits of tmux.

iTerm2

What really solidified tmux for me was Dan’s iterm2 keymaps for tmux customization. iTerm2’s ability to send hex codes definitely causes Angels to dance.

Here are my key sequences:

Key Sequence Hex Sequence Purpose
^D 0x04 disconnect from pane or window
^J c 0x0A 0x63 create new window
^J d 0x0A 0x64 detach from session
^J < 0x0A 0x3C previous window
^J > 0x0A 0x3E next window
^J | 0x0A 0x7C Split pane horizontally
^J - 0x0A 0x2D Split pane vertically
^J K 0x0A 0x4B Resize pane up
^J J 0x0A 0x4A Resize pane down
^J H 0x0A 0x48 Resize pane left
^J L 0x0A 0x4C Resize pane right
^J <arrow-up> 0x0A 0x1B 0x5B 0x41 move to pane above
^J <arrow-down> 0x0A 0x1B 0x5B 0x42 move to pane below
^J <arrow-right> 0x0A 0x1B 0x5B 0x43 move to pane at right
^J <arrow-left> 0x0A 0x1B 0x5B 0x44 move to pane at left

Here are my iTerm2 tmux shortcuts:

Shortcut Hex Sequence Purpose
Cmd-w 0x04 disconnect from pane or window
Cmd-t 0x0A 0x63 create new window
Cmd-d 0x0A 0x64 detach from session
Cmd-Left 0x0A 0x3C previous window
Cmd-Shift-h 0x0A 0x3C previous window
Cmd-Right 0x0A 0x3E next window
Cmd-Shift-l 0x0A 0x3E next window
Cmd-Shift-| 0x0A 0x7C Split pane horizontally
Cmd-Shift-_ 0x0A 0x2D Split pane vertically
Cmd-Opt-k 0x0A 0x4B Resize pane up
Cmd-Opt-j 0x0A 0x4A Resize pane down
Cmd-Opt-h 0x0A 0x48 Resize pane left
Cmd-Opt-l 0x0A 0x4C Resize pane right
Cmd-k 0x0A 0x1B 0x5B 0x41 move to pane above
Cmd-j 0x0A 0x1B 0x5B 0x42 move to pane below
Cmd-l 0x0A 0x1B 0x5B 0x43 move to pane at right
Cmd-h 0x0A 0x1B 0x5B 0x44 move to pane at left

Here are all of my iTerm2 global shortcuts:

iTerm2 Global Shortcuts

ZSH

Last but not least I added a few helpful commands to my .zshrc to make session management a little easier.

Command completion is always nice, so I added session name completion for my session function.

Make sure custom command completion is enabled:

fpath=(~/.zsh/completion $fpath)
autoload -U compinit
compinit

…and add the completion script:

Conclusion

Tmux is great at managing sessions and recoving from accidental disconnects. It still feels in the way at times but new things always do. It will take some time getting use to but I’m sure it has found a home.