From 5b130c10634e93235b5288471c41e560fab3ba9c Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 23 Jul 2026 17:39:52 -0700 Subject: [PATCH] Make tmux alert parsing and focus more robust Session names can contain pipes but never colons, so split fields on colons instead. Remember refreshes that arrive while the indicator is already polling, and jump to the most recently used tmux client rather than an arbitrary one. Co-Authored-By: Claude Fable 5 --- bin/omarchy-tmux-alert | 23 +++++++++++++--------- shell/plugins/bar/indicators/TmuxAlert.qml | 9 ++++++++- test/shell.d/tmux-alert-test.sh | 12 +++++------ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/bin/omarchy-tmux-alert b/bin/omarchy-tmux-alert index 88866801..a0881f71 100755 --- a/bin/omarchy-tmux-alert +++ b/bin/omarchy-tmux-alert @@ -6,8 +6,9 @@ set -e -# Window names can contain the separator, so they always come last when parsed. -WINDOW_FORMAT='#{window_bell_flag}#{window_activity_flag}#{window_silence_flag}|#{session_name}|#{window_index}|#{window_name}' +# Session names cannot contain colons, and window names can, so they always +# come last when parsed. +WINDOW_FORMAT='#{window_bell_flag}#{window_activity_flag}#{window_silence_flag}:#{session_name}:#{window_index}:#{window_name}' usage() { echo "Usage: omarchy-tmux-alert " >&2 @@ -20,9 +21,9 @@ alerted_windows() { local flags session index name tmux list-windows -a -F "$WINDOW_FORMAT" 2>/dev/null | - while IFS='|' read -r flags session index name; do + while IFS=':' read -r flags session index name; do if [[ $flags == *1* ]]; then - printf '%s|%s|%s\n' "$session" "$index" "$name" + printf '%s:%s:%s\n' "$session" "$index" "$name" fi done } @@ -33,7 +34,7 @@ show() { readarray -t windows < <(alerted_windows) for window in "${windows[@]}"; do - IFS='|' read -r session index name <<<"$window" + IFS=':' read -r session index name <<<"$window" [[ -n $description ]] && description+=", " description+="$name ($session:$index)" done @@ -68,23 +69,27 @@ focus_terminal_window() { hyprctl dispatch focuswindow "address:$address" >/dev/null } +most_recent_client() { + tmux list-clients "$@" -F '#{client_activity}:#{client_tty}:#{client_pid}' 2>/dev/null | sort -rn | head -n1 +} + focus() { local target session index client tty pid target=$(alerted_windows | head -n1) [[ -n $target ]] || return 0 - IFS='|' read -r session index _ <<<"$target" + IFS=':' read -r session index _ <<<"$target" - client=$(tmux list-clients -t "$session" -F '#{client_tty}|#{client_pid}' 2>/dev/null | head -n1) - [[ -n $client ]] || client=$(tmux list-clients -F '#{client_tty}|#{client_pid}' 2>/dev/null | head -n1) + client=$(most_recent_client -t "$session") + [[ -n $client ]] || client=$(most_recent_client) if [[ -z $client ]]; then tmux select-window -t "$session:$index" exec omarchy-launch-terminal tmux attach -t "$session" fi - IFS='|' read -r tty pid <<<"$client" + IFS=':' read -r _ tty pid <<<"$client" tmux switch-client -c "$tty" -t "$session:$index" omarchy-shell -q omarchy.indicators refresh focus_terminal_window "$pid" diff --git a/shell/plugins/bar/indicators/TmuxAlert.qml b/shell/plugins/bar/indicators/TmuxAlert.qml index 64ef8abe..430b9dfb 100644 --- a/shell/plugins/bar/indicators/TmuxAlert.qml +++ b/shell/plugins/bar/indicators/TmuxAlert.qml @@ -8,6 +8,7 @@ BarIndicator { property int waitingCount: 0 property string tooltip: "" + property bool refreshPending: false active: waitingCount > 0 activeText: "󰆍" @@ -16,7 +17,8 @@ BarIndicator { inactiveTooltipText: "No terminal is waiting" function refresh() { - if (!statusProc.running) statusProc.running = true + if (statusProc.running) refreshPending = true + else statusProc.running = true } function update(raw) { @@ -54,6 +56,11 @@ BarIndicator { root.waitingCount = 0 root.tooltip = "" } + + if (root.refreshPending) { + root.refreshPending = false + root.refresh() + } } } diff --git a/test/shell.d/tmux-alert-test.sh b/test/shell.d/tmux-alert-test.sh index a83addab..276771cb 100644 --- a/test/shell.d/tmux-alert-test.sh +++ b/test/shell.d/tmux-alert-test.sh @@ -22,22 +22,22 @@ export TMUX_STUB_WINDOWS="$test_dir/windows" export PATH="$test_dir:$PATH" cat >"$TMUX_STUB_WINDOWS" <<'WINDOWS' -000|Work|1|editor -100|Work|2|claude -001|Side|1|server|with|pipes +000:Work:1:editor +100:Work:2:claude +001:Side|Gig:1:server: still going WINDOWS output=$("$ROOT/bin/omarchy-tmux-alert" show --json) -expected='{"count":2,"tooltip":"claude (Work:2), server|with|pipes (Side:1)"}' +expected='{"count":2,"tooltip":"claude (Work:2), server: still going (Side|Gig:1)"}' [[ $output == "$expected" ]] || fail "tmux alert reports alerted windows" "expected: $expected"$'\n'"actual: $output" pass "tmux alert reports alerted windows" output=$("$ROOT/bin/omarchy-tmux-alert" show) -[[ $output == "claude (Work:2), server|with|pipes (Side:1)" ]] || fail "tmux alert describes alerted windows" "$output" +[[ $output == "claude (Work:2), server: still going (Side|Gig:1)" ]] || fail "tmux alert describes alerted windows" "$output" pass "tmux alert describes alerted windows" cat >"$TMUX_STUB_WINDOWS" <<'WINDOWS' -000|Work|1|editor +000:Work:1:editor WINDOWS output=$("$ROOT/bin/omarchy-tmux-alert" show --json)