Level up with tmux
Following on from the last development productivity post, let’s look at using tmux to speed up working with terminals in development.
tmux is a terminal multiplexer, allowing you to tile multiple terminals side by side in a single terminal window. This can be useful in development, when you need to run multiple long running processes at the same time, e.g. development servers, file watchers, and docker containers.
For example, here’s my tmux session for BackupsHQ:
There are two windows called “editor” and “server”. In the “editor” window I have three panes - one for my editor and two for shells in different directories. In the “server” window I have four panes with long running processes - a web server, docker containers, webpack, etc.
The tmux wiki explains the difference between sessions, windows, and panes in depth.
Tmux is a little hard to get comfortable with, so here are some tips I’ve learned to level up your tmux skills.
Use a sensible prefix key
Every tmux command begins with a prefix key, e.g. Prefix + c
to create a new window or Prefix + x
to close the current pane.
The prefix is Ctrl-b
out of the box, which isn’t particularly friendly.
Instead, I recommend Ctrl-a
- your left hand can reach it easily while your right hand hits the other shortcut key.
Here are the relevant lines to add to .tmux.conf
:
# Remove the default prefix key binding
unbind C-b
# Set the prefix key to ctrl-a
set -g prefix C-a
# Send the C-a key to the terminal by pressing it twice
bind C-a send-prefix
Also, if you set the Caps Lock key as another Ctrl (highly recommend for emacs users like me), hitting Ctrl-a
is a very simple left hand chord - Caps Lock
and a
.
An earlier alternative to tmux, GNU Screen, uses Ctrl-a
as its prefix too.
Vi keybindings
Moving between panes is done with the arrow keys, e.g. Prefix + ↓
to move to the pane below.
For vi aficionados, key bindings can be easily added:
# Move between panes with vi keys
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
Capital letters can be used to resize panes:
# Resize the current pane with upper case vi keys
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
And Ctrl could even be used to move between windows:
# Move to the window left and right
bind -r C-h select-window -t :-
bind -r C-l select-window -t :+
Tmux also supports vi keybindings when in copy mode. Add setw -g mode-keys vi
to your config, then entering copy mode (Prefix + [
) will enable vi-style navigation of the current pane.
Even visual mode (v
) works!
Zoom
A novel tmux feature for users coming from Screen is the “zoom” command.
Pressing Prefix + z
will make the active pane fill the entire window, and pressing it again will revert to its previous position.
I find this especially handy when inspecting failing tests - I put a test runner in a small pane underneath my editor, and zoom the pane when looking at the failing results.
As well as Prefix + z
, use Prefix + ?
to see all the available keys.
There are lots of useful combinations!
Quick session switcher
Switching between sessions from within tmux is fairly easy (Prefix + s
), but creating and attaching to sessions outside of tmux is a little trickier:
# Create a new tmux session called 'work' and attach to it
tmux new -s work
# Attach to an existing session called 'work'
tmux attach -t work
It gets more cumbersome if you’ve forgotten about an existing session:
# The 'work' session already exists
tmux new -s work
duplicate session: work
A bit of bash scripting and fzf, the fuzzy-finding swiss army knife, can solve this problem:
# Attach to or create a tmux session with fuzzy matching
tm() {
# If we're in a tmux session, we want to call `switch-client`, otherwise we want `attach-session`.
[[ -n "$TMUX" ]] && command="switch-client" || command="attach-session"
# If an argument has been supplied, try to attach to that session.
# If that doesn't work, create a new session with the argument as the name and attach to it.
if [ $1 ]; then
tmux $command -t "$1" 2>/dev/null || (tmux new-session -d -s $1 && tmux $command -t "$1"); return
fi
# If no argument has been supplied, list all tmux sessions and get the user to pick with fzf
session=$(tmux list-sessions -F "#{session_name}" 2>/dev/null | fzf --select-1 --exit-0) && tmux $change -t "$session" || echo "No sessions found."
}
After adding this function in your .bashrc
or .zshrc
, attaching to sessions is easy:
# Attach to the 'work' session, creating it if it doesn't exist
tm work
# Attach to the existing 'work' session (short-hand supported)
tm wo
# List all sessions and pick the one to attach to with fzf
tm
Quick reload of the config file
When tweaking .tmux.conf
, it can get frustrating to close the session and start it again to see the changes applied.
With this line, Prefix + r
will reload .tmux.conf
without restarting tmux:
bind r source-file ~/.tmux.conf \; display "Reloaded .tmux.conf"
Watch out for config syntax differences
Depending on the version of tmux, the syntax of the configuration file can be very different.
For example, setting colours on recent tmux versions looks like this:
set -g status-style fg=default,bg=colour234
set -g message-style fg=default,bg=colour234
set -g pane-border-style fg=colour234,bg=default
set -g pane-active-border-style fg=colour67,bg=default
setw -g window-status-style fg=default,bg=colour234
setw -g window-status-current-style fg=colour67,bg=colour234
setw -g window-status-activity-style fg=colour234,bg=colour245
While on older versions, it looks like this:
set -g status-fg default
set -g status-bg colour234
set -g message-fg default
set -g message-bg colour234
set -g pane-border-fg colour234
set -g pane-border-bg default
set -g pane-active-border-fg colour67
set -g pane-active-border-bg default
setw -g window-status-fg default
setw -g window-status-bg colour234
setw -g window-status-current-fg colour67
setw -g window-status-current-bg colour234
setw -g window-status-activity-fg colour234
setw -g window-status-activity-bg colour245
More resources
- The tmux wiki is a comprehensive guide to all things tmux.
- tmux 2: Productive Mouse-Free Development by Brian P. Hogan is a fantastic deep dive into using tmux as a full-time development environment.
- The thoughtbot blog has some interesting tmux articles:
- My .tmux.conf contains all the tips mentioned in this post.
- Tools like tmuxp and tmuxinator allow you to automate the setup of tmux sessions for different projects.