Files
socktop-swipe/socktop-swipe
T
jasonwitty c628c45291 Add swipe-down aux screen (SOCKTOP_AUX_CMD)
A separate tmux window running any TUI, reached with a vertical swipe from
any carousel screen; swiping up returns to the exact window/zoom you left.
The aux window is excluded from the horizontal carousel and horizontal
swipes on it are inert. Bound only when SOCKTOP_AUX_CMD is set.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 10:33:26 -07:00

122 lines
3.5 KiB
Bash
Executable File

#!/bin/sh
# socktop-swipe next|prev|down|up
#
# Walks a linear "zoom carousel" over the socktop session. Each tmux window is
# one group of hosts; within a group the line is the tiled overview, then each
# pane zoomed full-screen in index order; then the next window's overview:
#
# overview(g0) <-> g0.0 <-> ... <-> g0.N <-> overview(g1) <-> g1.0 <-> ...
#
# "next" moves right and stops at the last pane of the last window. "prev"
# moves back and stops at the first overview. Deliberately no wrap-around: on
# a wall display, wrapping makes it impossible to tell where you are.
#
# "down" jumps to the optional aux window (see SOCKTOP_AUX_CMD) and remembers
# where you were; "up" returns there. The aux window is not part of the
# horizontal carousel, and horizontal swipes while on it do nothing.
#
# This is tmux pane zoom, NOT extra socktop instances. All panes keep running
# and stay connected while hidden, so swiping back shows current data with no
# reconnect, and the polling load on the monitored hosts is constant.
set -eu
for c in /usr/local/etc/socktop-swipe.env "$(dirname "$0")/config.env"; do
[ -r "$c" ] && . "$c" && break
done
: "${SOCKTOP_SESSION:=socktop4}"
dir=${1:?usage: socktop-swipe next|prev|down|up}
# Ordered window ids (@N) of the carousel windows, the aux window if any, and
# the currently active window.
all=$(tmux list-windows -t "$SOCKTOP_SESSION" -F '#{window_id} #{window_name}' 2>/dev/null) || exit 0
[ -n "$all" ] || exit 0
wins= aux=
while read -r id name; do
if [ "$name" = aux ]; then aux=$id; else wins="$wins $id"; fi
done <<EOF
$all
EOF
WIN=$(tmux display-message -t "$SOCKTOP_SESSION" -p '#{window_id}') || exit 0
case "$dir" in
down)
[ -n "$aux" ] || exit 0
[ "$WIN" = "$aux" ] && exit 0
tmux set-option -t "$SOCKTOP_SESSION" @return_to "$WIN"
tmux select-window -t "$aux"
exit 0
;;
up)
[ "$WIN" = "$aux" ] || exit 0
back=$(tmux show-option -qv -t "$SOCKTOP_SESSION" @return_to)
[ -n "$back" ] && tmux has-session -t "$back" 2>/dev/null || back=${wins# }
back=${back%% *}
tmux select-window -t "$back"
exit 0
;;
esac
# On the aux screen, horizontal swipes are deliberately inert.
[ "$WIN" = "$aux" ] && exit 0
prev_win= next_win= seen=no
for w in $wins; do
if [ "$seen" = yes ]; then next_win=$w; break; fi
if [ "$w" = "$WIN" ]; then seen=yes; else prev_win=$w; fi
done
state=$(tmux display-message -t "$WIN" -p '#{window_zoomed_flag} #{pane_index} #{window_panes}') || exit 0
zoomed=${state%% *}
rest=${state#* }
idx=${rest%% *}
count=${rest##* }
last=$((count - 1))
zoom_to() {
# $1 = window id, $2 = pane index.
# Selecting a different pane auto-unzooms, so zoom explicitly afterwards.
tmux select-window -t "$1"
tmux select-pane -t "$1.$2"
tmux resize-pane -Z -t "$1.$2"
}
overview() {
# Show window $1 unzoomed.
tmux select-window -t "$1"
if [ "$(tmux display-message -t "$1" -p '#{window_zoomed_flag}')" = 1 ]; then
tmux resize-pane -Z -t "$1"
fi
}
if [ "$zoomed" = 0 ]; then
case "$dir" in
next) zoom_to "$WIN" 0 ;;
prev)
# Back out of this group's overview onto the previous group's last pane.
if [ -n "$prev_win" ]; then
pl=$(tmux display-message -t "$prev_win" -p '#{window_panes}')
zoom_to "$prev_win" $((pl - 1))
fi
;;
esac
else
case "$dir" in
next)
if [ "$idx" -lt "$last" ]; then
zoom_to "$WIN" $((idx + 1))
elif [ -n "$next_win" ]; then
tmux resize-pane -Z -t "$WIN.$idx" # unzoom before leaving
overview "$next_win"
fi
;;
prev)
if [ "$idx" -gt 0 ]; then
zoom_to "$WIN" $((idx - 1))
else
tmux resize-pane -Z -t "$WIN.$idx" # unzoom -> this group's overview
fi
;;
esac
fi