---
title: "Tmux prefix swapping"
date: 2022-12-06
url: https://fortes.com/2022/tmux-prefix-swapping/
summary: "Smart tmux prefixes, like a boss"
---

I know you're sick of me talking about my terminal workflows, but you should keep something in mind: I lack the social graces to care.

I switched over to tmux just over a decade ago. Like many I came from [GNU Screen](https://www.gnu.org/software/screen/), which uses `C-a` as the prefix key. So I happily changed from tmux's `C-b` default to keep the muscle memory. Plenty of people do this, and it's mostly fine. At some point, I grew as a person and moved to `C-b` so I wouldn't be completely lost when working without my custom config, but I've always kept a soft spot for `C-a`.

Due to the aforementioned lack of social skills, I spend a lot of time ssh'd into other servers, where I of course also use tmux. Having nested sessions is mostly fine, except for the fact that you're now hitting your prefix key twice in order to send to the inner session. This, of course, slows me down while writing my terrible code (so perhaps a net good?).

## Better living through configuration

Fortunately, tmux's config format is flexible enough that we can detect a nested (or likely nested) session and choose a different prefix key.

The first step is to create a small config file per prefix you want to support (using a separate file is useful later on, bear with me):

```bash
# tmux.prefix-a.conf
unbind C-b
unbind C-g
set-option -gq prefix C-a
bind-key -N "Send prefix" C-a send-prefix
```

```bash
# tmux.prefix-b.conf
unbind C-a
unbind C-g
set-option -gq prefix C-b
bind-key -N "Send prefix" C-b send-prefix
```

```bash
# tmux.prefix-g.conf
unbind C-a
unbind C-b
set-option -gq prefix C-g
bind-key -N "Send prefix" C-g send-prefix
```

Then in your main `tmux.conf`, detect if you're connecting via SSH and automatically use `C-a`:

```bash
if-shell 'test -n "${SSH_CONNECTION}"' {
  source-file -q ~/.config/tmux/tmux.prefix-a.conf
}
```

Due to being a psychopath, I'll sometimes end up with a third level of nesting (in a docker container), so in that case I map to `C-g` (if this happens to you, I'm certain you can figure out the config yourself).

## On-demand prefix swapping

Sometimes the heuristics don't work, or maybe you just wanna switch things up, and that's where tmux's `display-menu` command comes in handy:

```bash
bind-key -N "Select prefix key" G {
  display-menu -T Prefix -x P -y P \
    "C-a" "a" "source-file -q ~/.config/tmux/tmux.prefix-a.conf" \
    "C-b" "b" "source-file -q ~/.config/tmux/tmux.prefix-b.conf" \
    "C-g" "g" "source-file -q ~/.config/tmux/tmux.prefix-g.conf" \
}
```

Hitting `<prefix> G` shows a native tmux menu and lets you change prefixes on the fly. In order to make it clear which prefix is active, we display it in the status bar (clicking it also shows the prefix swap menu, make sure you `set -g mouse on` somewhere in your config):

```bash
# Indicate prefix and when activated
set-option -gaq status-left \
'#{?client_prefix,\
#[bg=white fg=brightcyan reverse bright] #{prefix} #[bg=default default] ,\
#[dim]#{prefix}#[default] \
}'

bind-key -N "Select prefix key" -Troot MouseUp1StatusLeft {
  # Menu command goes here...
}
```

Here it is in action, pretty sweet!

<figure class="terminal"><a href="/2022/tmux-prefix-swapping/tmux-prefix-demo.gif"><img src="/2022/tmux-prefix-swapping/tmux-prefix-demo.gif" alt="Prefix nested and swapping, colorized" width="400" height="238" loading="lazy" decoding="async"></a>
  <figcaption>Prefix nested and swapping, colorized</figcaption>
</figure>


