91 lines
3.7 KiB
Bash
Executable File
91 lines
3.7 KiB
Bash
Executable File
#!/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
|