Override ^p/^n in agent session to switch between root windows
This commit is contained in:
90
agent-sync.sh
Executable file
90
agent-sync.sh
Executable file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env bash
|
||||
# Move the client that opened the agent popup to the root window matching the
|
||||
# agent session's current window. Installed by agent.sh as the agent session's
|
||||
# session-window-changed hook, so it runs for any window change made inside the
|
||||
# popup: <prefix>C-n, <prefix>C-p, select-window, choose-tree or the mouse.
|
||||
#
|
||||
# Set @agent_follow_session to "off" to keep the opening client in the session
|
||||
# it is already on, never switching it to the session owning the match.
|
||||
|
||||
set -e
|
||||
|
||||
# Fields are joined with a unit separator, not a tab: `read` folds runs of tabs
|
||||
# and spaces even when IFS names them, so an unset option in the middle would
|
||||
# silently shift every field after it.
|
||||
us=$'\x1f'
|
||||
|
||||
# Everything recorded about the agent session's current window, in one
|
||||
# round-trip. Format lookups rather than show-option, so unset user options come
|
||||
# back empty instead of logging "invalid option" into the tmux message log.
|
||||
state=$(tmux display-message -p -t agent "#{session_attached}$us#{@agent_dir}\
|
||||
$us#{@agent_origin_window}$us#{@agent_popup_client}$us#{@agent_follow_session}" \
|
||||
2>/dev/null || true)
|
||||
IFS=$us read -r attached agent_dir origin_window popup_client follow <<<"$state"
|
||||
|
||||
# Only sync while a popup is actually attached. Without this guard the
|
||||
# detach-client + kill-window agent-cmd.sh performs when an agent exits would
|
||||
# drag the root client to whichever window tmux picks next.
|
||||
[ "${attached:-0}" -gt 0 ] || exit 0
|
||||
[ -n "$agent_dir" ] || exit 0
|
||||
|
||||
# An empty session means the recorded client has since gone away.
|
||||
client_session=""
|
||||
if [ -n "$popup_client" ]; then
|
||||
client_session=$(tmux list-clients -F "#{client_name}$us#{session_name}" \
|
||||
| awk -v FS="$us" -v client="$popup_client" '$1 == client { print $2; exit }')
|
||||
fi
|
||||
|
||||
target_window=""
|
||||
target_session=""
|
||||
|
||||
# Prefer the recorded origin window, as long as it still exists.
|
||||
if [ -n "$origin_window" ]; then
|
||||
while IFS=$us read -r window_id session_name; do
|
||||
if [ "$window_id" = "$origin_window" ] && [ "$session_name" != agent ]; then
|
||||
target_window=$window_id
|
||||
target_session=$session_name
|
||||
break
|
||||
fi
|
||||
done < <(tmux list-windows -a -F "#{window_id}$us#{session_name}")
|
||||
fi
|
||||
|
||||
# Otherwise match the recorded directory against root windows. This covers agent
|
||||
# windows created before origin recording existed, and root windows that have
|
||||
# been recreated since.
|
||||
if [ -z "$target_window" ]; then
|
||||
seen_window=""
|
||||
while IFS=$us read -r window_id session_name start_path current_path; do
|
||||
# Panes are listed grouped by window in index order, so the first row for a
|
||||
# window is its first pane.
|
||||
[ "$window_id" != "$seen_window" ] || continue
|
||||
seen_window=$window_id
|
||||
[ "$session_name" != agent ] || continue
|
||||
[ "$start_path" = "$agent_dir" ] || [ "$current_path" = "$agent_dir" ] || continue
|
||||
# Prefer a window in the session the opening client is already on.
|
||||
if [ "$session_name" = "$client_session" ]; then
|
||||
target_window=$window_id
|
||||
target_session=$session_name
|
||||
break
|
||||
fi
|
||||
if [ -z "$target_window" ]; then
|
||||
target_window=$window_id
|
||||
target_session=$session_name
|
||||
fi
|
||||
done < <(tmux list-panes -a -F "#{window_id}$us#{session_name}\
|
||||
$us#{pane_start_path}$us#{pane_current_path}")
|
||||
fi
|
||||
|
||||
# No match: leave the root sessions alone rather than inventing a window.
|
||||
[ -n "$target_window" ] || exit 0
|
||||
|
||||
# Window ids are server-global, so this moves the owning session whichever
|
||||
# client happens to be on it.
|
||||
tmux select-window -t "$target_window" 2>/dev/null || exit 0
|
||||
|
||||
# Selecting is enough when the client is already on the target session.
|
||||
[ -n "$client_session" ] || exit 0
|
||||
[ "$follow" != off ] || exit 0
|
||||
if [ -n "$target_session" ] && [ "$target_session" != "$client_session" ]; then
|
||||
tmux switch-client -c "$popup_client" -t "$target_session"
|
||||
fi
|
||||
Reference in New Issue
Block a user