Reservations - Avoiding Nests

For the longest time, I have been avoiding nesting my tmux sessions. This had been due to a combination of not having a usecase, and wanting to avoid ensuring my configuration could handle it well.

Even now I would still say that nesting should only be done with intention, after ensuring your setup will not leave you trapped.

Usecase

Now that I have gained a usecase, I have taken the time to tackle the issue.

My usecase includes sys admining multiple environments with 10+ hosts, and being annoyed at the limits of windows terminal/powershell terminal (the tools available for my work environments).

Prior Setup

I had been using windows terminal were possible, and falling back to the powershell terminal where not. Windows terminal isn't bad, and is a pretty decent step forward for windows. It even has tabs :) That said, it still has room to grow. Powershell could be worse as well but can be manageable after changing the default color profile.

In this case, I had been hitting the limits of how decent my workflow was with 10+ tabs (or windows on hosts without windows terminal), even with profiles created that would immediately ssh and attach to tmux or start tmux.

## Example "command line" field for windows terminal profile
ssh -t HOST "tmux attach -t 0 || tmux new"

Good to Know

There are a number of moving bits to highlight before we get into the setup.

  1. You will want to ensure you have a way of sending a tmux prefix signal to the nested instance
  2. Since you may end up nesting ssh, it is good to be aware of ssh escape sequences. <enter>~~. can exit an ssh instance a second level deep.
  3. ssh config files are amazing for adding aliases and having specific options for a host. I also use a catch all at the end of my file.
  4. If a nested tmux session ends uncleanly, such as from a network drop or a reboot, the higher level tmux instance can behave a bit badly with mouse mode. ie clicks can generate garbage. This can be recovered with a reset in the effected shell.

Nested Mode

What I ended up doing to make Nested Mode was

  • Make a prefix2
  • Toggle my preferred prefix of C-z into sending to the nested session. At this point prefix2 still works on the top level.
  • Tinker with the status color as an indicator.
  • Disable visual activity on the top level, as it was distracting.
  • Bonus -- A binding to toggle a mark on a window name, to allow for workflow tracking. ie "what servers is my current effort still waiting on"

And here is a snippet of the new tmux.conf:

### Key Bindings ###
unbind C-z                      ## Unbind C-z so I don't suspend, and free for bind
set -g prefix C-z               ## Change prefix key to C-z
bind-key C-z last-window        ## Make <prefix>C-z go to last window
#unbind C-a

## Nesting Bindings
set -g prefix2 C-b              ## Add secondary prefix
bind-key C-a send-prefix        ## Make <prefix>C-a send C-z literally
bind-key C-n set -ug prefix \; bind-key -n C-z send-keys C-z \; set status-fg yellow \; set visual-activity off ## Have C-z send input to nested tmux
bind-key C-u set -g prefix C-z \; set status-fg white \; set visual-activity on ## Restore top level prefix

## "mark" multiple window names for attention in personal workflow
## NOTE: Added escaping \ chars in conf, to get real escapes into binding. Setting from CLI doesnt need escaped escape chars.
bind ^ if-shell -F "#{m/ri:\\^$,#W}" "rename-window '#{s/\\^//:window_name}'" "rename-window '#W^'"

Window Name Marking

I particularly enjoy the prefix ^ binding above, as I can mark an arbitrary number of windows. The built in tmux marking really isn't for workflow tracking as it can only mark a single window at a time.

Other Extras to Go With Nesting

Status Bar Spacing Variable

As I nesting my tmux meant I was frequently having 10+ tmux windows in a half screen terminal emulator window, my status bar was starting to feel cramped. I ended up revisiting my existing SBS var, which I embed in my status bar for padding.

This improved version will even resized my status bar on the fly, when the threshold is hit.

TL;RD If there isn't enough room, the padding symbol is dropped.

## Status Bar Spacing variable
## Initial Setting, if <100 col use condensed margin;
## Then do math to see if there is too little room for all the windows, and drop the padding char.
%hidden SBS="#{?#{>=:#{window_width},100},#{?#{e|>=|:#{e|/|:#{e|-|:#{window_width},55},9},#{session_windows}}, ,},}"

Session Script

There are some nice tmux session tools out there, like tmuxinator. I got tired of tmuxinator breaking on arch everytime ruby updated...

So I decided it was time to just make a raw script. It was fairly simple :)

Here is a short example of a script to remote into multiple other tmux instances:

#!/bin/bash

## A script to start up custom profile of a tmux session
##
## NOTE: This assumes that "set -g base-index 1" is set.


SESSION="arch"


## Create a new detached tmux session if it doesn't exist
tmux has-session -t ${SESSION} 2>/dev/null


if [ $? != 0 ]; then
    ## Create Session
    tmux new-session -d -s ${SESSION} -c ${HOME}

    ## Create windows
    WINDOW='r4'
    NUM=1
    #tmux new-window -t ${SESSION}:1 -n 'r4'
    tmux rename-window -t ${SESSION}:${NUM} ${WINDOW}
    tmux send-keys -t ${WINDOW} "ssh -t ${WINDOW} 'tmux attach -t 0 || tmux new'" C-m

    WINDOW='r8'
    NUM=2
    tmux new-window -t ${SESSION}:${NUM} -n ${WINDOW}
    tmux send-keys -t ${WINDOW} "ssh -t ${WINDOW} 'tmux attach -t 0 || tmux new'" C-m

    WINDOW='ev'
    NUM=3
    tmux new-window -t ${SESSION}:${NUM} -n ${WINDOW}
    tmux send-keys -t ${WINDOW} "ssh -t ${WINDOW} 'tmux attach -t 0 || tmux new'" C-m
fi


## Attach after session generated
tmux attach-session -t ${SESSION}

dotfiles

If you want to see my full tmux, ssh, etc configs, you can look at my dotfiles

Links

tmux
windows terminal
ssh escape sequences
ssh config
tmuxinator
dotfiles

- demure