Add support for linked windows

pull/300/head
Pokey Rule 2019-06-17 17:01:49 +01:00
parent e3f05dd34f
commit 319c129cbd
2 changed files with 97 additions and 4 deletions

View File

@ -272,6 +272,34 @@ restore_pane_layout_for_each_window() {
done
}
restore_linked_windows() {
\grep '^link' $(last_resurrect_file) |
while IFS=$d read line_type session_name window_number window_source; do
if session_exists "$session_name"; then
tmux link-window -s "${window_source}" -t "${session_name}:${window_number}"
else
# Create session if it doesn't exist. This situation occurs
# when a session only contains linked windows. Otherwise the
# session will have been created at some point while
# restoring the panes.
TMUX="" tmux -S "$(tmux_socket)" new-session -d -s "$session_name"
local created_window_num="$(first_window_num)"
# If the window number we created is the same as our target
# window, we move it up by 1
if [ $created_window_num -eq $window_number ]; then
original_window_num=$created_window_num
let created_window_num=$original_window_num+1
tmux move-window -s "${session_name}:${original_window_num}" -t "${session_name}:${created_window_num}"
fi
tmux link-window -s "${window_source}" -t "${session_name}:${window_number}"
# We keep the window around to the end so that the session
# doesn't disappear
tmux kill-window -t "${session_name}:${created_window_num}"
fi
done
}
restore_shell_history() {
awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ { print $2, $3, $7, $10; }' $(last_resurrect_file) |
while IFS=$d read session_name window_number pane_index pane_command; do
@ -359,6 +387,7 @@ main() {
restore_active_pane_for_each_window
restore_zoomed_windows
restore_grouped_sessions # also restores active and alt windows for grouped sessions
restore_linked_windows
restore_active_and_alternate_windows
restore_active_and_alternate_sessions
execute_hook "post-restore-all"

View File

@ -50,6 +50,8 @@ pane_format() {
format+="#{pane_pid}"
format+="${delimiter}"
format+="#{history_size}"
format+="${delimiter}"
format+="#{window_id}"
echo "$format"
}
@ -66,6 +68,8 @@ window_format() {
format+=":#{window_flags}"
format+="${delimiter}"
format+="#{window_layout}"
format+="${delimiter}"
format+="#{window_id}"
echo "$format"
}
@ -79,6 +83,35 @@ state_format() {
echo "$format"
}
set_canonical_window() {
# We store the canonical window targets using variables named based on the
# window id, because Bash <4.0 doesn't support associative arrays. This
# technique is based on https://stackoverflow.com/a/11776875.
local session_name="$1"
local window_number="$2"
local window_id_num="${3:1}"
local window_target="${session_name}:${window_number}"
printf -v "CANONICAL_WINDOW__${window_id_num}" %s "$window_target"
}
get_canonical_window() {
local window_id_num="${1:1}"
var_name="CANONICAL_WINDOW__${window_id_num}"
echo "${!var_name}"
}
is_canonical_window() {
local session_name="$1"
local window_number="$2"
local window_id="$3"
local window_target="${session_name}:${window_number}"
canonical_window=$(get_canonical_window "$window_id")
[[ "$canonical_window" == "$window_target" ]]
}
dump_panes_raw() {
tmux list-panes -a -F "$(pane_format)"
}
@ -223,15 +256,40 @@ fetch_and_dump_grouped_sessions(){
fi
}
set_canonical_windows() {
# When multiple windows are linked via link-window, they will all share the
# same window_id. For each window_id, we arbitrarily pick one of the linked
# window locations (session_name:window_number) to be the canonical window. We
# will only output information for that window, and output a link line for all
# other windows linked to the given id.
# NB: We use bash process substitution instead of piping into the while
# loop to avoid losing the variables set in set_canonical_window. See
# http://mywiki.wooledge.org/BashFAQ/024 for more info.
while IFS=$d read line_type session_name window_index window_active window_flags window_layout window_id; do
# not saving windows from grouped sessions
if is_session_grouped "$session_name"; then
continue
fi
# We run this for every window, so that for any given window_id, the
# final time we encounter it will be the location we call canonical.
# This is arbitrary, so just picked easiest to implement.
set_canonical_window "$session_name" "$window_index" "$window_id"
done < <(dump_windows_raw)
}
# translates pane pid to process command running inside a pane
dump_panes() {
local full_command
dump_panes_raw |
while IFS=$d read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command pane_pid history_size; do
while IFS=$d read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command pane_pid history_size window_id; do
# not saving panes from grouped sessions
if is_session_grouped "$session_name"; then
continue
fi
if ! is_canonical_window "$session_name" "$window_number" "$window_id"; then
continue
fi
full_command="$(pane_full_command $pane_pid)"
dir=$(echo $dir | sed 's/ /\\ /') # escape all spaces in directory path
echo "${line_type}${d}${session_name}${d}${window_number}${d}${window_name}${d}${window_active}${d}${window_flags}${d}${pane_index}${d}${dir}${d}${pane_active}${d}${pane_command}${d}:${full_command}"
@ -240,12 +298,17 @@ dump_panes() {
dump_windows() {
dump_windows_raw |
while IFS=$d read line_type session_name window_index window_active window_flags window_layout; do
while IFS=$d read line_type session_name window_index window_active window_flags window_layout window_id; do
# not saving windows from grouped sessions
if is_session_grouped "$session_name"; then
continue
fi
echo "${line_type}${d}${session_name}${d}${window_index}${d}${window_active}${d}${window_flags}${d}${window_layout}"
if is_canonical_window "$session_name" "$window_index" "$window_id"; then
echo "${line_type}${d}${session_name}${d}${window_index}${d}${window_active}${d}${window_flags}${d}${window_layout}"
else
canonical_window=$(get_canonical_window "$window_id")
echo "link${d}${session_name}${d}${window_index}${d}${canonical_window}"
fi
done
}
@ -256,7 +319,7 @@ dump_state() {
dump_pane_contents() {
local pane_contents_area="$(get_tmux_option "$pane_contents_area_option" "$default_pane_contents_area")"
dump_panes_raw |
while IFS=$d read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command pane_pid history_size; do
while IFS=$d read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command pane_pid history_size window_id; do
capture_pane_contents "${session_name}:${window_number}.${pane_index}" "$history_size" "$pane_contents_area"
done
}
@ -281,6 +344,7 @@ save_all() {
local last_resurrect_file="$(last_resurrect_file)"
mkdir -p "$(resurrect_dir)"
fetch_and_dump_grouped_sessions > "$resurrect_file_path"
set_canonical_windows
dump_panes >> "$resurrect_file_path"
dump_windows >> "$resurrect_file_path"
dump_state >> "$resurrect_file_path"