tmux: track .tmux.conf.user (async statusline + stardate)

This commit is contained in:
2026-09-07 10:28:38 -07:00
parent 14382f29e7
commit eb15ddf87a
+76
View File
@@ -0,0 +1,76 @@
# ---------------------------------------------------------------------------
# Statusline element-flicker fix (2026-08-19).
# Sourced at the end of ~/.yadr/.tmux.conf, so these override what it sets.
# Kept HERE so a yadr re-bootstrap cannot clobber it.
#
# SYMPTOM dissimulo reported: "the statusbar is having a seizure -- elements
# appear and disappear at random." NOT the whole bar blanking (a 30fps screen
# recording of the bar showed zero frame-to-frame variation, and a whole-desktop
# capture showed nothing changing near it). Individual ELEMENTS winking out.
#
# CAUSE: `#(...)` in a status format is a tmux JOB. While that job is being
# (re)started its expansion is EMPTY, so the element vanishes until it finishes.
# tmux re-runs those jobs whenever the status is redrawn and the job is not
# already running -- and status redraws are driven by PANE ACTIVITY, not by
# `status-interval`. With a busy TUI in the pane (a `claude` session) the jobs
# were being restarted several times a second, so the username and the IP
# flickered in and out constantly. Measured: `#(whoami)` and `#(tmux-net)`
# expanded EMPTY in 30 out of 30 consecutive renders.
#
# FIX: resolve both into tmux USER OPTIONS and reference those. `#{@user}` and
# `#{@net}` are plain variable lookups -- no job, so nothing can ever be
# half-started and render empty. Rendered text is byte-identical to before.
# @user - a username cannot change within a session: read it ONCE.
# @net - the IP CAN change, so refresh on a slow background loop
# (4 forks/minute instead of several a second). The loop exits by
# itself when tmux goes away, because `tmux set` then fails.
#
# Bonus, already measured: this also cut the tmux server from ~25% of a core to
# ~12% and eliminated the fork churn (17 execs/10s -> 0).
#
# DO NOT "simplify" #{@user}/#{@net} back to #(whoami)/#(~/.local/bin/tmux-net).
# That is the bug, not a tidier way of writing it.
# ---------------------------------------------------------------------------
run-shell 'tmux set -g @user "$(whoami)"'
run-shell 'tmux set -g @net "$($HOME/.local/bin/tmux-net)"'
run-shell -b 'while sleep 60; do tmux set -g @net "$($HOME/.local/bin/tmux-net)" 2>/dev/null || exit 0; done'
# These lengths are measured against the RAW format string, NOT the rendered
# width: tmux applies them as #{T;=/N:status-right}, truncating BEFORE the
# #[...] style directives are stripped. status-right renders ~46 columns but is
# ~129 characters of source. A cap below the raw length severs the string
# mid-way, which looks exactly like 'the right side of the bar disappeared'.
# Set here as well as in .tmux.conf so this file stays self-sufficient.
set -g status-left-length 451
set -g status-right-length 451
set -g status-left '#[fg=colour235,bg=colour252,bold] ❐ #S #[fg=colour252,bg=colour238,nobold]#[fg=colour245,bg=colour238,bold] #{@user} '
# The trailing %S is drawn in bg-on-bg (colour234 on colour234) so it is
# INVISIBLE, but it makes the status string CHANGE every second.
#
# WHY THAT MATTERS -- the second half of the bug: tmux only repaints the status
# line when its computed content DIFFERS from what it last drew. With the clock
# at minute resolution and @user/@net static, the string was byte-identical for
# up to 60s at a stretch; so when anything wiped the bar it STAYED wiped until
# the minute rolled over. That is the "sometimes the entire bar disappears" half.
# A once-per-second change forces a repaint, so a wipe self-heals within ~1s.
# It costs one redraw of one row and NO forks (that is only affordable because
# the #() jobs above became #{@user}/#{@net}).
set -g status-right '#[bold][#[nobold,fg=colour229]#h#[fg=default] / #[fg=colour229]#{@net}#[fg=default,bold]]#[nobold,fg=colour255] %-I:%M%P %d-%b-%Y #[fg=colour39]★ Stardate %Y.%j#[fg=colour255] '
# ---- circled window numbers, stamped asynchronously ----------------------
# The icon is computed ONCE per window change and stored as a window-level
# user option; the format below is a plain #{@icon} lookup. The old version
# nested ten #{?#{==:#{window_index},N},...} conditionals evaluated for every
# window on every redraw, and redraws follow PANE ACTIVITY, not status-interval.
# run-shell -b is backgrounded, so none of this sits on the render path.
set -g window-status-format '#[fg=colour235,bg=colour252,nobold] #{?#{@icon},#{@icon},#{window_index}} #{b:pane_current_path} #W '
set -g window-status-current-format '#[fg=colour234,bg=colour39,bold] [#[fg=colour232,bold]#{?window_zoomed_flag,#[fg=colour228],} #{?#{@icon},#{@icon},#{window_index}} #{b:pane_current_path} #W #[fg=colour234,bold]] '
run-shell -b '$HOME/.local/bin/tmux-window-icons'
set-hook -g after-new-window 'run-shell -b "$HOME/.local/bin/tmux-window-icons"'
set-hook -g window-linked 'run-shell -b "$HOME/.local/bin/tmux-window-icons"'
set-hook -g window-unlinked 'run-shell -b "$HOME/.local/bin/tmux-window-icons"'
set-hook -g session-window-changed 'run-shell -b "$HOME/.local/bin/tmux-window-icons"'