4

I would like to have my machines setup so that everytime a shell is spawned, a tmux session is started.

Also, I normally log in to multiple SSH servers, and I would like for them to be setup the same.

Finally, I would like for each machine / server to have a different color set for the status bar, and for this color to be automatically generated and unique to the system, so that I don't have to choose a color each time I'm deploying a new local or server installation (this would be especially useful for docker instances), and so that I don't have to configure each installation past the user's ~/.bashrc just for this.

Having a different status bar color for each installation would be especially useful when connecting to one of the servers; normally, this would have the effect of "stacking" the server's tmux status bar on top of the local machine's tmux status bar already (technically giving some sort of clue that one's connected to a server); however, that's not very visible, and doesn't give a clue about which server one's connected to.

So how do I auto-start tmux, setting the status bar to a system-unique color?

1 Answer 1

6

Put this in your user's ~/.bashrc:

if [ -z "$TMUX" ]; then
    tmux_default_session_name=Default

    tmux_bg_color=#
    tmux_fg_color=#000000

    tmux_bg_color_brightness=0

    for c in $(cut -c27- /etc/machine-id | fold -w2); do
        tmux_bg_color="${tmux_bg_color}${c}"
        tmux_bg_color_brightness=$((tmux_bg_color_brightness + 16#${c}))
    done

    tmux_bg_color_brightness=$((tmux_bg_color_brightness / 3))

    [ "$tmux_bg_color_brightness" -lt 128 ] && tmux_fg_color=#ffffff

    tmux new-session -d -s "$tmux_default_session_name"

    tmux set-option -t "$tmux_default_session_name" status-style "bg=${tmux_bg_color}"
    tmux set-option -at "$tmux_default_session_name" status-style "fg=${tmux_fg_color}"
    tmux set-option -at "$tmux_default_session_name" terminal-features ',*:RGB'

    tmux attach -t "$tmux_default_session_name"

    exit "$?"
fi

screenshot


For the automatic start part, all we need to do is to check if we're already in a tmux session and, if not, to start a tmux session. I chose to name the session "Default".

Exiting with a $? value will make the shell return automatically once the tmux session is not attached to it anymore, by any means (stopped / detached), propagating the status code generated by the tmux command to the caller.

This is normally desirable, as you normally don't want to close the shell twice each time you're done with it, but the exit line can simply be omitted (or changed) in case it's not.

if [ -z "$TMUX" ]; then
    tmux_default_session_name=Default

    [ ... ]

    tmux new-session -d -s "$tmux_default_session_name"

    [ ... ]

    tmux attach -t "$tmux_default_session_name"

    exit "$?"
fi

Then we need to automatically generate a system-unique1 color for the status bar; leveraging /etc/machine-id, we can generate one that will persist even across hardware changes.

After having done this, we need to calculate the "brightness" of the system-unique1 color, so that we can set an appropriately bright / dark color for the text of the status bar (for the sake of simplicity any color below a "brightness" of 128 will have the corresponding text color set to white and any color equal or above a "brightness" of 128 will have the corresponding text color set to black 2 - see below for a more granular solution).

This can be done by:

  • Extracting the last 6 hex digits from /etc/machine-id
  • Iterating over each 2-digits pair, concatenating each pair to a variable which will hold an #rrggbb string defining the color and converting each pair to a decimal number, adding it to an accumulator which will hold the sum of the "brightnesses" of the R / G / B components of the color
  • Dividing the "brightnesses sum accumulator" by 3 to calculate the average "brightness" of the R / G / B components
  • Setting the text color appropriately
tmux_bg_color=#
tmux_fg_color=#000000

tmux_bg_color_brightness=0

for c in $(cut -c27- /etc/machine-id | fold -w2); do
    tmux_bg_color="${tmux_bg_color}${c}"
    tmux_bg_color_brightness=$((tmux_bg_color_brightness + 16#${c}))
done

tmux_bg_color_brightness=$((tmux_bg_color_brightness / 3))

[ "$tmux_bg_color_brightness" -lt 128 ] && tmux_fg_color=#ffffff

Finally, to set the status bar color and text color:

tmux set-option -t "$tmux_default_session_name" status-style "bg=${tmux_bg_color}"
tmux set-option -at "$tmux_default_session_name" status-style "fg=${tmux_fg_color}"
tmux set-option -at "$tmux_default_session_name" terminal-features ',*:RGB'

1 - The selected color is based on the system, however it does not uniquely identify it; the uniqueness is limited by the number of displayable colors in a #rrggbb format (accepted by tmux), which de-facto limits the possible colors pool to ~16 millions; the seed for the color is extracted from the last 6 hex digits of /etc/machine-id, which is instead a unique identifier for the system; still this method produces a more than "unique enough" color considering the final objective (and I'd challenge you to tell apart 2 colors next to each other even in a "small" ~16 million colors pool... which is already probably too big, kinda defeating the purpose in relatively rare instances).

2 - To apply an appropriate proportionally bright / dark text color, one could subset the possible "brightness" of the status bar color in ranges; here I've subsetted it into 8 ranges; this snippet is meant to replace the [ "$tmux_bg_color_brightness" -lt 128 ] && tmux_fg_color=#ffffff line (if using this, one might as well then also remove the tmux_fg_color=#000000 line):

if [[ $tmux_bg_color_brightness -ge 0 && $tmux_bg_color_brightness -lt 32 ]]; then
    tmux_fg_color="#ffffff"
elif [[ $tmux_bg_color_brightness -ge 32 && $tmux_bg_color_brightness -lt 64 ]]; then
    tmux_fg_color="#cccccc"
elif [[ $tmux_bg_color_brightness -ge 64 && $tmux_bg_color_brightness -lt 96 ]]; then
    tmux_fg_color="#aaaaaa"
elif [[ $tmux_bg_color_brightness -ge 96 && $tmux_bg_color_brightness -lt 128 ]]; then
    tmux_fg_color="#888888"
elif [[ $tmux_bg_color_brightness -ge 128 && $tmux_bg_color_brightness -lt 160 ]]; then
    tmux_fg_color="#666666"
elif [[ $tmux_bg_color_brightness -ge 160 && $tmux_bg_color_brightness -lt 192 ]]; then
    tmux_fg_color="#444444"
elif [[ $tmux_bg_color_brightness -ge 192 && $tmux_bg_color_brightness -lt 224 ]]; then
    tmux_fg_color="#222222"
elif [[ $tmux_bg_color_brightness -ge 224 && $tmux_bg_color_brightness -le 255 ]]; then
    tmux_fg_color="#000000"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .