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-namespace
but 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 | fzf
is 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 | fzf
is great for listing out keybindings- I ran into
'~/.tmux/plugins/tpm/tpm' returned 1
and 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 1
error reappeared. The core issue was launching tmux directly outside of a terminal session. This causedPATH
to not be modified by shell configuration files to include homebrew. Setting the path explicitly in tmux config fixed this. - I found that
tmux-copycat
was 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-environment
does not update the shell launched from tmux, butupdate-environment
did 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-cancel
andcopy-selection-and-cancel
are equivilent if there is only one param (pbcopy
) passed. Thepipe
variant 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-D
andC-d
are equivilent. - tmux-sidebar is a cool concept, but seems messier than a simple
ls
ortree
when 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 optcmd
does 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
, andread
are 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\e
or\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^[f
for 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
Space
to enable selectionV
to enable vertical selectionV
select lineEsc
clear selection
Navigating Text
{, }
next and prev paragraphM
jump to the middle of the bufferb
jump to prompt startH
is top,L
is bottom (of buffer)g
is history top,G
is history bottomu
is page up,d
is page downU
is page up 3x,D
is page down 3x (this is custom)
Copying Text
Cntrl+D
to copy end of line, trim newline and trailing/leading spaces- Enter to copy the entire line that the cursor is on
cntrl+w
to copy till the end of the word and trim whitespacet
to copy content after cursor, to end of line, and trim trailing whitespaceT
to copy content after cursor, to end of line, and trim trailing and leading whitespaceo
open selected text with default application (from tmux-open)- With tmux-yank,
y
to copy text andShift+Y
to 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-Y
to copy pwd to clipboardprefix-p
to copy current prompt line to clipboard (modifed version from tmux-yank)prefix-/
for move-as-you-type live searches- With tmux-fastcopy
prefix-f
will 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;3C
and\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.