7 Commits

Author SHA1 Message Date
3da5d61b5b v0.0.5 2014-08-28 01:11:56 +02:00
5509256a02 Update readme 2014-08-28 01:09:55 +02:00
cde50d4d92 Command strategies; restore vim sessions
Closes #4
2014-08-28 00:43:31 +02:00
07bba0fde7 Update readme 2014-08-27 21:31:10 +02:00
1e945c2cac Enable selectively restoring processes
- user can restore all processes with ':all:'
- user can selectively restore wanted processes

Closes #13
2014-08-27 16:19:36 +02:00
7f50660918 User option for disabling pane process restoring 2014-08-27 13:12:32 +02:00
cbf58ac613 Restore all pane processes
Close #3
2014-08-27 00:28:35 +02:00
7 changed files with 264 additions and 8 deletions

View File

@ -2,6 +2,14 @@
### master ### master
### v0.0.5, 2014-08-28
- restore pane processes
- user option for disabling pane process restoring
- enable whitelisting processes that will be restored
- expand readme with configuration options
- enable command strategies; enable restoring vim sessions
- update readme: explain restoring vim sessions
### v0.0.4, 2014-08-26 ### v0.0.4, 2014-08-26
- restore pane layout for each window - restore pane layout for each window
- bugfix: correct pane ordering in a window - bugfix: correct pane ordering in a window

View File

