I have been exploring some new tools here and there. When I started watching Primeagen, I took a note of several tools that he was using and advocating for. One of them was tmux.
What is tmux?#
tmux is a terminal multiplexer. What that means is you can have many terminals in one. According to tmux wiki:
tmux is a program which runs in a terminal and allows multiple other terminal programs to be run inside it. Each program inside tmux gets its own terminal managed by tmux, which can be accessed from the single terminal where tmux is running - this called multiplexing and tmux is a terminal multiplexer.
tmux goes further by allowing you to have a lot of control over how the terminals are displayed, how they function, and how are they styled. You can have many separate windows as tabs. You can have many panes within one window. Are you working on several different projects? Then why don’t you have multiple sessions - each of them containing sets of windows and panes - all giving you access to multiple terminals. With a tool like this you no longer need to arrange multiple terminal instance windows on your desktop or using multiple workspaces for those instances - you can have it all in one place.
One additional feature that tmux boasts in is the ability to retain the terminal session upon its closure. Imagine that you have a long running process like a local server or a persistent connection like ssh session. If you were to close that window, you would lose that session and the process that was in it. Tmux has the ability to detach and attach to multiple sessions making them easier to manage and not to worry about losing it.
tmux wiki goes into detail talking about several other features of tmux:
The main uses of tmux are to: Protect running programs on a remote server from connection drops by running them inside tmux.
Allow programs running on a remote server to be accessed from multiple different local computers.
Work with multiple programs and shells together in one terminal, a bit like a window manager. For example: A user connects to a remote server using ssh(1) from an xterm(1) on their work computer and run several programs. perhaps an editor, a compiler and a few shells.
They work with these programs interactively, perhaps start compiling, then close the xterm(1) with tmux and go home for the day.
They are then able to connect to the same remote server from home, attach to tmux, and continue from where they were previously.
My first tmux experience#
The first impression of tmux didn’t leave me with much excitement of exploring what is truly possible :/ Source: https://github.com/tmux/tmux/wiki/Getting-Started
When I first started using tmux, I felt overwhelmed by the very poor default UI that it offers and the amount of options and shortcuts that I needed to know to operate it well and be productive. It took me several tries before I started to feel more or less comfortable with it.
One of the things that stood out to me right away was how dreadful UI looked. Not only it felt uninviting, but it almost felt “gatekeepy” - if you don’t know how to use it in this configuration, then might as well forget about it. But one thing that kept me going was the promise of a highly customizable terminal that I could make my own at some point.
While promising all of these amazing features, the dreadful tmux UI didn’t necessarily inspire :( Source: https://github.com/tmux/tmux/wiki/Getting-Started
Customization journey#
To preface, I must mention that I am using iterm2 with Powerline10k and NerdFonts. They heavily affect the final look of the tmux due to colors and icons being inherited from the iterm2 configuration. With that said, let’s get into it.
The file that is responsible for customizing tmux - its function and its look - is .tmux.conf . This file should be located in user’s Home folder a.k.a. ~/ . That is where tmux will be looking for it.
There are quite a few options when it comes to customizing tmux. One of the first things that I wanted to address was the prefix key binding. This prefix is a key combination that you would use to enter the tmux shortcut or command mode. By default, the prefix is C-b a.k.a. Ctrl-b . One of the common remaps that most people go with is to switch it to C-a , which is a lot easier to use. To do that, we need to add the following lines to the configuration file:
# remap prefix from 'C-b' to 'C-a' unbind C-b set-option -g prefix C-a bind-key C-a send-prefix
While researching ways to customize tmux, I stumbled upon several more useful key remaps, which I decided to use:
# split panes using | and - bind | split-window -h bind - split-window -v unbind '"' unbind % # reload config file (change file location to your the tmux.conf you want to use) bind r source-file ~/.tmux.conf ; display-message "~/.tmux.conf reloaded." # switch panes using Alt-arrow without prefix bind -n M-Left select -pane -L bind -n M-Right select -pane -R bind -n M-Up select -pane -U bind -n M-Down select -pane -D # switch windows using Shift-arrow without prefix bind -n S-Left previous-window bind -n S-Right next-window
Here we are changing function to split window from C-a " to C-a | for vertical splits and from C-a % to C-a - for horizontal splits, which is a lot more intuitive. Next we are creating several useful keybinds: C-a r to source the configuration file, M-Left , M-Right , M-Up , M-Down for faster navigation between the panes ( M being either Alt or Option ), and S-Left and S-Right for better navigation between the windows ( S being Shift ). These changes alone have already made my tmux experience 10x better than before.
Next, I wanted to improve my experience when scrolling the terminal output. By default, if you were to attempt to scroll it up or down, tmux would iterate over the history of the commands that you have executed. I would like to be able to look over the previous output and be able to operate on it. By default it is possible by entering the copy mode using C-a [ . Once you’re there, it gives you very little to work with - the default terminal output retention is quite small. To fix all of these issues, I used the following configuration:
# Increase the scrollback buffer to a higher limit than the default 2000 lines set -g history-limit 9999999 # Enable mouse control (clickable windows, panes, resizable panes) set -g mouse on # Enable vim keybinds to be used in copy mode set-window-option -g mode-keys vi
These settings enable tmux retain 9999999 lines of terminal output (more than enough for me), enable using mouse, which removes the necessity to enter the copy mode to browse terminal output, and lastly enable Vim key bindings when in copy mode to quickly search and navigate through it.
And that brings us to styling tmux. As I mentioned, I didn’t like the original UI much, so I felt strongly about changing that. To do that, I used the following configuration:
# clock mode setw -g clock-mode-colour yellow # copy mode setw -g mode-style 'fg=black bg=yellow bold' # panes set -g pane-border-style 'fg=yellow' set -g pane-active-border-style 'fg=green' # statusbar set -g status-position top set -g status-justify left set -g status-style 'fg=green' set -g status-left '' set -g status-left-length 10 set -g status-right '#[fg=green,bg=default,bright]#(tmux-mem-cpu-load) #[fg=red,dim,bg=default]#(uptime | cut -f 4-5 -d " " | cut -f 1 -d ",") #[fg=white,bg=default]%a%l:%M:%S %p#[default] #[fg=blue]%Y-%m-%d' setw -g window-status-current-style 'fg=black bg=green' setw -g window-status-current-format ' #I #W #F ' setw -g window-status-style 'fg=green bg=black' setw -g window-status-format ' #I #[fg=white]#W #[fg=yellow]#F ' setw -g window-status-bell-style 'fg=black bg=yellow bold' # messages set -g message-style 'fg=black bg=yellow bold'
These lines attempt to create a (subjectively) better looking UI that is easier on the eyes and more intuitive. It uses standard color names that would fit the color scheme that your terminal is already using so that it doesn’t stick out too much. Although it is very much possible to use whatever colors you want here - tmux is your oyster. Here we are also calibrating the positioning of the elements like status bar, look and function of parts of the status bar, and lastly colors for messages and copy mode.
Finally, let’s add tmux plugin manager. That’s right - tmux has a whole library of community maintained plugins. If you want to you can find entire plugins that will change the look and feel or your tmux in an instant. The reason I decided to go with my own configuration is so that I could learn it better and own it. Any new theme plugin would require some learning to know how it functions and where everything is. Regardless, configuring tmux plugin manager can be done in just a few lines:
# List of plugins set -g @plugin 'tmux-plugins/tpm' set -g @plugin 'tmux-plugins/tmux-sensible' # Other examples: # set -g @plugin 'github_username/plugin_name' # set -g @plugin 'github_username/plugin_name#branch' # set -g @plugin '[email protected]:user/plugin' # set -g @plugin '[email protected]:user/plugin' # Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf) run '~/.tmux/plugins/tpm/tpm'
One note to make here is that you would need to clone the repository for tmux plugin manager into ~/.tmux/plugins/tpm for it to work. You can do that by following instructions on the tmux plugin manager GitHub repository.
I haven’t installed many plugins just yet because I am still exploring which plugins I would want to have installed. I have several that I’m interested in exploring and giving a go:
Full configuration#
Here is a full configuration file. It includes a couple of other features that I haven’t mentioned because they are less significant than the ones that I have highlighted.
# remap prefix from 'C-b' to 'C-a' unbind C-b set-option -g prefix C-a bind-key C-a send-prefix # split panes using | and - bind | split-window -h bind - split-window -v unbind '"' unbind % # reload config file (change file location to your the tmux.conf you want to use) bind r source-file ~/.tmux.conf ; display-message "~/.tmux.conf reloaded." # switch panes using Alt-arrow without prefix bind -n M-Left select -pane -L bind -n M-Right select -pane -R bind -n M-Up select -pane -U bind -n M-Down select -pane -D # switch windows using Shift-arrow without prefix bind -n S-Left previous-window bind -n S-Right next-window # Increase the scrollback buffer to a higher limit than the default 2000 lines set -g history-limit 9999999 # Enable mouse control (clickable windows, panes, resizable panes) set -g mouse on # Enable vim keybinds to be used in copy mode set-window-option -g mode-keys vi # don't rename windows automatically # set-option -g allow-rename off # rename window to reflect current program setw -g automatic-rename on # renumber windows when a window is closed set -g renumber-windows on # don't do anything when a 'bell' rings set -g visual-activity off set -g visual-bell off set -g visual-silence off setw -g monitor-activity off set -g bell-action none # clock mode setw -g clock-mode-colour yellow # copy mode setw -g mode-style 'fg=black bg=yellow bold' # panes set -g pane-border-style 'fg=yellow' set -g pane-active-border-style 'fg=green' # Allows for faster key repetition # set -s escape-time 50 # statusbar set -g status-position top set -g status-justify left set -g status-style 'fg=green' set -g status-left '' set -g status-left-length 10 set -g status-right '#[fg=green,bg=default,bright]#(tmux-mem-cpu-load) #[fg=red,dim,bg=default]#(uptime | cut -f 4-5 -d " " | cut -f 1 -d ",") #[fg=white,bg=default]%a%l:%M:%S %p#[default] #[fg=blue]%Y-%m-%d' setw -g window-status-current-style 'fg=black bg=green' setw -g window-status-current-format ' #I #W #F ' setw -g window-status-style 'fg=green bg=black' setw -g window-status-format ' #I #[fg=white]#W #[fg=yellow]#F ' setw -g window-status-bell-style 'fg=black bg=yellow bold' # messages set -g message-style 'fg=black bg=yellow bold' # List of plugins set -g @plugin 'tmux-plugins/tpm' set -g @plugin 'tmux-plugins/tmux-sensible' # Other examples: # set -g @plugin 'github_username/plugin_name' # set -g @plugin 'github_username/plugin_name#branch' # set -g @plugin '[email protected]:user/plugin' # set -g @plugin '[email protected]:user/plugin' # Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf) run '~/.tmux/plugins/tpm/tpm'
This file could also be found in my GitHub repo: https://github.com/EvgeniiKlepilin/config-files/blob/main/.tmux.conf . I will keep updating it as I continue my customization efforts, so stay tuned.
Final look#
In the end, here is what my tmux looks like now:
Much better! 😎
I hope you will find this useful and maybe even inspiring to create something custom of your own!