From 4337db3aec58a1ca732fa57b768a480513fadca1 Mon Sep 17 00:00:00 2001 From: "Kenneth Benzie (Benie)" Date: Mon, 14 Sep 2026 16:02:33 +0100 Subject: [PATCH] Extend agent-nav.sh to also work with windows indices --- agent-nav.sh | 66 ++++++++++++++++++++++++++++++++++------------------ tmux.conf | 13 +++++++++++ 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/agent-nav.sh b/agent-nav.sh index 12d53aa..2e9399b 100755 --- a/agent-nav.sh +++ b/agent-nav.sh @@ -1,24 +1,27 @@ #!/usr/bin/env bash -# Cycle the agent popup through the windows of the session underneath it rather -# than through the agent session's own window list. Bound to C-n and -# C-p inside the agent session (see tmux.conf). +# Drive the agent popup from the windows of the session underneath it rather +# than from the agent session's own window list. Bound inside the agent session +# to C-n and C-p ("next"/"prev") and to 0..9 (a window +# index) -- see tmux.conf. # -# Root windows with no agent window are stepped over; cycling never creates an -# agent window, only A does. Both the client underneath and the popup -# move, so closing the popup leaves you on the window you cycled to. +# Root windows with no agent window are stepped over when cycling and do nothing +# when named by index, so the popup and the session below it never disagree. +# Neither ever creates an agent window; only A does. Both the client +# underneath and the popup move, so closing the popup leaves you where you went. set -e -direction=${1:-next} +target=${1:-next} us=$'\x1f' # Fall back to plain window cycling within the agent session when there is no # usable client underneath (popup opened before this was configured, or the # recorded client has gone away). fallback() { - case $direction in + case $target in + next) tmux next-window -t agent ;; prev) tmux previous-window -t agent ;; - *) tmux next-window -t agent ;; + *) tmux select-window -t "agent:$target" 2>/dev/null || true ;; esac exit 0 } @@ -64,22 +67,48 @@ agent_window_for() { return 1 } -# The underlying session's windows, in its own order, each with its first pane's -# directory. Panes are listed grouped by window in index order. +# Move the client underneath and the popup together. The agent window is re-keyed +# to the window being moved to, so the sync hook that the select below fires +# agrees with what happened here instead of dragging the client back to wherever +# that window was last opened from. +move_to() { # move_to + tmux set-window-option -t "$2" @agent_origin_window "$1" + tmux select-window -t "$1" + tmux select-window -t "$2" + exit 0 +} + +# The underlying session's windows, in its own order, each with its index and its +# first pane's directory. Panes are listed grouped by window in index order. root_windows=() +root_indexes=() root_paths=() seen_window="" -while IFS=$us read -r window_id start_path current_path; do +while IFS=$us read -r window_id window_index start_path current_path; do [ "$window_id" != "$seen_window" ] || continue seen_window=$window_id root_windows+=("$window_id") + root_indexes+=("$window_index") root_paths+=("$start_path$us$current_path") done < <(tmux list-panes -s -t "$client_session" \ - -F "#{window_id}$us#{pane_start_path}$us#{pane_current_path}" 2>/dev/null || true) + -F "#{window_id}$us#{window_index}$us#{pane_start_path}$us#{pane_current_path}" \ + 2>/dev/null || true) count=${#root_windows[@]} [ "$count" -gt 0 ] || exit 0 +# 0..9: the window with that index in the session underneath. Doing +# nothing when it has no agent window keeps the popup and that session in step. +if [ -n "$target" ] && [ -z "${target//[0-9]/}" ]; then + for i in "${!root_windows[@]}"; do + [ "${root_indexes[$i]}" = "$target" ] || continue + IFS=$us read -r start_path current_path <<<"${root_paths[$i]}" + target_agent=$(agent_window_for "${root_windows[$i]}" "$start_path" "$current_path") || exit 0 + move_to "${root_windows[$i]}" "$target_agent" + done + exit 0 +fi + # Where the client sits in that order. current=0 for i in "${!root_windows[@]}"; do @@ -89,7 +118,7 @@ for i in "${!root_windows[@]}"; do fi done -if [ "$direction" = prev ]; then step=-1; else step=1; fi +if [ "$target" = prev ]; then step=-1; else step=1; fi # Walk in that direction for the first window with an agent window, wrapping. # Landing back on the starting window means nothing else has one: selecting it @@ -100,12 +129,5 @@ for _ in $(seq 1 "$count"); do target_root=${root_windows[$i]} IFS=$us read -r start_path current_path <<<"${root_paths[$i]}" target_agent=$(agent_window_for "$target_root" "$start_path" "$current_path") || continue - - # Re-key the agent window to the window being moved to, so the sync hook that - # the select below fires agrees with what happened here instead of dragging - # the client back to wherever that window was last opened from. - tmux set-window-option -t "$target_agent" @agent_origin_window "$target_root" - tmux select-window -t "$target_root" - tmux select-window -t "$target_agent" - exit 0 + move_to "$target_root" "$target_agent" done diff --git a/tmux.conf b/tmux.conf index 975c53d..0598929 100644 --- a/tmux.conf +++ b/tmux.conf @@ -112,6 +112,19 @@ bind C-p if -F '#{==:#{session_name},agent}' { previous-window } +# Numbered window selection. Inside the agent popup the number addresses the +# underlying session's windows, doing nothing if that window has no agent window. +bind 0 if -F '#{==:#{session_name},agent}' "run -b '~/.config/tmux/agent-nav.sh 0'" 'select-window -t :=0' +bind 1 if -F '#{==:#{session_name},agent}' "run -b '~/.config/tmux/agent-nav.sh 1'" 'select-window -t :=1' +bind 2 if -F '#{==:#{session_name},agent}' "run -b '~/.config/tmux/agent-nav.sh 2'" 'select-window -t :=2' +bind 3 if -F '#{==:#{session_name},agent}' "run -b '~/.config/tmux/agent-nav.sh 3'" 'select-window -t :=3' +bind 4 if -F '#{==:#{session_name},agent}' "run -b '~/.config/tmux/agent-nav.sh 4'" 'select-window -t :=4' +bind 5 if -F '#{==:#{session_name},agent}' "run -b '~/.config/tmux/agent-nav.sh 5'" 'select-window -t :=5' +bind 6 if -F '#{==:#{session_name},agent}' "run -b '~/.config/tmux/agent-nav.sh 6'" 'select-window -t :=6' +bind 7 if -F '#{==:#{session_name},agent}' "run -b '~/.config/tmux/agent-nav.sh 7'" 'select-window -t :=7' +bind 8 if -F '#{==:#{session_name},agent}' "run -b '~/.config/tmux/agent-nav.sh 8'" 'select-window -t :=8' +bind 9 if -F '#{==:#{session_name},agent}' "run -b '~/.config/tmux/agent-nav.sh 9'" 'select-window -t :=9' + # Kill current window bind W kill-window