Adding custom dynamic elements to tmux's status bar
written on August 6, 2024
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. 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
:
$ shell
$ 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 task!
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 :)