Compare commits
18 Commits
Author | SHA1 | Date |
---|---|---|
Bruno Sutic | cff343cf9e | |
George Guimares | 4c1c0dcf85 | |
Bruno Sutic | 6df04051fe | |
kt programs | 299c4aa8ce | |
kt programs | b8ff2ea08b | |
kt programs | 4941cdb074 | |
Bruno Sutic | a2ddfb96b9 | |
Lu Xu | dd36a4561b | |
Bruno Sutic | 88297b4c3a | |
Thomas Faughnan | 45aa8feef6 | |
Bruno Sutic | 75458f91c8 | |
Michael T. DeGuzis | 1431ba6fbe | |
Bruno Sutic | 3606e4f602 | |
Robert Brennan | 7f5fa4bed2 | |
Bruno Sutic | 74d9112314 | |
Robert Brennan | 8101d98358 | |
Bruno Sutic | ca6468e2de | |
Bruno Sutic | 6050d2d8d8 |
|
@ -1,6 +1,7 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
### master
|
### master
|
||||||
|
- Remove deprecated "restoring shell history" feature.
|
||||||
|
|
||||||
### v4.0.0, 2022-04-10
|
### v4.0.0, 2022-04-10
|
||||||
- Proper handling of `automatic-rename` window option.
|
- Proper handling of `automatic-rename` window option.
|
||||||
|
|
|
@ -104,10 +104,6 @@ You should now be able to use the plugin.
|
||||||
is nice if you're a vim/neovim user.
|
is nice if you're a vim/neovim user.
|
||||||
- [Restoring pane contents](docs/restoring_pane_contents.md) feature.
|
- [Restoring pane contents](docs/restoring_pane_contents.md) feature.
|
||||||
|
|
||||||
**Experimental features (also optional)**
|
|
||||||
|
|
||||||
- [restoring shell history](docs/restoring_shell_history.md)
|
|
||||||
|
|
||||||
### Other goodies
|
### Other goodies
|
||||||
|
|
||||||
- [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin for
|
- [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin for
|
||||||
|
|
|
@ -20,15 +20,9 @@ Currently the following hooks are supported:
|
||||||
|
|
||||||
Called before any tmux state is altered.
|
Called before any tmux state is altered.
|
||||||
|
|
||||||
- `@resurrect-hook-pre-restore-history` - deprecated
|
|
||||||
|
|
||||||
Called after panes and layout have been restores, but before bash history is
|
|
||||||
restored (if it is enabled) -- the hook is always called even if history
|
|
||||||
saving is disabled.
|
|
||||||
|
|
||||||
- `@resurrect-hook-pre-restore-pane-processes`
|
- `@resurrect-hook-pre-restore-pane-processes`
|
||||||
|
|
||||||
Called after history is restored, but before running processes are restored.
|
Called before running processes are restored.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
tmux-ressurect no longer restores shell history for each pane, as of [this PR](https://github.com/tmux-plugins/tmux-resurrect/pull/308).
|
||||||
|
|
||||||
|
As a workaround, you can use the `HISTFILE` environment variable to preserve history for each pane separately, and modify
|
||||||
|
`PROMPT_COMMAND` to make sure history gets saved with each new command.
|
||||||
|
|
||||||
|
Unfortunately, we haven't found a perfect way of getting a unique identifier for each pane, as the `TMUX_PANE` variable
|
||||||
|
seems to occasionally change when resurrecting. As a workaround, the example below sets a unique ID in each pane's `title`.
|
||||||
|
The downside of this implementation is that pane titles must all be unique across sessions/windows, and also must use the `pane_id_prefix`.
|
||||||
|
|
||||||
|
Any improvements/suggestions for getting a unique, persistent ID for each pane are welcome!
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pane_id_prefix="resurrect_"
|
||||||
|
|
||||||
|
# Create history directory if it doesn't exist
|
||||||
|
HISTS_DIR=$HOME/.bash_history.d
|
||||||
|
mkdir -p "${HISTS_DIR}"
|
||||||
|
|
||||||
|
if [ -n "${TMUX_PANE}" ]; then
|
||||||
|
|
||||||
|
# Check if we've already set this pane title
|
||||||
|
pane_id=$(tmux display -pt "${TMUX_PANE:?}" "#{pane_title}")
|
||||||
|
if [[ $pane_id != "$pane_id_prefix"* ]]; then
|
||||||
|
|
||||||
|
# if not, set it to a random ID
|
||||||
|
random_id=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16)
|
||||||
|
printf "\033]2;$pane_id_prefix$random_id\033\\"
|
||||||
|
pane_id=$(tmux display -pt "${TMUX_PANE:?}" "#{pane_title}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# use the pane's random ID for the HISTFILE
|
||||||
|
export HISTFILE="${HISTS_DIR}/bash_history_tmux_${pane_id}"
|
||||||
|
else
|
||||||
|
export HISTFILE="${HISTS_DIR}/bash_history_no_tmux"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stash the new history each time a command runs.
|
||||||
|
export PROMPT_COMMAND="$PROMPT_COMMAND;history -a"
|
||||||
|
```
|
|
@ -1,7 +1,8 @@
|
||||||
# Restoring previously saved environment
|
# Restoring previously saved environment
|
||||||
|
|
||||||
None of the previous saves are deleted (unless you explicitly do that). All save
|
None of the previous saves are deleted (unless you explicitly do that). All save
|
||||||
files are kept in `~/.tmux/resurrect/` directory.<br/>
|
files are kept in `~/.tmux/resurrect/` directory, or `~/.local/share/tmux/resurrect`
|
||||||
|
(unless `${XDG_DATA_HOME}` says otherwise).<br/>
|
||||||
Here are the steps to restore to a previous point in time:
|
Here are the steps to restore to a previous point in time:
|
||||||
|
|
||||||
- make sure you start this with a "fresh" tmux instance
|
- make sure you start this with a "fresh" tmux instance
|
||||||
|
|
|
@ -28,6 +28,10 @@ contains space-separated list of additional programs to restore.
|
||||||
|
|
||||||
set -g @resurrect-processes 'some_program "grunt->grunt development"'
|
set -g @resurrect-processes 'some_program "grunt->grunt development"'
|
||||||
|
|
||||||
|
- Use `*` to expand the arguments from the saved command when restoring:
|
||||||
|
|
||||||
|
set -g @resurrect-processes 'some_program "~rails server->rails server *"'
|
||||||
|
|
||||||
- Don't restore any programs:
|
- Don't restore any programs:
|
||||||
|
|
||||||
set -g @resurrect-processes 'false'
|
set -g @resurrect-processes 'false'
|
||||||
|
@ -96,6 +100,20 @@ command name".
|
||||||
Full (long) process name is now ignored and you'll see just `rails server` in
|
Full (long) process name is now ignored and you'll see just `rails server` in
|
||||||
the command line when the program is restored.
|
the command line when the program is restored.
|
||||||
|
|
||||||
|
> What is asterisk `*` and why is it used?
|
||||||
|
|
||||||
|
(Please read the above clarifications about tilde `~` and arrow `->`).
|
||||||
|
|
||||||
|
Continuing with the `rails server` example, you might have added flags for e.g.
|
||||||
|
verbose logging, but with the above configuration, the flags would be lost.
|
||||||
|
|
||||||
|
To preserve the command arguments when restoring, use the asterisk `*`: (**note**: there **must** be a space before `*`)
|
||||||
|
|
||||||
|
set -g @resurrect-processes '"~rails server->rails server *"'
|
||||||
|
|
||||||
|
This option says: "when this process is restored use `rails server` as the
|
||||||
|
command name, but preserve its arguments".
|
||||||
|
|
||||||
> Now I understand the tilde and the arrow, but things still don't work for me
|
> Now I understand the tilde and the arrow, but things still don't work for me
|
||||||
|
|
||||||
Here's the general workflow for figuring this out:
|
Here's the general workflow for figuring this out:
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
# Restoring shell history (deprecated, do not use)
|
|
||||||
|
|
||||||
This feature is deprecated because it's very invasive. It will be removed in
|
|
||||||
the future with no replacement. To see problems it causes check
|
|
||||||
[this issue](https://github.com/tmux-plugins/tmux-resurrect/issues/288).
|
|
||||||
|
|
||||||
**Supported shells**: `bash` and `zsh`.
|
|
||||||
|
|
||||||
Enable feature with this option in `.tmux.conf`:
|
|
||||||
|
|
||||||
set -g @resurrect-save-shell-history 'on'
|
|
||||||
|
|
||||||
**Note**: the older `@resurrect-save-bash-history` is now an alias to
|
|
||||||
`@resurrect-save-shell-history`.
|
|
||||||
|
|
||||||
Shell `history` for individual panes will now be saved and restored. Due to
|
|
||||||
technical limitations, this only works for panes which have no program running
|
|
||||||
in foreground when saving. `tmux-resurrect` will send history write command to
|
|
||||||
each such pane.
|
|
||||||
|
|
||||||
To prevent these commands from being added to `bash` history
|
|
||||||
themselves, add `HISTCONTROL=ignoreboth` to your `.bashrc`
|
|
||||||
(this is set by default in Ubuntu).
|
|
|
@ -13,7 +13,10 @@ exit_safely_if_empty_ppid() {
|
||||||
|
|
||||||
full_command() {
|
full_command() {
|
||||||
[[ -z "$COMMAND_PID" ]] && exit 0
|
[[ -z "$COMMAND_PID" ]] && exit 0
|
||||||
cat /proc/${COMMAND_PID}/cmdline | xargs -0 printf "%q "
|
# See: https://unix.stackexchange.com/a/567021
|
||||||
|
# Avoid complications with system printf by using bash subshell interpolation.
|
||||||
|
# This will properly escape sequences and null in cmdline.
|
||||||
|
cat /proc/${COMMAND_PID}/cmdline | xargs -0 bash -c 'printf "%q " "$0" "$@"'
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
|
|
|
@ -11,7 +11,7 @@ exit_safely_if_empty_ppid() {
|
||||||
}
|
}
|
||||||
|
|
||||||
full_command() {
|
full_command() {
|
||||||
ps -ao "ppid command" |
|
ps -ao "ppid,args" |
|
||||||
sed "s/^ *//" |
|
sed "s/^ *//" |
|
||||||
grep "^${PANE_PID}" |
|
grep "^${PANE_PID}" |
|
||||||
cut -d' ' -f2-
|
cut -d' ' -f2-
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
default_resurrect_dir="$HOME/.tmux/resurrect"
|
if [ -d "$HOME/.tmux/resurrect" ]; then
|
||||||
|
default_resurrect_dir="$HOME/.tmux/resurrect"
|
||||||
|
else
|
||||||
|
default_resurrect_dir="${XDG_DATA_HOME:-$HOME/.local/share}"/tmux/resurrect
|
||||||
|
fi
|
||||||
resurrect_dir_option="@resurrect-dir"
|
resurrect_dir_option="@resurrect-dir"
|
||||||
|
|
||||||
SUPPORTED_VERSION="1.9"
|
SUPPORTED_VERSION="1.9"
|
||||||
|
@ -64,13 +68,6 @@ files_differ() {
|
||||||
! cmp -s "$1" "$2"
|
! cmp -s "$1" "$2"
|
||||||
}
|
}
|
||||||
|
|
||||||
save_shell_history_option_on() {
|
|
||||||
local option_shell="$(get_tmux_option "$shell_history_option" "off")"
|
|
||||||
local option_bash="$(get_tmux_option "$bash_history_option" "off")"
|
|
||||||
|
|
||||||
[ "$option_shell" == "on" ] || [ "$option_bash" == "on" ]
|
|
||||||
}
|
|
||||||
|
|
||||||
get_grouped_sessions() {
|
get_grouped_sessions() {
|
||||||
local grouped_sessions_dump="$1"
|
local grouped_sessions_dump="$1"
|
||||||
export GROUPED_SESSIONS="${d}$(echo "$grouped_sessions_dump" | cut -f2 -d"$d" | tr "\\n" "$d")"
|
export GROUPED_SESSIONS="${d}$(echo "$grouped_sessions_dump" | cut -f2 -d"$d" | tr "\\n" "$d")"
|
||||||
|
@ -143,12 +140,6 @@ pane_contents_archive_file() {
|
||||||
echo "$(resurrect_dir)/pane_contents.tar.gz"
|
echo "$(resurrect_dir)/pane_contents.tar.gz"
|
||||||
}
|
}
|
||||||
|
|
||||||
resurrect_history_file() {
|
|
||||||
local pane_id="$1"
|
|
||||||
local shell_name="$2"
|
|
||||||
echo "$(resurrect_dir)/${shell_name}_history-${pane_id}"
|
|
||||||
}
|
|
||||||
|
|
||||||
execute_hook() {
|
execute_hook() {
|
||||||
local kind="$1"
|
local kind="$1"
|
||||||
shift
|
shift
|
||||||
|
|
|
@ -121,7 +121,7 @@ _get_command_arguments() {
|
||||||
if _proc_starts_with_tildae "$match"; then
|
if _proc_starts_with_tildae "$match"; then
|
||||||
match="$(remove_first_char "$match")"
|
match="$(remove_first_char "$match")"
|
||||||
fi
|
fi
|
||||||
echo "$pane_full_command" | sed "s,^.*${match}[^ ]* ,,"
|
echo "$pane_full_command" | sed "s,^.*${match}[^ ]* *,,"
|
||||||
}
|
}
|
||||||
|
|
||||||
_get_proc_restore_command() {
|
_get_proc_restore_command() {
|
||||||
|
@ -132,7 +132,7 @@ _get_proc_restore_command() {
|
||||||
if [[ "$restore_element" =~ " ${inline_strategy_arguments_token}" ]]; then
|
if [[ "$restore_element" =~ " ${inline_strategy_arguments_token}" ]]; then
|
||||||
# replaces "%" with command arguments
|
# replaces "%" with command arguments
|
||||||
local command_arguments="$(_get_command_arguments "$pane_full_command" "$match")"
|
local command_arguments="$(_get_command_arguments "$pane_full_command" "$match")"
|
||||||
echo "$restore_element" | sed "s/${inline_strategy_arguments_token}/${command_arguments}/"
|
echo "$restore_element" | sed "s,${inline_strategy_arguments_token},${command_arguments},"
|
||||||
else
|
else
|
||||||
echo "$restore_element"
|
echo "$restore_element"
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -303,25 +303,6 @@ restore_window_properties() {
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
restore_shell_history() {
|
|
||||||
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
|
|
||||||
if ! is_pane_registered_as_existing "$session_name" "$window_number" "$pane_index"; then
|
|
||||||
local pane_id="$session_name:$window_number.$pane_index"
|
|
||||||
local history_file="$(resurrect_history_file "$pane_id" "$pane_command")"
|
|
||||||
|
|
||||||
if [ "$pane_command" = "bash" ]; then
|
|
||||||
local read_command="history -r '$history_file'"
|
|
||||||
tmux send-keys -t "$pane_id" "$read_command" C-m
|
|
||||||
elif [ "$pane_command" = "zsh" ]; then
|
|
||||||
local accept_line="$(expr "$(zsh -i -c bindkey | grep -m1 '\saccept-line$')" : '^"\(.*\)".*')"
|
|
||||||
local read_command="fc -R '$history_file'; clear"
|
|
||||||
tmux send-keys -t "$pane_id" "$read_command" "$accept_line"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -359,7 +340,7 @@ restore_grouped_sessions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
restore_active_and_alternate_windows() {
|
restore_active_and_alternate_windows() {
|
||||||
awk 'BEGIN { FS="\t"; OFS="\t" } /^window/ && $6 ~ /[*-]/ { print $2, $4, $3; }' $(last_resurrect_file) |
|
awk 'BEGIN { FS="\t"; OFS="\t" } /^window/ && $6 ~ /[*-]/ { print $2, $5, $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}"
|
||||||
|
@ -389,10 +370,6 @@ main() {
|
||||||
restore_all_panes
|
restore_all_panes
|
||||||
handle_session_0
|
handle_session_0
|
||||||
restore_window_properties >/dev/null 2>&1
|
restore_window_properties >/dev/null 2>&1
|
||||||
execute_hook "pre-restore-history"
|
|
||||||
if save_shell_history_option_on; then
|
|
||||||
restore_shell_history
|
|
||||||
fi
|
|
||||||
execute_hook "pre-restore-pane-processes"
|
execute_hook "pre-restore-pane-processes"
|
||||||
restore_all_pane_processes
|
restore_all_pane_processes
|
||||||
# below functions restore exact cursor positions
|
# below functions restore exact cursor positions
|
||||||
|
|
|
@ -144,46 +144,6 @@ capture_pane_contents() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
save_shell_history() {
|
|
||||||
if [ "$pane_command" = "bash" ]; then
|
|
||||||
local history_w='history -w'
|
|
||||||
local history_r='history -r'
|
|
||||||
local accept_line='C-m'
|
|
||||||
local end_of_line='C-e'
|
|
||||||
local backward_kill_line='C-u'
|
|
||||||
elif [ "$pane_command" = "zsh" ]; then
|
|
||||||
# fc -W does not work with -L
|
|
||||||
# fc -l format is different from what's written by fc -W
|
|
||||||
# fc -R either reads the format produced by fc -W or considers
|
|
||||||
# the entire line to be a command. That's why we need -n.
|
|
||||||
# fc -l only list the last 16 items by default, I think 64 is more reasonable.
|
|
||||||
local history_w='fc -lLn -64 >'
|
|
||||||
local history_r='fc -R'
|
|
||||||
|
|
||||||
local zsh_bindkey="$(zsh -i -c bindkey)"
|
|
||||||
local accept_line="$(expr "$(echo "$zsh_bindkey" | grep -m1 '\saccept-line$')" : '^"\(.*\)".*')"
|
|
||||||
local end_of_line="$(expr "$(echo "$zsh_bindkey" | grep -m1 '\send-of-line$')" : '^"\(.*\)".*')"
|
|
||||||
local backward_kill_line="$(expr "$(echo "$zsh_bindkey" | grep -m1 '\sbackward-kill-line$')" : '^"\(.*\)".*')"
|
|
||||||
else
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local pane_id="$1"
|
|
||||||
local pane_command="$2"
|
|
||||||
local full_command="$3"
|
|
||||||
if [ "$full_command" = ":" ]; then
|
|
||||||
# leading space prevents the command from being saved to history
|
|
||||||
# (assuming default HISTCONTROL settings)
|
|
||||||
local write_command=" $history_w '$(resurrect_history_file "$pane_id" "$pane_command")'"
|
|
||||||
local read_command=" $history_r '$(resurrect_history_file "$pane_id" "$pane_command")'"
|
|
||||||
# C-e C-u is a Bash shortcut sequence to clear whole line. It is necessary to
|
|
||||||
# delete any pending input so it does not interfere with our history command.
|
|
||||||
tmux send-keys -t "$pane_id" "$end_of_line" "$backward_kill_line" "$write_command" "$accept_line"
|
|
||||||
# Immediately restore after saving
|
|
||||||
tmux send-keys -t "$pane_id" "$end_of_line" "$backward_kill_line" "$read_command" "$accept_line"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
get_active_window_index() {
|
get_active_window_index() {
|
||||||
local session_name="$1"
|
local session_name="$1"
|
||||||
tmux list-windows -t "$session_name" -F "#{window_flags} #{window_index}" |
|
tmux list-windows -t "$session_name" -F "#{window_flags} #{window_index}" |
|
||||||
|
@ -266,13 +226,6 @@ dump_pane_contents() {
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
dump_shell_history() {
|
|
||||||
dump_panes |
|
|
||||||
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"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_old_backups() {
|
remove_old_backups() {
|
||||||
# remove resurrect files older than 30 days (default), but keep at least 5 copies of backup.
|
# remove resurrect files older than 30 days (default), but keep at least 5 copies of backup.
|
||||||
local delete_after="$(get_tmux_option "$delete_backup_after_option" "$default_delete_backup_after")"
|
local delete_after="$(get_tmux_option "$delete_backup_after_option" "$default_delete_backup_after")"
|
||||||
|
@ -302,9 +255,6 @@ save_all() {
|
||||||
pane_contents_create_archive
|
pane_contents_create_archive
|
||||||
rm "$(pane_contents_dir "save")"/*
|
rm "$(pane_contents_dir "save")"/*
|
||||||
fi
|
fi
|
||||||
if save_shell_history_option_on; then
|
|
||||||
dump_shell_history
|
|
||||||
fi
|
|
||||||
remove_old_backups
|
remove_old_backups
|
||||||
execute_hook "post-save-all"
|
execute_hook "post-save-all"
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,9 +38,6 @@ pane_contents_option="@resurrect-capture-pane-contents"
|
||||||
pane_contents_area_option="@resurrect-pane-contents-area"
|
pane_contents_area_option="@resurrect-pane-contents-area"
|
||||||
default_pane_contents_area="full"
|
default_pane_contents_area="full"
|
||||||
|
|
||||||
bash_history_option="@resurrect-save-bash-history" # deprecated
|
|
||||||
shell_history_option="@resurrect-save-shell-history" # deprecated
|
|
||||||
|
|
||||||
# set to 'on' to ensure panes are never ever overwritten
|
# set to 'on' to ensure panes are never ever overwritten
|
||||||
overwrite_option="@resurrect-never-overwrite"
|
overwrite_option="@resurrect-never-overwrite"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue