13 Commits

Author SHA1 Message Date
e87d7d592c v4.0.0 2022-04-10 08:40:19 +02:00
5b5e6ca7b1 Merge pull request #431 from Hologos/feature/save-pane-title
Adds support for saving and restoring pane titles.
2022-04-10 08:39:15 +02:00
1ad109d3a8 Adds support for saving and restoring pane titles. 2022-04-09 13:52:28 +02:00
027960ad25 Explain delayed pane content cleanup 2021-12-19 16:21:44 +01:00
dc6252d950 Merge pull request #422 from cartoonist/master
Fix #141
2021-12-19 16:19:30 +01:00
c3d0599a6e Fix #141
The issue apprently happens when using fish as the default shell. This commit
fixes this issue by postponing `restore/pane_contents` clean-up after calling
`restore_active_pane_for_each_window` (scripts/restore.sh:392). It might also
fix #192.
2021-12-19 12:50:20 +01:00
6be2f34b5f automatic-rename: changelog and comments 2021-08-30 14:17:15 +02:00
4234ba99aa Merge pull request #401 from Farzat07/automatic-rename2
Maintain the value of automatic-rename
2021-08-30 14:07:33 +02:00
3e8fbdf7aa Make window_name variable local in restoring func
In restore_window_properties function, the window_name is set globally
at first, but now it is first declared as local to prevent that from
happening.
2021-08-27 18:02:00 +09:00
1b63a940a0 Fix even more bugs in before last commit
First, increment the relevant indices in the awk statements regarding
windows, as now the window_name entry exists.

Second, remove the window_name entry from the dump_pane_contents and
dump_shell_history functions as it no longer exists in the format.
2021-08-27 15:57:26 +09:00
02a7f1f9d6 Fix some of the errors in the last commit
First, make sure to include the ":" placeholder in the window_name
format.

Second, decrement the indices in relevant awk commands to make sure they
point to the right items.
2021-08-27 13:27:00 +09:00
6c9322aa99 Leave window name handling to windows
Previously, window names were set when creating panes and were therefore
saved with pane data. However, saving the names with window data is more
intuitive and easier to manage. In addition, one can set the name and
automatic-rename options in the same function, so one can make sure that
renaming the windows will not overwrite the automatic-rename option.
2021-08-26 07:00:49 +09:00
80adb917c1 Maintain the value of automatic-rename
When the session is restored, the windows are renamed to their original
names switching off automatic-rename, which can be undesirable.
Therefore the value of automatic-rename is now saved for each window and
restored after the renaming.

If the value is set, that value is saved and then applied. Otherwise, a
placeholder of ':' is placed instead, in which case the local option is
unset for that window (as it originally was).
2021-08-23 14:04:11 +09:00
3 changed files with 65 additions and 42 deletions

View File

@ -2,6 +2,11 @@
### master ### master
### v4.0.0, 2022-04-10
- Proper handling of `automatic-rename` window option.
- save and restore tmux pane title (breaking change: you have to re-save to be
able to properly restore!)
### v3.0.0, 2021-08-30 ### v3.0.0, 2021-08-30
- save and restore tmux pane contents (@laomaiweng) - save and restore tmux pane contents (@laomaiweng)
- update tmux-test to solve issue with recursing git submodules in that project - update tmux-test to solve issue with recursing git submodules in that project

View File

@ -126,31 +126,29 @@ pane_creation_command() {
new_window() { new_window() {
local session_name="$1" local session_name="$1"
local window_number="$2" local window_number="$2"
local window_name="$3" local dir="$3"
local dir="$4" local pane_index="$4"
local pane_index="$5"
local pane_id="${session_name}:${window_number}.${pane_index}" local pane_id="${session_name}:${window_number}.${pane_index}"
dir="${dir/#\~/$HOME}" dir="${dir/#\~/$HOME}"
if is_restoring_pane_contents && pane_contents_file_exists "$pane_id"; then if is_restoring_pane_contents && pane_contents_file_exists "$pane_id"; then
local pane_creation_command="$(pane_creation_command "$session_name" "$window_number" "$pane_index")" local pane_creation_command="$(pane_creation_command "$session_name" "$window_number" "$pane_index")"
tmux new-window -d -t "${session_name}:${window_number}" -n "$window_name" -c "$dir" "$pane_creation_command" tmux new-window -d -t "${session_name}:${window_number}" -c "$dir" "$pane_creation_command"
else else
tmux new-window -d -t "${session_name}:${window_number}" -n "$window_name" -c "$dir" tmux new-window -d -t "${session_name}:${window_number}" -c "$dir"
fi fi
} }
new_session() { new_session() {
local session_name="$1" local session_name="$1"
local window_number="$2" local window_number="$2"
local window_name="$3" local dir="$3"
local dir="$4" local pane_index="$4"
local pane_index="$5"
local pane_id="${session_name}:${window_number}.${pane_index}" local pane_id="${session_name}:${window_number}.${pane_index}"
if is_restoring_pane_contents && pane_contents_file_exists "$pane_id"; then if is_restoring_pane_contents && pane_contents_file_exists "$pane_id"; then
local pane_creation_command="$(pane_creation_command "$session_name" "$window_number" "$pane_index")" local pane_creation_command="$(pane_creation_command "$session_name" "$window_number" "$pane_index")"
TMUX="" tmux -S "$(tmux_socket)" new-session -d -s "$session_name" -n "$window_name" -c "$dir" "$pane_creation_command" TMUX="" tmux -S "$(tmux_socket)" new-session -d -s "$session_name" -c "$dir" "$pane_creation_command"
else else
TMUX="" tmux -S "$(tmux_socket)" new-session -d -s "$session_name" -n "$window_name" -c "$dir" TMUX="" tmux -S "$(tmux_socket)" new-session -d -s "$session_name" -c "$dir"
fi fi
# change first window number if necessary # change first window number if necessary
local created_window_num="$(first_window_num)" local created_window_num="$(first_window_num)"
@ -162,9 +160,8 @@ new_session() {
new_pane() { new_pane() {
local session_name="$1" local session_name="$1"
local window_number="$2" local window_number="$2"
local window_name="$3" local dir="$3"
local dir="$4" local pane_index="$4"
local pane_index="$5"
local pane_id="${session_name}:${window_number}.${pane_index}" local pane_id="${session_name}:${window_number}.${pane_index}"
if is_restoring_pane_contents && pane_contents_file_exists "$pane_id"; then if is_restoring_pane_contents && pane_contents_file_exists "$pane_id"; then
local pane_creation_command="$(pane_creation_command "$session_name" "$window_number" "$pane_index")" local pane_creation_command="$(pane_creation_command "$session_name" "$window_number" "$pane_index")"
@ -172,27 +169,24 @@ new_pane() {
else else
tmux split-window -t "${session_name}:${window_number}" -c "$dir" tmux split-window -t "${session_name}:${window_number}" -c "$dir"
fi fi
tmux rename-window -t "${session_name}:${window_number}" "$window_name"
# minimize window so more panes can fit # minimize window so more panes can fit
tmux resize-pane -t "${session_name}:${window_number}" -U "999" tmux resize-pane -t "${session_name}:${window_number}" -U "999"
} }
restore_pane() { restore_pane() {
local pane="$1" local pane="$1"
while IFS=$d read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command pane_full_command; do while IFS=$d read line_type session_name window_number window_active window_flags pane_index pane_title dir pane_active pane_command pane_full_command; do
dir="$(remove_first_char "$dir")" dir="$(remove_first_char "$dir")"
window_name="$(remove_first_char "$window_name")"
pane_full_command="$(remove_first_char "$pane_full_command")" pane_full_command="$(remove_first_char "$pane_full_command")"
if [ "$session_name" == "0" ]; then if [ "$session_name" == "0" ]; then
restored_session_0_true restored_session_0_true
fi fi
if pane_exists "$session_name" "$window_number" "$pane_index"; then if pane_exists "$session_name" "$window_number" "$pane_index"; then
tmux rename-window -t "${session_name}:${window_number}" "$window_name"
if is_restoring_from_scratch; then if is_restoring_from_scratch; then
# overwrite the pane # overwrite the pane
# happens only for the first pane if it's the only registered pane for the whole tmux server # happens only for the first pane if it's the only registered pane for the whole tmux server
local pane_id="$(tmux display-message -p -F "#{pane_id}" -t "$session_name:$window_number")" local pane_id="$(tmux display-message -p -F "#{pane_id}" -t "$session_name:$window_number")"
new_pane "$session_name" "$window_number" "$window_name" "$dir" "$pane_index" new_pane "$session_name" "$window_number" "$dir" "$pane_index"
tmux kill-pane -t "$pane_id" tmux kill-pane -t "$pane_id"
else else
# Pane exists, no need to create it! # Pane exists, no need to create it!
@ -200,13 +194,14 @@ restore_pane() {
register_existing_pane "$session_name" "$window_number" "$pane_index" register_existing_pane "$session_name" "$window_number" "$pane_index"
fi fi
elif window_exists "$session_name" "$window_number"; then elif window_exists "$session_name" "$window_number"; then
tmux rename-window -t "${session_name}:${window_number}" "$window_name" new_pane "$session_name" "$window_number" "$dir" "$pane_index"
new_pane "$session_name" "$window_number" "$window_name" "$dir" "$pane_index"
elif session_exists "$session_name"; then elif session_exists "$session_name"; then
new_window "$session_name" "$window_number" "$window_name" "$dir" "$pane_index" new_window "$session_name" "$window_number" "$dir" "$pane_index"
else else
new_session "$session_name" "$window_number" "$window_name" "$dir" "$pane_index" new_session "$session_name" "$window_number" "$dir" "$pane_index"
fi fi
# set pane title
tmux select-pane -t "$session_name:$window_number.$pane_index" -T "$pane_title"
done < <(echo "$pane") done < <(echo "$pane")
} }
@ -277,9 +272,6 @@ restore_all_panes() {
restore_pane "$line" restore_pane "$line"
fi fi
done < $(last_resurrect_file) done < $(last_resurrect_file)
if is_restoring_pane_contents; then
rm "$(pane_contents_dir "restore")"/*
fi
} }
handle_session_0() { handle_session_0() {
@ -292,15 +284,27 @@ handle_session_0() {
fi fi
} }
restore_pane_layout_for_each_window() { restore_window_properties() {
local window_name
\grep '^window' $(last_resurrect_file) | \grep '^window' $(last_resurrect_file) |
while IFS=$d read line_type session_name window_number window_active window_flags window_layout; do while IFS=$d read line_type session_name window_number window_name window_active window_flags window_layout automatic_rename; do
tmux select-layout -t "${session_name}:${window_number}" "$window_layout" tmux select-layout -t "${session_name}:${window_number}" "$window_layout"
# Below steps are properly handling window names and automatic-rename
# option. `rename-window` is an extra command in some scenarios, but we
# opted for always doing it to keep the code simple.
window_name="$(remove_first_char "$window_name")"
tmux rename-window -t "${session_name}:${window_number}" "$window_name"
if [ "${automatic_rename}" = ":" ]; then
tmux set-option -u -t "${session_name}:${window_number}" automatic-rename
else
tmux set-option -t "${session_name}:${window_number}" automatic-rename "$automatic_rename"
fi
done done
} }
restore_shell_history() { restore_shell_history() {
awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ { print $2, $3, $7, $10; }' $(last_resurrect_file) | awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ { print $2, $3, $6, $9; }' $(last_resurrect_file) |
while IFS=$d read session_name window_number pane_index pane_command; do while IFS=$d read session_name window_number pane_index pane_command; do
if ! is_pane_registered_as_existing "$session_name" "$window_number" "$pane_index"; then if ! is_pane_registered_as_existing "$session_name" "$window_number" "$pane_index"; then
local pane_id="$session_name:$window_number.$pane_index" local pane_id="$session_name:$window_number.$pane_index"
@ -321,7 +325,7 @@ restore_shell_history() {
restore_all_pane_processes() { restore_all_pane_processes() {
if restore_pane_processes_enabled; then if restore_pane_processes_enabled; then
local pane_full_command local pane_full_command
awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ && $11 !~ "^:$" { print $2, $3, $7, $8, $11; }' $(last_resurrect_file) | awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ && $11 !~ "^:$" { print $2, $3, $6, $8, $11; }' $(last_resurrect_file) |
while IFS=$d read -r session_name window_number pane_index dir pane_full_command; do while IFS=$d read -r session_name window_number pane_index dir pane_full_command; do
dir="$(remove_first_char "$dir")" dir="$(remove_first_char "$dir")"
pane_full_command="$(remove_first_char "$pane_full_command")" pane_full_command="$(remove_first_char "$pane_full_command")"
@ -331,7 +335,7 @@ restore_all_pane_processes() {
} }
restore_active_pane_for_each_window() { restore_active_pane_for_each_window() {
awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ && $9 == 1 { print $2, $3, $7; }' $(last_resurrect_file) | awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ && $9 == 1 { print $2, $3, $6; }' $(last_resurrect_file) |
while IFS=$d read session_name window_number active_pane; do while IFS=$d read session_name window_number active_pane; do
tmux switch-client -t "${session_name}:${window_number}" tmux switch-client -t "${session_name}:${window_number}"
tmux select-pane -t "$active_pane" tmux select-pane -t "$active_pane"
@ -339,7 +343,7 @@ restore_active_pane_for_each_window() {
} }
restore_zoomed_windows() { restore_zoomed_windows() {
awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ && $6 ~ /Z/ && $9 == 1 { print $2, $3; }' $(last_resurrect_file) | awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ && $5 ~ /Z/ && $9 == 1 { print $2, $3; }' $(last_resurrect_file) |
while IFS=$d read session_name window_number; do while IFS=$d read session_name window_number; do
tmux resize-pane -t "${session_name}:${window_number}" -Z tmux resize-pane -t "${session_name}:${window_number}" -Z
done done
@ -355,7 +359,7 @@ restore_grouped_sessions() {
} }
restore_active_and_alternate_windows() { restore_active_and_alternate_windows() {
awk 'BEGIN { FS="\t"; OFS="\t" } /^window/ && $5 ~ /[*-]/ { print $2, $4, $3; }' $(last_resurrect_file) | awk 'BEGIN { FS="\t"; OFS="\t" } /^window/ && $6 ~ /[*-]/ { print $2, $4, $3; }' $(last_resurrect_file) |
sort -u | sort -u |
while IFS=$d read session_name active_window window_number; do while IFS=$d read session_name active_window window_number; do
tmux switch-client -t "${session_name}:${window_number}" tmux switch-client -t "${session_name}:${window_number}"
@ -370,13 +374,21 @@ restore_active_and_alternate_sessions() {
done < $(last_resurrect_file) done < $(last_resurrect_file)
} }
# A cleanup that happens after 'restore_all_panes' seems to fix fish shell
# users' restore problems.
cleanup_restored_pane_contents() {
if is_restoring_pane_contents; then
rm "$(pane_contents_dir "restore")"/*
fi
}
main() { main() {
if supported_tmux_version_ok && check_saved_session_exists; then if supported_tmux_version_ok && check_saved_session_exists; then
start_spinner "Restoring..." "Tmux restore complete!" start_spinner "Restoring..." "Tmux restore complete!"
execute_hook "pre-restore-all" execute_hook "pre-restore-all"
restore_all_panes restore_all_panes
handle_session_0 handle_session_0
restore_pane_layout_for_each_window >/dev/null 2>&1 restore_window_properties >/dev/null 2>&1
execute_hook "pre-restore-history" execute_hook "pre-restore-history"
if save_shell_history_option_on; then if save_shell_history_option_on; then
restore_shell_history restore_shell_history
@ -389,6 +401,7 @@ main() {
restore_grouped_sessions # also restores active and alt windows for grouped sessions restore_grouped_sessions # also restores active and alt windows for grouped sessions
restore_active_and_alternate_windows restore_active_and_alternate_windows
restore_active_and_alternate_sessions restore_active_and_alternate_sessions
cleanup_restored_pane_contents
execute_hook "post-restore-all" execute_hook "post-restore-all"
stop_spinner stop_spinner
display_message "Tmux restore complete!" display_message "Tmux restore complete!"

View File

@ -33,14 +33,14 @@ pane_format() {
format+="${delimiter}" format+="${delimiter}"
format+="#{window_index}" format+="#{window_index}"
format+="${delimiter}" format+="${delimiter}"
format+=":#{window_name}"
format+="${delimiter}"
format+="#{window_active}" format+="#{window_active}"
format+="${delimiter}" format+="${delimiter}"
format+=":#{window_flags}" format+=":#{window_flags}"
format+="${delimiter}" format+="${delimiter}"
format+="#{pane_index}" format+="#{pane_index}"
format+="${delimiter}" format+="${delimiter}"
format+="#{pane_title}"
format+="${delimiter}"
format+=":#{pane_current_path}" format+=":#{pane_current_path}"
format+="${delimiter}" format+="${delimiter}"
format+="#{pane_active}" format+="#{pane_active}"
@ -61,6 +61,8 @@ window_format() {
format+="${delimiter}" format+="${delimiter}"
format+="#{window_index}" format+="#{window_index}"
format+="${delimiter}" format+="${delimiter}"
format+=":#{window_name}"
format+="${delimiter}"
format+="#{window_active}" format+="#{window_active}"
format+="${delimiter}" format+="${delimiter}"
format+=":#{window_flags}" format+=":#{window_flags}"
@ -227,25 +229,28 @@ fetch_and_dump_grouped_sessions(){
dump_panes() { dump_panes() {
local full_command local full_command
dump_panes_raw | 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_active window_flags pane_index pane_title dir pane_active pane_command pane_pid history_size; do
# not saving panes from grouped sessions # not saving panes from grouped sessions
if is_session_grouped "$session_name"; then if is_session_grouped "$session_name"; then
continue continue
fi fi
full_command="$(pane_full_command $pane_pid)" full_command="$(pane_full_command $pane_pid)"
dir=$(echo $dir | sed 's/ /\\ /') # escape all spaces in directory path 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}" echo "${line_type}${d}${session_name}${d}${window_number}${d}${window_active}${d}${window_flags}${d}${pane_index}${d}${pane_title}${d}${dir}${d}${pane_active}${d}${pane_command}${d}:${full_command}"
done done
} }
dump_windows() { dump_windows() {
dump_windows_raw | 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_name window_active window_flags window_layout; do
# not saving windows from grouped sessions # not saving windows from grouped sessions
if is_session_grouped "$session_name"; then if is_session_grouped "$session_name"; then
continue continue
fi fi
echo "${line_type}${d}${session_name}${d}${window_index}${d}${window_active}${d}${window_flags}${d}${window_layout}" automatic_rename="$(tmux show-window-options -vt "${session_name}:${window_index}" automatic-rename)"
# If the option was unset, use ":" as a placeholder.
[ -z "${automatic_rename}" ] && automatic_rename=":"
echo "${line_type}${d}${session_name}${d}${window_index}${d}${window_name}${d}${window_active}${d}${window_flags}${d}${window_layout}${d}${automatic_rename}"
done done
} }
@ -256,14 +261,14 @@ dump_state() {
dump_pane_contents() { dump_pane_contents() {
local pane_contents_area="$(get_tmux_option "$pane_contents_area_option" "$default_pane_contents_area")" local pane_contents_area="$(get_tmux_option "$pane_contents_area_option" "$default_pane_contents_area")"
dump_panes_raw | 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_active window_flags pane_index pane_title dir pane_active pane_command pane_pid history_size; do
capture_pane_contents "${session_name}:${window_number}.${pane_index}" "$history_size" "$pane_contents_area" capture_pane_contents "${session_name}:${window_number}.${pane_index}" "$history_size" "$pane_contents_area"
done done
} }
dump_shell_history() { dump_shell_history() {
dump_panes | dump_panes |
while IFS=$d read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command full_command; do while IFS=$d read line_type session_name window_number window_active window_flags pane_index dir pane_active pane_command full_command; do
save_shell_history "$session_name:$window_number.$pane_index" "$pane_command" "$full_command" save_shell_history "$session_name:$window_number.$pane_index" "$pane_command" "$full_command"
done done
} }