@ -1,11 +1,39 @@
# Tmux Session Saver # Tmux Session Saver
Enables saving and restoring of tmux sessions. Persists `tmux` environment across system restarts.
Tmux is great, except when you have to restart your computer. You loose all the
running programs, working directories, pane layouts etc.
There are helpful management tools out there, but they require initial
configuration and continuous updates as your workflow evolves or you start new
projects.
Enter `tmux-session-saver`: tmux persistence without configuration so there are
no interruptions in your workflow.
It will even (optionally) [restore vim sessions](#restoring-vim-sessions)!
### Key bindings ### Key bindings
- `prefix + M-s` - save - `prefix + Alt-s` - save
- `prefix + M-r` - restore - `prefix + Alt-r` - restore
### About
This plugin goes to great lengths to save and restore all the details from your
`tmux` environment. Here's what's been taken care of:
- all sessions, windows, panes and their order
- current working directory for each pane
- **exact pane layouts** within windows
- active and alternative session
- active and alternative window for each session
- active pane for each window
- programs running within a pane! More details in the [configuration section](#configuration).
- restoring vim sessions (optional). More details in
[restoring vim sessions](#restoring-vim-sessions).
Requirements / dependencies: `tmux 1.9` or higher, `pgrep`
### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended) ### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended)
@ -36,5 +64,45 @@ Reload TMUX environment:
You should now be able to use the plugin. You should now be able to use the plugin.
### Configuration
By default, only a conservative list of programs is restored:
`vim emacs man less more tail top htop irssi`.
Open a github issue if you think some other program should be on the default list.
- Restore additional programs by putting the following in `.tmux.conf`:
set -g @session-saver-processes 'ssh telnet myprogram'
- Don't restore any programs:
set -g @session-saver-processes 'false'
- Restore **all** programs (be careful with this!):
set -g @session-saver-processes ':all:'
#### Restoring vim sessions
- save vim sessions - I recommend [tpope/vim-obsession](tpope/vim-obsession)
- in `.tmux.conf`:
set -g @session-saver-strategy-vim "session"
`tmux-session-saver` will now restore vim sessions if `Sessions.vim` file is
present.
### Reporting bugs and contributing
Code contributions are welcome!
If you find a bug please report it in the issues. When reporting a bug please
attach a file symlinked to `~/.tmux/sessions/last`.
### Credits
[Mislav Marohnić](https://github.com/mislav) - the idea for the plugin came from his
[tmux-session script](https://github.com/mislav/dotfiles/blob/master/bin/tmux-session).
### License ### License
[MIT](LICENSE.md) [MIT](LICENSE.md)

View File

@ -1,6 +1,6 @@
# configurable constants # configurable constants
default_sessions_dir="$HOME/.tmux/sessions" default_sessions_dir="$HOME/.tmux/sessions"
sessions_dir_option="@sessions-dir" sessions_dir_option="@session-saver-dir"
SUPPORTED_VERSION="1.9" SUPPORTED_VERSION="1.9"

View File

@ -0,0 +1,121 @@
# default processes that are restored
default_proc_list_option="@session-saver-default-processes"
default_proc_list="vim emacs man less more tail top htop irssi"
# User defined processes that are restored
# 'false' - nothing is restored
# ':all:' - all processes are restored
#
# user defined list of programs that are restored:
# 'my_program foo another_program'
restore_processes_option="@session-saver-processes"
restore_processes=""
# Defines part of the user variable. Example usage:
# set -g @session-saver-strategy-vim "session"
restore_process_strategy_option="@session-saver-strategy-"
restore_pane_processes_enabled() {
local restore_processes="$(get_tmux_option "$restore_processes_option" "$restore_processes")"
if [ "$restore_processes" == "false" ]; then
return 1
else
return 0
fi
}
restore_pane_process() {
local pane_full_command="$1"
local session_name="$2"
local window_number="$3"
local pane_index="$4"
local dir="$5"
if _process_should_be_restored "$pane_full_command"; then
tmux switch-client -t "${session_name}:${window_number}"
tmux select-pane -t "$pane_index"
if _strategy_exists "$pane_full_command"; then
local strategy_file="$(_get_strategy_file "$pane_full_command")"
local strategy_command="$($strategy_file "$pane_full_command" "$dir")"
tmux send-keys "$strategy_command" "C-m"
# tmux send-keys "Strategy! $pane_full_command $strategy_file"
# tmux send-keys "Strategy! $strategy_command"
else
# just invoke the command
tmux send-keys "$pane_full_command" "C-m"
fi
fi
}
# private functions below
_process_should_be_restored() {
local pane_full_command="$1"
if _restore_all_processes; then
return 0
elif _process_on_the_restore_list "$pane_full_command"; then
return 0
else
return 1
fi
}
_restore_all_processes() {
local restore_processes="$(get_tmux_option "$restore_processes_option" "$restore_processes")"
if [ $restore_processes == ":all:" ]; then
return 0
else
return 1
fi
}
_process_on_the_restore_list() {
local pane_full_command="$1"
local restore_list="$(_restore_list)"
local proc
for proc in $restore_list; do
if [[ "$pane_full_command" =~ (^$proc) ]]; then
return 0
fi
done
return 1
}
_restore_list() {
local user_processes="$(get_tmux_option "$restore_processes_option" "$restore_processes")"
local default_processes="$(get_tmux_option "$default_proc_list_option" "$default_proc_list")"
if [ -z $user_processes ]; then
# user didn't define any processes
echo "$default_processes"
else
echo "$default_processes $user_processes"
fi
}
_strategy_exists() {
local pane_full_command="$1"
local strategy="$(_get_command_strategy "$pane_full_command")"
if [ -n "$strategy" ]; then # strategy set?
local strategy_file="$(_get_strategy_file "$pane_full_command")"
[ -e "$strategy_file" ] # strategy file exists?
else
return 1
fi
}
_get_command_strategy() {
local pane_full_command="$1"
local command="$(_just_command "$pane_full_command")"
get_tmux_option "${restore_process_strategy_option}${command}" ""
}
_just_command() {
echo "$1" | cut -d' ' -f1
}
_get_strategy_file() {
local pane_full_command="$1"
local strategy="$(_get_command_strategy "$pane_full_command")"
local command="$(_just_command "$pane_full_command")"
echo "$CURRENT_DIR/../strategies/${command}_${strategy}.sh"
}

View File

@ -3,6 +3,7 @@
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$CURRENT_DIR/helpers.sh" source "$CURRENT_DIR/helpers.sh"
source "$CURRENT_DIR/process_restore_helpers.sh"
is_line_type() { is_line_type() {
local line_type="$1" local line_type="$1"
@ -75,8 +76,9 @@ new_pane() {
restore_pane() { restore_pane() {
local pane="$1" local pane="$1"
echo "$pane" | echo "$pane" |
while IFS=$'\t' read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active; do while IFS=$'\t' read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command pane_full_command; do
window_name="$(remove_first_char $window_name)" window_name="$(remove_first_char "$window_name")"
pane_full_command="$(remove_first_char "$pane_full_command")"
if window_exists "$session_name" "$window_number"; then if window_exists "$session_name" "$window_number"; then
new_pane "$session_name" "$window_number" "$window_name" "$dir" new_pane "$session_name" "$window_number" "$window_name" "$dir"
elif session_exists "$session_name"; then elif session_exists "$session_name"; then
@ -104,6 +106,17 @@ restore_all_sessions() {
done < $(last_session_path) done < $(last_session_path)
} }
restore_all_pane_processes() {
if restore_pane_processes_enabled; then
local pane_full_command
awk 'BEGIN { FS="\t"; OFS="\t" } /^pane/ && $11 !~ "^:$" { print $2, $3, $7, $8, $11; }' $(last_session_path) |
while IFS=$'\t' read session_name window_number pane_index dir pane_full_command; do
pane_full_command="$(remove_first_char "$pane_full_command")"
restore_pane_process "$pane_full_command" "$session_name" "$window_number" "$pane_index" "$dir"
done
fi
}
restore_pane_layout_for_each_window() { restore_pane_layout_for_each_window() {
\grep '^window' $(last_session_path) | \grep '^window' $(last_session_path) |
while IFS=$'\t' read line_type session_name window_number window_active window_flags window_layout; do while IFS=$'\t' read line_type session_name window_number window_active window_flags window_layout; do
@ -139,7 +152,9 @@ main() {
if supported_tmux_version_ok; then if supported_tmux_version_ok; then
check_saved_session_exists check_saved_session_exists
restore_all_sessions restore_all_sessions
restore_pane_layout_for_each_window restore_all_pane_processes
restore_pane_layout_for_each_window >/dev/null 2>&1
# below functions restore exact cursor positions
restore_active_pane_for_each_window restore_active_pane_for_each_window
restore_active_and_alternate_windows restore_active_and_alternate_windows
restore_active_and_alternate_sessions restore_active_and_alternate_sessions

View File

@ -24,6 +24,10 @@ pane_format() {
format+="#{pane_current_path}" format+="#{pane_current_path}"
format+="${delimiter}" format+="${delimiter}"
format+="#{pane_active}" format+="#{pane_active}"
format+="${delimiter}"
format+="#{pane_current_command}"
format+="${delimiter}"
format+="#{pane_pid}"
echo "$format" echo "$format"
} }
@ -55,10 +59,27 @@ state_format() {
echo "$format" echo "$format"
} }
dump_panes() { dump_panes_raw() {
tmux list-panes -a -F "$(pane_format)" tmux list-panes -a -F "$(pane_format)"
} }
pane_full_command() {
pane_pid="$1"
\pgrep -lf -P "$pane_pid" |
cut -d' ' -f2-
}
# translates pane pid to process command running inside a pane
dump_panes() {
local full_command
local d=$'\t' # delimiter
dump_panes_raw |
while IFS=$'\t' read line_type session_name window_number window_name window_active window_flags pane_index dir pane_active pane_command pane_pid; do
full_command="$(pane_full_command $pane_pid)"
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}"
done
}
dump_windows() { dump_windows() {
tmux list-windows -a -F "$(window_format)" tmux list-windows -a -F "$(window_format)"
} }

23
strategies/vim_session.sh Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
# "vim session strategy"
#
# Restores a vim session from 'Session.vim' file, if it exists.
# If 'Session.vim' does not exist, it falls back to invoking the original
# command.
ORIGINAL_COMMAND="$1"
DIRECTORY="$2"
vim_session_file_exists() {
[ -e "${DIRECTORY}/Session.vim" ]
}
main() {
if vim_session_file_exists; then
echo "vim -S"
else
echo "$ORIGINAL_COMMAND"
fi
}
main