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.
- You will want to ensure you have a way of sending a tmux prefix signal to the nested instance
- 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. - 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.
- 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