When I worked at Braintree, I pair-programmed full-time. Braintree had developed custom tooling that was tailored for a hassle-free pair-programming experience. The basic setup was vim as a text editor running inside tmux with custom key bindings and aliases. Developers were expected to work in this setup. I joined as an intern and at the time, my experience with development tools was limited to Atom. It was certainly overwhelming to have to learn vim shortcuts and spend an eternity on the simplest tasks but once I got a hang of it, I could really see my productivity increase. More details on how Braintree's vim/tmux setup works are on this blog.
One thing I am a little sad to admit is that I never bothered to look into how any of it worked. I knocked off the 'setup tmux' item from my onboarding checklist and that was it. Now that I don't need to use this setup for work, I miss it. I decided to setup tmux on my machine and learn how to customize it. Here is an attempt at compiling a quick guide for others who may be interested in giving this a shot.
Before diving into it, I would just like to mention that I understand that getting used to tmux takes time. All the different commands can be overwhelming and in the beginning it might not seem worth the effort. I strongly believe that if you give this an honest try, it will pay off. The key bindings will become muscle memory. In fact, multiple times while I was onboarding new engineers, I would draw a blank when someone asked me a command to do something on tmux but my fingers would always know what to do.
What is tmux?
tmux is a terminal multiplexer. It allows you to create multiple terminal windows, split panes vertically or horizontally, customize bindings/themes and it allows detaching/reattaching sessions which is extremely powerful when you have to work with remote boxes.
Setting up tmux
On Mac, brew install tmux
should do the trick. You can also get it from the Github repo directly by following the instructions here.
To run, simply type tmux
on your console and that should open up a new session with a new window. Initially, it isn't much to look at and might even be a little annoying but bear with me here. All commands on tmux need to be prepended by a "leader"/"prefix". By default, it happens to be Ctrl + b
. If you want to create a new window, you'll first type in the leader (Ctrl + b
) followed by a c
. Just looking at the placement of b
and Ctrl
on the keyboard, it is pretty obvious that having to input this combo over and over again is very counterproductive. This is where customizations come in.
Customizing tmux
tmux uses ~/.tmux.conf
to store configuration. Go ahead and create that file if it doesn't already exist. The very first thing to do is to get rid of the awkward prefix and change it to something more sane. I use Ctrl + a
with my caps lock key remapped to Ctrl
.
# set prefix to C-aunbind C-bset -g prefix C-abind C-a send-prefix
Since we are going to be experimenting quite a bit with the tmux configuration, it is a good idea to have a quick way to reload the tmux config.
# reload tmux config filebind r source ~/.tmux.conf
Each time there's an edit to ~/.tmux.conf
, reload it using prefix
+ r
.
Next up, we'd want to be able to split a window into vertical and horizontal panes. By default, tmux command to split a window/pane horizontally is prefix
+ "
and vertically is prefix
+ %
. This is pretty awkward too. I have personally gotten used to vim's split commands so I'm binding horizontal split to s
and vertical split to v
. This might not be very intuitive to people who haven't worked with vim before so feel free to use anything that makes sense. I've also seen |
for vertical splits and -
for horizontal as a visual reminder of the action.
# split windows like vimbind s split-window -v -c "#{pane_current_path}"bind v split-window -h -c '#{pane_current_path}'unbind '"'unbind %
The -c
simply specifies the "target client" and pane_current_path
is as the name suggests, the current pane.
Now that we can create new panes, we want to be able to move around them. By default, tmux uses prefix
+ ←
/ ↓
/ ↑
/ →
(arrow keys). While this isn't as bad as the ones above, I have personally gotten very used to vim's "arrow keys" h
/ j
/ k
/ l
so I bind the pane movement to these.
# move around the panes with hjklbind h select-pane -Lbind j select-pane -Dbind k select-pane -Ubind l select-pane -R
Note that I did not unbind the arrow keys so I can potentially use them too to move around the panes.
By default, tmux splits panes equally. If you want to have more space on a particular pane for a focused task and a side pane to tail logs (or whatever else your workflow requires), the provided way of doing that is prefix
+ :
. That opens up a prompt at the bottom of the screen. There you can type resize-pane
followed by a -
, direction (L
/ D
/ U
/ R
) and an optional number that represents how much you want to move a pane by (defaulted to 1).
prefix
+ :
(then in the prompt) resize-pane -L 10
As you can see this is quite cumbersome but you can add a binding for this action to your ~/.tmux.conf
# resize panesbind -r < resize-pane -L 10bind -r > resize-pane -R 10bind -r - resize-pane -D 10bind -r + resize-pane -U 10
The -r
toggles the client read-only flag.
If at any point you feel like you've messed up the sizing and want to go back to equal splits, you can add the following to your configuration:
# switch to tiled layoutbind = select-layout tiled
select-layout
applies a previously used layout. The tiled
layout spreads out the panes as evenly as possible. Other supported layouts are even-horizontal
, even-vertical
, main-horizontal
and main-vertical
. You can flip around these layouts using next-layout
which is bound to space
bar by default.
There is also a way to swap panes using prefix
+ {
/ }
. I personally haven't found a lot of use for it but depending on your needs, it could be helpful. One last thing that might be interesting is prefix
+ q
. It displays the 'id' of the panes in the current window.
To zoom into a particular pane, try prefix
+ z
. Getting out of the zoomed pane uses the same command. Finally, to kill a pane, all you have to do is prefix
+ x
. tmux will ask you to confirm if you really want to kill the pane. Enter y
and the pane is gone. If there are no panes on a window, the window will be removed too.
At this point, I would quickly like to mention that there is no need to memorize all these commands at once. Just knowing the existence of these commands, is good enough to get started. As you continue working, you'll have to look these up quite a bit in the beginning until your brain naturally starts to remember it and eventually it will become muscle memory so keep at it.
Now that we have covered panes, let's look into windows. As stated above, to create a new window, the default command is prefix
+ c
. Tmux likes to be smart and update the name of the window based on the last command that was run. I usually like to name windows based on what they are running so the first thing I'll recommend doing here is stopping the auto-rename.
set-option -g allow-rename off
You can rename your windows with prefix
+ ,
then just type in the name and hit enter.
To switch between windows, you can simply type prefix
+ <window number>
. Quite simply, if you want to go to window 2, prefix
+ 2
will do the trick. By default, tmux starts numbering windows from 0 and it is a hassle to have to go all the way to 0
each time you want to access that window. The following line in your configuration will make tmux start numbering from 1 instead.
# start numbering windows from 1 instead of 0set -g base-index 1
Styling your tmux
This part of the tmux configuration is highly subjective and yours might end up looking a lot different than what I have depending on your preferences and the changes you make overtime. I don't think diving deep into what each config line does is very helpful so I'm just going to add what I have and how it looks on my tmux. It is fairly straightforward but to understand what each command does, I would recommend playing around by tweaking things (for eg. change a config line to an outrageous color) and seeing what it impacts to then tailor it to your preferences.
# status bar themeset -g status 'on'set -g status-position bottomset -g status-bg 'colour235'set -g status-justify 'left'set -g status-left-length '20'set -g status-right-length '100'set -g status-left '#[fg=colour255,bg=colour233] #S #[fg=colour232,bg=colour235,nobold,nounderscore,noitalics]'set -g status-right '#[fg=colour237,bg=colour235,nobold,nounderscore,noitalics]#[fg=colour246,bg=colour235] %r %a #[fg=colour243,bg=colour235,nobold,nounderscore,noitalics]#[fg=colour222,bg=colour238] #H #[fg=colour237,bg=colour238,nobold,nounderscore,noitalics]#[fg=colour235,bg=colour235] 'setw -g window-status-format '#[fg=colour241,bg=colour235,nobold,nounderscore,noitalics]#[fg=color235,bg=color=235] #I#[fg=color246,bg=color235] #W #[fg=colour246,bg=colour235,nobold,nounderscore,noitalics]'setw -g window-status-current-format '#[fg=colour237,bg=colour238,nobold,nounderscore,noitalics]#[fg=colour222,bg=colour238] #I #W #F #[fg=colour243,bg=colour235,nobold,nounderscore,noitalics]'
Here's what my status bar looks like:
Note: I am using MesloLGS NF font on my iTerm which adds characters like the solid triangle (visible next to the session number, current window, etc. on my status bar). It will probably show up as a hollow rectangle on your system if you don't have fonts that support that character.
Adding plugins
You can take your setup a step further by using a host of plugins that developers have already put out. You can use 'tpm' which can be easily setup by following the instructions here.
# Pluginsset -g @plugin 'tmux-plugins/tpm'set -g @plugin 'tmux-plugins/tmux-sensible'set -g @plugin 'tmux-plugins/tmux-resurrect'# Initialize TMUX plugin managerrun '~/.tmux/plugins/tpm/tpm'
You can find a list of other available plugins here, or better yet — you can create your own!
In conclusion
There are plenty of customizations possible with tmux. For eg. you can even have the name of the song currently playing on your Spotify on the tmux status bar using this plugin or even the current temperature of the CPU. You can make it look the way you want and hyper-personalize it to make you productive. The key takeaway from this would be to get started and do your own research. Figure out what works for you, customize it to your needs and supercharge your terminal experience!