Mastering Tmux
Tags: coding, learning, software • Categories: Software, Uncategorized
Tmux has been one of the best things I’ve added to my developer toolkit. After my initial dive into tmux, I’ve slowly learned more about the system and made some additional improvements to my workflow.
Some notes from my tmux learnings over the last couple years:
- It’s been great that tmux continues to get consistent updates. Mad props to the developer who has maintained this tool for quite a long time without too much funding.
- In recent versions of tmux, you don’t need
reattach-to-user-namespacebut you do need to remap default keybindings to usepbcopy. From my research, it wasn’t clear that you still needed to modify your config to usepbcopy, but you definitely do. - tmux-copycat modifies all copy-mode keybindings which cancel, this is why your keybindings might look crazy mutated
tmux show-option -g | fzfis great for inspecting options that are set in the tmux session- Here’s all of the default keybindings tmux provides. Some of these are more complex than you’d think
tmux list-keys | fzfis great for listing out keybindings- I ran into
'~/.tmux/plugins/tpm/tpm' returned 1and it was causing strange issues. I had to nuke everything to fix the issue:rm -rf ~/.tmux/plugins && git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm && tmux kill-server - Another time, the
returned 1error reappeared. The core issue was launching tmux directly outside of a terminal session. This causedPATHto not be modified by shell configuration files to include homebrew. Setting the path explicitly in tmux config fixed this. - I found that
tmux-copycatwas really slow compared to native search and I opted for writing my own searching shortcuts. - You can specify a list of environment variables to be copied from the originating shell (if you are launching tmux from another shell) using
update-environment. It seems likeset-environmentdoes not update the shell launched from tmux, butupdate-environmentdid the trick for me when attempting to propogageVSCODE*variables to tmux. - Tmux variables that are an array can be specified with a space-separated string. Example:
set -g update-environment "VSCODE_GIT_ASKPASS_EXTRA_ARGS VSCODE_GIT_ASKPASS_MAIN VSCODE_GIT_IPC_HANDLE VSCODE_INJECTION" copy-pipe-and-cancelandcopy-selection-and-cancelare equivilent if there is only one param (pbcopy) passed. Thepipevariant is useful when running a shell script to transform the selection before passing it to the clipboard tool.- Tmux differentiates between "physical" and "virtual" lines. Physical lines: Actual lines in the terminal window. Virtual lines: Lines in the tmux buffer, which can exceed visible area
- You can create custom commands using a tmux config. Configuration can only be bound to keyboard bindings, not an arbitrary command string. You cannot create commands and then remix them.
- This isn’t a tmux thing, but there is no casing difference when a keyboard shortcut is using the control modifier. In other words,
C-DandC-dare equivilent. - tmux-sidebar is a cool concept, but seems messier than a simple
lsortreewhen you want to get a file listing. - tmux-jump is great, but the same functionality can basically be achieved with custom livesearch and
tmux-fastcopy - You can use variables within tmux configuration
Upgrading Tmux & Plugins
Here’s how to upgrade tmux + TPM plugins when a new tmux version comes out:
brew upgrade tmux
# to upgrade plugins, within a tmux session tmux: prefix-U
# this will destroy all of your sessions so the latest version of tmux can be launched
tmux kill-server
Now open up a new terminal, prefix+: and then run display-message -p '#{version}' to make sure you are using the latest version.
Unbound Copy-mode Commands
Here’s a list of all copy-mode commands that don’t have any keybindings by default. This was helpful for me to understand what commands are worth investigating.
copy-end-of-line
copy-end-of-line-and-cancel
copy-pipe-end-of-line
copy-line
copy-line-and-cancel
copy-pipe-line
copy-pipe-line-and-cancel
copy-pipe
copy-pipe-no-clear
copy-pipe-and-cancel
copy-selection
copy-selection-no-clear
Modifier Keys & Escape Sequences
Understanding modifier keys and how they are described with escape sequences is helpful to not being completely confused when mutating keybindings.
- Nice guide to tmux modifier keys here
^is control^[is optcmddoes not have an escape sequence in the terminal- arrow keys are mapped to specific keys based on your terminal configuration. You’ll need to marry up how tmux + your terminal thinks about arrow keys to make your life easier.
od -tx1,cat, andreadare all ways to get the raw key bindings that are being sent to the terminal. This is helpful for debugging^[[part is actually a single escape character, often represented as\eor\033. Try opening up alacritty , runningcat, and pressing the arrow keys to see this in action.- Escape codes are often different across terminal emulators.
^[b^[ffor meta-left arrow and meta-right arrow and others use;3D;3C(Extended Keyboard Codes)
Keyboard Copy Mode Navigation
Here’s a cheat sheet to navigating tmux when in copy mode.
Managing Selection
Spaceto enable selectionVto enable vertical selectionVselect lineEscclear selection
Navigating Text
{, }next and prev paragraphMjump to the middle of the bufferbjump to prompt startHis top,Lis bottom (of buffer)gis history top,Gis history bottomuis page up,dis page downUis page up 3x,Dis page down 3x (this is custom)
Copying Text
Cntrl+Dto copy end of line, trim newline and trailing/leading spaces- Enter to copy the entire line that the cursor is on
cntrl+wto copy till the end of the word and trim whitespacetto copy content after cursor, to end of line, and trim trailing whitespaceTto copy content after cursor, to end of line, and trim trailing and leading whitespaceoopen selected text with default application (from tmux-open)- With tmux-yank,
yto copy text andShift+Yto copy and paste text to zsh buffer
Copy Last Terminal Command Output
One thing I’ve always wanted is an easy way to select + copy the output of the last command. It’s possible, but requires some work:
- Custom fork of pure to add a special non-breaking character
- Pretty long tmux command
But with these two things in place opt+shift+up arrow magically selects the last output of my terminal command.
One of the downsides with this is I need to manually keep my fork of the pure repo up to date since I cannot heavily customize the prompt of pure using ENV vars.
This is a bummer, but it’s a quick script and tmux plugins don’t change much. The whole ecosystem is remarkably stable and feels very much like "finished software".
cd /Users/mike/Projects/zsh/pure
g pull --rebase upstream HEAD
g push --force origin HEAD
Copying Text Outside of Copy Mode
prefix-Yto copy pwd to clipboardprefix-pto copy current prompt line to clipboard (modifed version from tmux-yank)prefix-/for move-as-you-type live searches- With tmux-fastcopy
prefix-fwill highlight common text patterns so you can easily copy them - You can define a keybinding that gets you right into copy mode without hitting the prefix, I really like this. I use ctrl+opt+k
As an aside, here’s a great list of macOS emacs-style bindings. Better keyboard-based text navigation on macOS!
Fixing iTerm CSI U (extended mode)


Here’s the iTerm config that worked for me:
- Use command
/opt/homebrew/bin/tmux - CSI U enabled
- Esc+ for left + right option key
And here’s the key mapping that was needed specifically for extended key mode in iTerm. The interesting bit here is M-Right and M-Left is not reported by these keys in non-CSI U mode (i.e. vs code integrated terminal / xterm.js). Instead left/right is reported as ESC-b and ESC-f, and I have no idea why this is—maybe because right/left arrow was not part of the original keybindings?
- I’m not sure why, but only in iterm (and I have tmux -CC disabled) the M-Left & M-Right arrow keys report
\e[1;3Cand\e[1;3D. Tmux seems to consider these M-Right and M-Left. This fixes M-{Arrow} word navigation for me. Weirdly enough, iTerm only does this in a tmux session: not in zsh, bash, etc (although these are not consistent either). - To get iTerm working properly with tmux I used Esc+ as the option key modifier and "Report modifiers using CSI u". Without CSI U I had weird keybindings errors.
Copying VS Code Environment Variables to Tmux
In my last post, I created a script to open tmux in vscode and nicely name & restore the sessions. I found there were a handful for VSCODE_* variables injected into the terminal that were not copied over. This can effect the terminal integration and other ways the terminal operates, so I wanted to update my script to get them copied over.
Conclusion
Although it can be nuanced, tmux is a great tool for your virtual toolbox. While there’s always more to learn, it has consistently been reliable and versatile. If you’re not using tmux yet, I think it is definitely worth diving into—it will help optimize your terminal usage.