Session switching with the tmux menu

| 4 min read

Here's a way to get a simple session switcher in tmux using a popup menu.

I was looking at Waylon Walker's tmux fzf session jumper recently, and really liked it, so much so that I dug into the incantations that he shared, resulting in a new post on this autodidactics blog: tmux output formatting.

Anyway, I was still thinking about session switching yesterday, and randomly came across this Reddit post: how to bring up context menu without a mouse. I'd seen the context menu before, by accidentally triggering it with the right mouse button, and it looks something like this:

context menu

It was the comment by user Coffee_24_7 that really got me thinking - turns out that this type of menu can be called up with one of the myriad tmux commands, one which I hadn't yet come across: display-menu.

Building a context menu

I thought that using a context menu like this to present a list of sessions to switch to would be fun and teach me more about the display-menu command. Basically I just wanted to have the menu display the sessions I had, and when I'd selected one, switch me to it. So, this is what I did.

The first part of the tmux man page for the display-menu command looks like this:

display-menu [-O] [-c target-client] [-t target-pane] [-T title] [-x position] [-y position] name key command

Display a menu on target-client. target-pane gives the target for any commands run from the menu.

A menu is passed as a series of arguments: first the menu item name, second the key shortcut (or empty for none) and third the command to run when the menu item is chosen. The name and command are formats, see the FORMATS and STYLES sections. If the name begins with a hyphen (-), then the item is disabled (shown dim) and may not be chosen. The name may be empty for a separator line, in which case both the key and command should be omitted.

-T is a format for the menu title (see FORMATS).

So it looked like I would need something like this to have three sessions listed, with shortcut keys 1-3, and commands to switch to the selected one:

tmux display-menu \
writing 1 'switch-client -t writing' \
dotfiles 2 'switch-client -t dotfiles' \
focus 3 'switch-client -t focus'

(The session names in this example are actually the permanent sessions I use right now.)

Listing the sessions

From the tmux output formatting post we already know how to do this. The basic tmux list-sessions command produces something like this:

dotfiles: 2 windows (created Thu Aug 12 10:06:53 2021)
focus: 1 windows (created Wed Aug 11 10:44:18 2021)
writing: 1 windows (created Wed Aug 11 10:46:21 2021) (attached)

To get just the session names, I can supply a format with the -F option, like this (specifying #S for "session name"):

tmux list-sessions -F '#S'

This produces:


Creating the input

For each of the menu entries, three values are needed - the session name, an incrementing identifier (which becomes the single key to press for selection), and the switch-client command to switch to the selected session. There are many ways to turn this list of sessions into something like this; I'm going to use awk here, for these reasons:

  • I like awk and its history
  • it has a nice NR built-in variable that holds the record number being processed, and I can use it for the incrementing identifier
  • I can set ORS, the Output Record Separator (which is usually a newline), to a space, to avoid having to use something like tr or paste to bring everything onto one line afterwards

The invocation now becomes:

tmux list-sessions -F '#S' \
| awk 'BEGIN {ORS=" "} {print $1, NR, "\"switch-client -t", $1 "\""}'

This produces:

dotfiles 1 "switch-client -t dotfiles" focus 2 "switch-client -t focus" writing 3 "switch-client -t writing"

Using the input for the menu

Now I can just pass that entire output, via the venerable xargs, to tmux's display-menu command. While I'm at it, I'll use the -T option to supply a title for the top of the menu display.

This is what the invocation finally becomes:

tmux list-sessions -F '#S' \
| awk 'BEGIN {ORS=" "} {print $1, NR, "\"switch-client -t", $1 "\""}' \
| xargs tmux display-menu -T "Switch session"

It's worth putting this in a script, so I have done: session-menu.

Bind the menu to a key

The final touch in this learning experiment is to bind this invocation to a key in tmux, so that I can quickly invoke it. I'll choose "prefix Ctrl-s", which means the line I need to add to my config looks like this:

bind-key C-s run-shell session-menu

And with this in place, I can invoke the session switch menu popup very comfortably - this is what it looks like:

session switch menu

If I decide I don't want to switch sessions after all, I can just dismiss the menu with the standard key q (this is also in the display-menu part of the tmux man page).

So there you have it. I do love fzf and all the things it can do, but it's worth spending some time on this native tmux feature. There's more to it, as well - for example, you can add separators and disabled items (like the ones in the first screenshot in this post) - but this will do me nicely for now. Happy multiplexing!