Adding custom dynamic elements to tmux's status bar
written on August 6, 2024
categories: engineering
I've been using the Alacritty + tmux combo for a while now, and I've been pretty happy with it. It allows me to have a nice, neat terminal while also being able to split it into multiple panes and hop between them very easily.
The thing is, I prefer having Alacritty in fullscreen mode, which means that when I have a terminal pulled up, I can't really see anything else... except for tmux's status bar, which is that horrendous-neon-green-by-default thing you see on the bottom with a non-customized config:
You can of course customize this status bar pretty easily. For example, this is how you set the left part of it to display some fixed string:
.tmux.conf
set -g status-left "hello tmux :)"
How about dynamic elements, like date/time? Well, there are some predefined sequences you can use
for those. For example, this is how you set the right part of the status bar to display the date
and time in a YYYY-MM-DD HH:MM
format:
.tmux.conf
set -g status-right "%Y-%m-%d %H:%M"
This is all nice and good, but what about "arbitrary" customization? For example, it would be nice to be able to see the battery level on the status bar, so that I know when my laptop is about to die!
Well... that one is a little more complicated. Technically, there is a way to execute shell
commands inside the tmux configuration file, but they get very unwieldy very fast. There seems to
be a way to do if-statements too, but I find it awkward as
well. Overall, it seems like the simplest way to do this is to just delegate all of this to a shell
script, and then do something like run-shell /path/to/shell/script
from the tmux config file. So,
I set out to write a little shell script that can take care of setting the battery status (and
possibly other things in the future) on the tmux status bar.
First attempt
At first, my reasoning was this: since the tmux configuration language is kind of awkward to use, maybe it's best to delegate the entire status bar configuration to a (or multiple) shell script(s), and add on stuff as needed in the future through that mechanism.
So, the general "architecture" would be this:
set-status-bar.sh
battery_status() {
# ...
}
date_and_time() {
# ...
}
tmux set-option -g status-right "$(battery_status) | $(date_and_time)"
.tmux.conf
run-shell /path/to/set-status-bar.sh
There is one small hiccup with this: how to find set-status-bar.sh
. This is easily circumvented
if you use the classic dotfiles + GNU stow approach,
in which case you can simply store set-status-bar.sh
(and any other scripts) under ~/tmux/
for
example, and then you would know what the absolute path to it is.
As a small aside, getting the battery status should be pretty easy; I use upower
:
$ upower -i $(upower -e | grep BAT) | grep percentage
percentage: 79%
This works pretty well, in the sense that you do get the battery status to display on the tmux
status bar. However... how do you update it? I mean, tmux does update the status bar regularly, but
it doesn't do it by re-sourcing the entire config file! To my understanding, it simply re-runs
whatever command was used to set the status bar in the first place. The problem here is that the
set
command is not run in the tmux config itself, but in the shell script, so it's run indirectly
through run-shell
. I guess you could set up a cron thing to make it refresh regularly, but that
sounds extremely complicated for such a small thing!
Second attempt
A very simple solution to this issue would be to somehow still have a set -g status-right
command
present in the tmux config file. So how can we still delegate the rest of the work to the shell
script? Turns out, you can just run any shell command and capture its output in a string inside of
the tmux config file like this:
.tmux.conf
set -g status-right "#(echo hi)"
So the solution is pretty simple: just make the shell script print out the status bar element instead, and incorporate it into the final status bar in the tmux config file via that shell-command-output-to-string syntax! As a bonus, we can simplify the shell script and only keep whatever's relevant (simpler things such as static strings or date/time can be handled natively inside the tmux config file):
set-status-bar.sh
battery_status() {
# ...
}
echo -n "$(battery_status)"
.tmux.conf
set -g status-right "#(bash ~/tmux/set-status-bar.sh) | %Y-%m-%d %H:%M"
I hope this little hack saves you some time when customizing your tmux config :)