Compare commits

...

183 Commits

Author SHA1 Message Date
Bruno Sutic cff343cf9e
Merge pull request #474 from georgeanderson/master
Update description of default session location
2023-03-06 11:20:22 +01:00
George Guimares 4c1c0dcf85 Updated description of default session location.
- Include alternate location
- Include reference to `${XDB_DATA_HOME}` env variable
2023-03-05 20:58:11 -06:00
Bruno Sutic 6df04051fe
Merge pull request #469 from ktprograms/restore-arguments-misc-fixes
Restore with command arguments misc fixes
2023-01-31 10:40:52 +01:00
kt programs 299c4aa8ce docs: add info on asterisk (*) restore option 2023-01-30 10:50:07 +08:00
kt programs b8ff2ea08b _get_proc_restore_command: use "," as sed delimiter
When command_arguments contains a path, there are too many delimiters
for sed, which causes it to not replace properly.

The result of this is that the original command gets executed without
remapping and/or expanding the arguments.
2023-01-30 10:37:15 +08:00
kt programs 4941cdb074 _get_command_arguments: make trailing space optional
When pane_full_command has no arguments, the regex doesn't find argv[0]
as there is no trailing space.

For example, if pane_full_command was "vim" and the restore option was
"~Vim->vim *", the command "vim vim" would get executed instead of just
"vim".

Make the trailing space optional to match having only the command
without arguments.
2023-01-30 10:37:15 +08:00
Bruno Sutic a2ddfb96b9
Merge pull request #458 from oliverlew/xdg_dir
use XDG_DATA_HOME for resurrect-dir path
2022-10-22 16:31:55 +02:00
Lu Xu dd36a4561b
use XDG_DATA_HOME for resurrect-dir path 2022-10-22 14:21:51 +08:00
Bruno Sutic 88297b4c3a
Merge pull request #455 from tfaughnan/ps-fix
ps.sh: fix ps arguments to work for busybox
2022-09-22 09:14:40 +02:00
Thomas Faughnan 45aa8feef6
ps.sh: fix ps arguments to work for busybox
Use the format specifier 'ppid,args' instead of 'ppid command'. POSIX
allows either spaces or commas as separators, but busybox only allows
commas. Furthermore, 'args' is recognized by POSIX[0] while 'command' is
not. On implementations of ps that do recognize 'command', it is simply
an alias for 'args', e.g. Debian[1] and FreeBSD[2].

[0]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
[1]: https://manpages.debian.org/bullseye/procps/ps.1.en.html
[2]: https://www.freebsd.org/cgi/man.cgi?query=ps
2022-09-20 18:30:28 -04:00
Bruno Sutic 75458f91c8
Merge pull request #450 from mdeguzis/master
Use bash subshell for procfs interpolation of cmdline file
2022-08-17 09:09:56 +02:00
Michael T. DeGuzis 1431ba6fbe Use bash subshell for procfs interpolation of cmdline file 2022-08-16 08:57:39 -04:00
Bruno Sutic 3606e4f602
Merge pull request #443 from rbren/master
Fix for restoring bash history
2022-07-16 13:55:50 +02:00
Robert Brennan 7f5fa4bed2
Update restoring_bash_history.md 2022-07-15 16:36:24 -04:00
Bruno Sutic 74d9112314
Merge pull request #442 from rbren/master
Create restoring_bash_history.md
2022-06-26 09:18:44 +02:00
Robert Brennan 8101d98358
Create restoring_bash_history.md 2022-06-25 16:33:19 -04:00
Bruno Sutic ca6468e2de
Fix restoring active/alternate windows 2022-05-01 17:32:14 +02:00
Bruno Sutic 6050d2d8d8
Remove deprecated "restoring shell history" 2022-04-10 08:58:27 +02:00
Bruno Sutic e87d7d592c
v4.0.0 2022-04-10 08:40:19 +02:00
Bruno Sutic 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
Jiří Málek 1ad109d3a8
Adds support for saving and restoring pane titles. 2022-04-09 13:52:28 +02:00
Bruno Sutic 027960ad25
Explain delayed pane content cleanup 2021-12-19 16:21:44 +01:00
Bruno Sutic dc6252d950
Merge pull request #422 from cartoonist/master
Fix #141
2021-12-19 16:19:30 +01:00
Ali Ghaffaari 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
Bruno Sutic 6be2f34b5f
automatic-rename: changelog and comments 2021-08-30 14:17:15 +02:00
Bruno Sutic 4234ba99aa
Merge pull request #401 from Farzat07/automatic-rename2
Maintain the value of automatic-rename
2021-08-30 14:07:33 +02:00
Bruno Sutic 003a7cddbb
v3.0.0 2021-08-30 14:06:58 +02:00
A Farzat 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
A Farzat 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
A Farzat 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
A Farzat 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
A Farzat 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
Yordan Georgiev 716b958145
enable tilde expansion ( aka ~ ) into /home/ubuntu in saved session files's paths 2021-07-05 09:53:56 +02:00
Bruno Sutic abbc4fbfc4
Merge pull request #381 from chrysn-pull-requests/doc-improvement
More explicit warning of restoring :all: programs
2021-03-18 11:52:35 +01:00
chrysn dff7b2d2ae More explicit warning of restoring :all: programs
Closes: https://github.com/tmux-plugins/tmux-resurrect/issues/250
2021-03-17 12:54:21 +01:00
Bruno Sutic 1c0eae57c8
Merge pull request #325 from alfredbez/master
How to restore to a previously saved environment
2021-03-13 11:49:28 +01:00
alfredbez afcddf8b9e Add link to how-to restore to a previously saved environment 2021-03-12 13:10:21 +01:00
Bruno Sutic 4a36ded50f
Merge pull request #376 from coldeasy/patch-1
Add extra detail around using MacVim
2021-02-02 16:00:52 +01:00
Colin Deasy 76656c510b
Add extra detail around using MacVim 2021-02-01 15:34:21 +00:00
Bruno Sutic e4825055c9
Merge pull request #361 from diegoximenes/fix/restore_window_renaming
Fix rename-window's target-window during restore
2020-09-18 10:59:01 +02:00
Diego Ximenes b6cbf652c4 Fix rename-window's target-window during restore 2020-09-18 00:47:32 -03:00
Bruno Sutic 123d83c668
Do not output deleted files to stdout 2020-08-17 10:32:11 +02:00
Ash Berlin-Taylor e815c50f13
Make backup retention period configurable
For instance `tmux set-option -g @resurrect-delete-backup-after 1`
to only keep 1 day of backups.

Closes 252.
2020-08-17 10:28:42 +02:00
Bruno Sutic 5f5f9d8fd5
Kill session 0 if it's not restored 2020-08-03 08:58:41 +02:00
Bruno Sutic 78d67e4dcb
Merge pull request #211 from malkomalko/mm-rename-window
actually rename windows when restoring
2020-07-27 09:18:18 +02:00
Bruno Sutic da1a755802
Whitespace cleanup 2020-06-14 11:37:47 +02:00
Bruno Sutic e4e21f3f48
Restore command args for inline strategies with '*'
Example inline strategy: "~/bin/my_program->my_program *"
for full command: "ruby /Users/john/bin/my_program arg1 arg2"
restores command: "my_program arg1 arg2"
2020-06-14 11:33:31 +02:00
Bruno Sutic bd671b83dc
Don't be too smart when restoring vim session
A user may decide to use custom session file. Eg vim -S Session1.vim
With the previous approach we were preventing that as we only checked
for the existence of the default Session.vim file.
2020-06-05 09:24:42 +02:00
Bruno Sutic 327c0481ad
Add 'view' to the list of restored processes 2020-03-21 23:51:59 +01:00
Bruno Sutic 905abba3c3
Merge pull request #283 from rummik/cmdline
Add cmdline save strategy
2019-12-17 18:03:06 +01:00
*Kim Zick 2382467b8e
Change `CPID` to something a little less cryptic 2019-12-17 11:04:45 -05:00
*Kim Zick 17cf30a69c
Rename cmdline.sh to linux_procfs.sh 2019-12-17 11:00:52 -05:00
Helmut K. C. Tessarek 1160c1da71
only add -l when default_shell is bash 2019-12-06 13:00:39 +01:00
Bruno Sutic c66b791fff
Merge pull request #281 from lwilke/hotfix/94_use_login_shell_with_default_shell
Fix #94 start default-shell as login shell.
2019-11-27 14:56:15 +01:00
Bruno Sutic 0f0ec12e92
Merge pull request #308 from tmux-plugins/deprecate_restoring_shell_history
Deprecate restoring shell history
2019-10-21 12:03:38 +02:00
Bruno Sutic d7825683d1
Deprecate restoring shell history
"restoring shell history" feature is very invasive and dirty. I propose
removing it in the future without the replacement.

I worry it spoils the first experience of using this plugin for users
that accidentally turn it on and don't know how to turn it off, see
https://github.com/tmux-plugins/tmux-resurrect/issues/288

Also, it hurts me to reject PRs that improve the feature.

Thoughts?
2019-08-27 13:26:29 +02:00
Bruno Sutic e3f05dd34f
Update README.md 2019-04-19 12:44:26 +02:00
Bruno Sutic 8fcb4ab40b
Merge pull request #291 from pattersongp/bugfix-162
Adds a fix for directory paths with spaces that aren't escaped.
2019-03-01 18:19:42 +01:00
Graham Patterson a876ad6648 Adds a fix for directory paths with spaces that aren't escaped. 2019-03-01 10:37:01 -05:00
*Kim Zick (rummik) ac8a446667 Remove lingering code from base64-dependent cmdline solution 2019-01-07 11:34:59 -05:00
Bruno Sutic c3ffe89e52
Merge pull request #284 from rummik/mosh-client-strategy
Add mosh-client default strategy
2019-01-07 13:35:20 +01:00
*Kim Zick (rummik) e99f1977b6 Add mosh-client default strategy 2018-12-28 20:08:46 -05:00
*Kim Zick (rummik) 913f693f80 Remove cmdline dependency on base64 and perl 2018-12-28 19:37:33 -05:00
*Kim Zick (rummik) 15cabbb930 Fixes for cmdline save/restore strategy 2018-12-28 17:16:53 -05:00
donat-b edd8132bef Add cmdline strategy 2018-12-27 22:45:15 -05:00
Lars Wilke 9187f8b377 Fix #94 start default-shell as login shell.
If pane content is restored and no default-command is set, restore.sh
falls back to default-shell, which tmux sets automatically and calls as
a login shell.

In pane_creation_command() we need to make sure to call default-shell as a login shell.
As tmux does. But take care not to call default-command as a login shell.
2018-12-10 10:43:16 +01:00
Bruno Sutic b020b2481e
Merge pull request #220 from kevinkjt2000/fix-issue-95
fix #95 restore name of first window
2018-11-30 13:29:24 +01:00
Bruno Sutic e5cbe54c75
Merge pull request #272 from JBlond/master
Windows file names can not contain a colon
2018-10-08 11:42:29 +02:00
Mario 71b93407f2
Changed to fit ISO8601
See https://github.com/tmux-plugins/tmux-resurrect/pull/272#issuecomment-419934801
2018-09-11 13:23:58 +02:00
Bruno Sutic 9dc3f8c639
Always use 'ps -ao' to detect commands
Previously we used 'ps -eo' for some operating systems. It turns out
flags '-ao' work fine for all, and it should also be fine per posix spec

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html#tag_20_96
2018-09-11 11:16:30 +02:00
Mario 8b504d4b06
Windows file names can not contain a colon
That would solve https://github.com/tmux-plugins/tmux-resurrect/issues/131
2018-09-10 10:46:09 +02:00
Bruno Sutic 6feae65a83
Merge pull request #267 from ashb/save-restore-hooks
Further Save and restore hooks
2018-08-20 16:57:24 +02:00
Ash Berlin-Taylor 8aa999c591 Add more hook points
And make the hook calling simpler at the call site.
2018-08-20 12:17:43 +01:00
Sergey Vlasov 0133c7a96a Save and restore hooks 2018-08-17 20:19:27 +01:00
Bruno Sutic 42f77b303c
Merge pull request #233 from woutgg/master
Fix https://github.com/tmux-plugins/tmux-resurrect/issues/176.
2018-01-28 17:40:17 +01:00
Wouter R 2f5394bfed Remove superfluous if-block. 2018-01-27 19:08:28 +01:00
Wouter R fee390d1b5 Update tests to save and restore a setup with a zoomed pane. 2018-01-24 22:32:35 +01:00
Wouter R 6d10ee01b6 Fix https://github.com/tmux-plugins/tmux-resurrect/issues/176.
This removes (un)zooming on save which should not be necessary anymore
with recent tmux versions (from 2.2 on?).
2018-01-24 18:20:44 +01:00
Kevin Tindall 8f3f8d7cb9
fix #95 restore name of first window 2017-12-03 22:11:51 -06:00
Bruno Sutic 7c77c70483
Merge pull request #214 from mc10/patch-1
README: Use the SVG Travis badge
2017-11-14 13:17:47 +01:00
Kevin Ji 195a16f35f
README: Use the SVG Travis badge 2017-11-14 02:40:05 -08:00
Robert Malko 365a2e78ae
actually rename windows when restoring 2017-10-30 08:40:56 -07:00
Bruno Sutic 9c7ec631d4 Merge pull request #210 from eugenevd/20171014-remove_old_backups-find
remove_old_backups() : replace xargs with -exec to handle 0 files found better
2017-10-26 14:06:11 +04:00
Eugene Van Dam 5f3873c502 remove_old_backups() : replace xargs with -exec to handle 0 files found
by find better
2017-10-25 14:30:50 +02:00
Bruno Sutic dcef21995a Merge pull request #209 from job/add_weechat
Add weechat to conservative list
2017-10-10 12:14:25 +02:00
Job Snijders e3878caa75 Add weechat to conservative list 2017-10-10 08:12:44 +00:00
Bruno Sutic 4f7f4e00ae Merge pull request #206 from nguymin4/improve-doc
Add instruction for NodeJS related project and tools
2017-09-24 19:44:31 +02:00
Minh Son Nguyen 75ecae9bcb Add instruction for NodeJS related project and tools 2017-09-24 06:36:31 +03:00
Bruno Sutic 3a31bfbbb8
Use 'xargs rm' instead of 'find -delete' 2017-06-04 00:52:37 +02:00
Bruno Sutic 241f62089a
Update changelog 2017-06-04 00:32:53 +02:00
Bruno Sutic fe8390a578
Resurrect file prefix and extension vars 2017-06-04 00:31:17 +02:00
Xu Cheng 9d81e8d026
auto remove old backup files
remove backup files older than 30 days, but keep at least 5 copies of backup.

Fixes #102.
2017-06-04 00:23:50 +02:00
Bruno Sutic 7e0bfcb7e9
Remove comment 2017-06-04 00:19:51 +02:00
Mohammad Alsaleh aaec581334
Immediately restore shell history after saving
This is necessary for zsh.

Signed-off-by: Mohammad Alsaleh <CE.Mohammad.AlSaleh@gmail.com>
2017-06-04 00:17:36 +02:00
Mohammad Alsaleh ea3cbcedc6
Add zsh history saving and restoring to CHANGELOG.md
Signed-off-by: Mohammad Alsaleh <CE.Mohammad.AlSaleh@gmail.com>
2017-06-04 00:17:35 +02:00
Mohammad Alsaleh bf07546645
mv docs/restoring_{bash,shell}_history.md and update the doc
Signed-off-by: Mohammad Alsaleh <CE.Mohammad.AlSaleh@gmail.com>
2017-06-04 00:16:53 +02:00
Mohammad Alsaleh 2c9cc224c0
Rename dump_bash_history() to dump_shell_history()
Signed-off-by: Mohammad Alsaleh <CE.Mohammad.AlSaleh@gmail.com>
2017-06-04 00:16:52 +02:00
Mohammad Alsaleh 655ed8c6f4
Add @resurrect-save-shell-history option
Also make @resurrect-save-bash-history an alias to the new option.

Signed-off-by: Mohammad Alsaleh <CE.Mohammad.AlSaleh@gmail.com>
2017-06-04 00:16:51 +02:00
Mohammad Alsaleh e757e1b8a9
Add zsh support in save/restore functions
Signed-off-by: Mohammad Alsaleh <CE.Mohammad.AlSaleh@gmail.com>
2017-06-04 00:15:01 +02:00
Bruno Sutic fbed36ad0e
Allow using '$HOSTNAME' in @resurrect-dir
Closes #197
2017-06-01 17:35:00 +02:00
Bruno Sutic eef844c747
Memoize return of resurrect path functions 2017-06-01 17:03:39 +02:00
Bruno Sutic b7a4ee2a40
Pane contents save and restore in separate dirs 2017-06-01 05:47:09 +02:00
Bruno Sutic ba59a2b642
Revert "remove pane contents cleanup to repair restore"
This reverts commit 0a6f90788f.
2017-05-30 06:14:21 +02:00
Bruno Sutic 573897cd71
Revert "Remove pane_content_files_cleanup function"
This reverts commit 7a8d90a27d.
2017-05-30 06:11:41 +02:00
Bruno Sutic 7a8d90a27d
Remove pane_content_files_cleanup function 2017-05-30 05:49:51 +02:00
Bruno Sutic 8de2570960 Merge pull request #193 from Mellbourn/restore-pane-fix
remove pane contents cleanup to repair restore
2017-05-30 05:49:13 +02:00
Bruno Sutic 1a3a094265
Make send-keys more reliable
Thanks @mk12 for the PR
https://github.com/tmux-plugins/tmux-resurrect/pull/180
2017-05-30 05:43:12 +02:00
Bruno Sutic 40c776c747 Merge pull request #194 from Mellbourn/remove-terminal-clearing
remove terminal clearing since it collides with capture-pane-contents
2017-05-30 05:31:27 +02:00
Bruno Sutic b1f3df21e9
Create new file only if there are changes
Code submitted by @vburdo in
https://github.com/tmux-plugins/tmux-resurrect/issues/156
2017-05-30 05:14:14 +02:00
Bruno Sutic dec4e15fc5
Update '.travis.yml' from tmux-test 2017-05-30 05:04:08 +02:00
Bruno Sutic 14b2a97791
Update tmux-test 2017-05-30 05:02:58 +02:00
Bruno Sutic 0a2de2ea44
Fix tests for tmux 2.5 2017-05-30 04:55:10 +02:00
Bruno Sutic 69480dcd87
Update tmux-test 2017-05-30 04:54:59 +02:00
Bruno Sutic 5722856e54
Fix bug for restoring commands on tmux 2.5 2017-05-30 02:05:23 +02:00
Klas Mellbourn 0a6f90788f remove pane contents cleanup to repair restore
as suggested in https://github.com/tmux-plugins/tmux-resurrect/issues/141
2017-05-07 19:35:06 +02:00
Klas Mellbourn 71fd3c8dd2 remove terminal clearing since it collides with capture-pane-contents 2017-05-06 00:37:13 +02:00
Bruno Sutic b8cc90a7f4 Merge pull request #148 from kmiasko/patch-1
Fixed typo in Session.vim file name.
2016-05-28 17:27:40 +02:00
Krzysztof Miąsko c6a4d9dfd1 Fixed typo in Session.vim file name. 2016-05-16 23:28:54 +02:00
Bruno Sutic a2eb3b01d2 Merge pull request #125 from HeathNaylor/master
Fix comparision operators. Fixes #124
2016-01-30 10:49:40 +01:00
Heath Naylor 3bc852bbae Fix comparision operators. Fixes #124 2016-01-29 09:41:52 -07:00
Bruno Sutic 370b4861cb Revert "Symlink 'last' file at the end of successful save"
This reverts commit 6750a88e74.
2015-11-25 13:42:37 +01:00
Bruno Sutic 6750a88e74
Symlink 'last' file at the end of successful save 2015-11-25 13:40:54 +01:00
Bruno Sutic 5f04ceabbc
Add sleep when saving zoomed windows
When saving zoomed windows:

- window is un-zoomed
- window layout snapshot is taken
- window is zoomed back

This is done because otherwise tmux does not provide correct window
layout. With this we're working around a tmux bug really.

The above causes an issue with vim. For some reason vim cannot properly
reload it's content when "un-zoom + zoom" is done quickly. Everything
works ok if a little sleep/wait is added, so we're doing just that.
0.1 second sleep seems to be enough.

About `sleep 0.1 || sleep 1`: this is a hack. We want to wait for 0.1
seconds, which seems to be enough to fix the issue. However, according
to POSIX, `sleep` command takes only integers.
BUT, decimal values seem to work everywhere. So, we're using a decimal
value, and if that fails, we behave POSIX friendly.

Related to issue #112.
2015-10-26 01:22:46 +01:00
Bruno Sutic fbfb0993a1 Merge pull request #113 from peteches/master
Adding png attributes as binary files so git does not swap the crlf t…
2015-10-15 13:58:45 +02:00
Pete "Peteches" McCabe 7fc9757e9d Adding png attributes as binary files so git does not swap the crlf to lf. 2015-10-14 18:06:20 +00:00
Bruno Sutic 3ae61a70f2
Mention cygwin support in the terminal 2015-10-08 18:30:08 +02:00
Bruno Sutic c0eeb04874
Improve cygwin support 2015-10-08 18:25:16 +02:00
Bruno Sutic 7fd2c979f0
Document known issue for restore pane contents feature 2015-08-21 17:46:39 +02:00
Bruno Sutic 550ef94ec4
Update doc for restoring programs 2015-08-20 02:50:22 +02:00
Bruno Sutic 66e95a243a
Migrating from tmuxinator guide typo 2015-08-19 00:01:03 +02:00
Bruno Sutic 53578fee8b
Added guide for migrating from tmuxinator 2015-08-18 23:56:57 +02:00
Bruno Sutic 06b8ad744a
Mutt added to the list of automatically restored programs 2015-08-14 19:23:36 +02:00
Bruno Sutic 82837109d4
Additional info about restoring programs 2015-08-10 19:35:56 +02:00
Bruno Sutic 4d5c30c29a
Move all docs to 'docs/' dir 2015-08-10 18:56:50 +02:00
Bruno Sutic e81f8e5f37
More portable pane_capture archiving 2015-07-10 19:29:40 +02:00
Bruno Sutic a47236d247
Implement pane content files compression 2015-07-10 18:01:20 +02:00
Bruno Sutic a750628a44
Change 'save pane contents' directory 2015-07-08 00:14:40 +02:00
Bruno Sutic 74773bed62
Save pane contents only if pane not blank 2015-07-08 00:02:20 +02:00
Bruno Sutic aa0b424ca6
Refactoring 2015-07-07 23:35:41 +02:00
Bruno Sutic 852af79075
Do not save empty trailing lines when pane content is saved 2015-07-07 19:23:47 +02:00
Bruno Sutic 6fe70853a5
Expand tilde in @resurrect-dir
Fixes #74
2015-07-07 18:23:43 +02:00
Bruno Sutic cb6e31e12f
Update readme 2015-07-07 18:03:10 +02:00
Bruno Sutic 8ca7c5374f
Update readme wording 2015-07-07 02:33:53 +02:00
Bruno Sutic ab91fe1cb5
Readme update for TPM changes 2015-07-07 02:31:18 +02:00
Dmitry Motylev ed6fb9b523
try to treat inline strategy as alias for strategy
if strategy with that name exists apply it otherwise use it as inline
strategy

Closes #88
2015-06-11 15:29:13 +02:00
Bruno Sutic 8af7aed9b3
Bugfix for pane contents restoration 2015-05-12 13:31:13 +02:00
Bruno Sutic f3c6321501
Refactoring: drop dependency on command 2015-05-09 15:05:30 +02:00
Bruno Sutic c85a3b4487
Improve pane content restore: remove extra `cat` 2015-05-09 14:05:51 +02:00
Bruno Sutic fee40e2121
Capture pane contents feature, small refactor 2015-05-09 12:37:37 +02:00
Bruno Sutic 00008e7f40
Quiet set-options in resurrect.tmux
Using "loud" set-options command is an issue when plugin is installed
manually.

Fixes #83
2015-04-23 14:22:55 +02:00
Bruno Sutic c32fb488e7
Update tmux-test 2015-04-20 01:31:54 +02:00
Bruno Sutic 6a6a87626a
Add 'save&restore pane contents' feature to changelog and readme 2015-04-02 15:20:32 +02:00
Bruno Sutic c3d5a8c19c Merge pull request #79 from laomaiweng/resurrect-pane-contents
Save and restore tmux pane contents
2015-04-02 14:17:50 +02:00
quentin 737568922b Make "full" pane contents saving the default 2015-03-18 22:38:38 +01:00
quentin a1e3d37461 Correctly capture wrapped lines in the pane contents
Add the -J options to `capture-pane` to handle wrapped lines correctly.
This way wrapped lines will be joined upon capture and once restored,
will re-wrap upon pane size changes.
2015-03-18 10:14:20 +01:00
Bruno Sutic 5d46aa27d0
Update readme 2015-03-18 02:33:13 +01:00
quentin 4f685d5c3d Add an option to save the full pane contents
By default only the visible pane area is captured and restored.
The @resurrect-pane-contents-area option lets the full pane area be
captured instead.
2015-03-17 04:13:54 +01:00
quentin b22b2a7203 Save and restore tmux pane contents
This feature is controlled by the '@resurrect-capture-pane-contents'
option.
Currently only the visible area of each pane is saved and restored.
2015-03-17 03:17:37 +01:00
Bruno Sutic 9c63ea625b
v2.4.0 2015-02-23 02:05:18 +01:00
Bruno Sutic 7258e29656
Remove typo 2015-02-23 01:27:25 +01:00
Bruno Sutic 781b5104e4
Add travis badge to the readme 2015-02-23 01:21:13 +01:00
Bruno Sutic f4f36a5af9
Update changelog 2015-02-23 01:19:19 +01:00
Bruno Sutic d4ec690610
Use more 'tmux-test' functions 2015-02-23 01:19:05 +01:00
Bruno Sutic d9ac38bef9
Update 'tmux-test' 2015-02-23 01:18:45 +01:00
Bruno Sutic c5bc35932b
Run setup task from .travis.yml 2015-02-23 00:46:41 +01:00
Bruno Sutic a3dd99085a
Fix tests for travis 2015-02-23 00:05:54 +01:00
Bruno Sutic 157bd5e38a
Do not gitignore 'tmux-test' files 2015-02-22 22:31:57 +01:00
Bruno Sutic 890a413b9f
Update changelog 2015-02-22 21:54:20 +01:00
Bruno Sutic 9cabda7c71
Resurrect restore test and updates 2015-02-22 21:53:33 +01:00
Bruno Sutic 66916085d9
Update resurrect save test 2015-02-22 21:20:46 +01:00
Bruno Sutic 30366a3cb4
Test resurrect save feature 2015-02-22 20:49:59 +01:00
Bruno Sutic ac86e025ad
Setup 'tmux-test' 2015-02-22 18:41:58 +01:00
Bruno Sutic 8b183f373f
Readme update 2015-02-20 14:18:24 +01:00
Bruno Sutic 5c1105c579
Update readme 2015-02-20 14:16:46 +01:00
Bruno Sutic 3dd5441d42
Link to tmux-continuum instead of tmux-resurrect-auto 2015-02-20 13:44:46 +01:00
Bruno Sutic 703df121e2
Readme update 2015-02-12 15:31:32 +01:00
Bruno Sutic 2bc9bc0dd7
Mention tmux-resurrect-auto in the readme 2015-02-12 14:21:16 +01:00
Bruno Sutic 671699a054
v2.3.0 2015-02-12 14:13:22 +01:00
Bruno Sutic b7e7669999
Improve fetching "window_layout" value
It's faster now.
2015-02-12 14:10:56 +01:00
Bruno Sutic 952e1f9784
v2.2.0 2015-02-12 12:53:47 +01:00
Bruno Sutic abad85f03b
Enable quiet saving 2015-02-12 12:53:19 +01:00
Bruno Sutic e1b01ee4f9
Export script paths so that 'tmux-resurrect-auto' plugin can use them 2015-02-12 12:48:44 +01:00
Bruno Sutic 708cd49d31
Fix a zoomed windows related regression 2015-02-12 12:47:09 +01:00
37 changed files with 1221 additions and 198 deletions

5
.gitattributes vendored Normal file
View File

@ -0,0 +1,5 @@
# Force text files to have unix eols, so Windows/Cygwin does not break them
*.* eol=lf
# Except for images because then on checkout the files have been altered.
*.png binary

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
run_tests
tests/run_tests_in_isolation
tests/helpers/helpers.sh

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "lib/tmux-test"]
path = lib/tmux-test
url = https://github.com/tmux-plugins/tmux-test.git

19
.travis.yml Normal file
View File

@ -0,0 +1,19 @@
# generic packages and tmux
before_install:
- sudo apt-get update
- sudo apt-get install -y git-core expect
- sudo apt-get install -y python-software-properties software-properties-common
- sudo apt-get install -y libevent-dev libncurses-dev
- git clone https://github.com/tmux/tmux.git
- cd tmux
- git checkout 2.5
- sh autogen.sh
- ./configure && make && sudo make install
install:
- git fetch --unshallow --recurse-submodules || git fetch --recurse-submodules
# manual `git clone` required for testing `tmux-test` plugin itself
- git clone https://github.com/tmux-plugins/tmux-test lib/tmux-test; true
- lib/tmux-test/setup
script: ./tests/run_tests_in_isolation

View File

@ -1,6 +1,63 @@
# Changelog
### master
- Remove deprecated "restoring shell history" feature.
### 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
- save and restore tmux pane contents (@laomaiweng)
- update tmux-test to solve issue with recursing git submodules in that project
- set options quietly in `resurrect.tmux` script
- improve pane contents restoration: `cat <file>` is no longer shown in pane
content history
- refactoring: drop dependency on `paste` command
- bugfix for pane contents restoration
- expand tilde char `~` if used with `@resurrect-dir`
- do not save empty trailing lines when pane content is saved
- do not save pane contents if pane is empty (only for 'save pane contents'
feature)
- "save pane contents" feature saves files to a separate directory
- archive and compress pane contents file
- make archive & compress pane contents process more portable
- `mutt` added to the list of automatically restored programs
- added guide for migrating from tmuxinator
- fixed a bug for restoring commands on tmux 2.5 (and probably tmux 2.4)
- do not create another resurrect file if there are no changes (credit @vburdo)
- allow using '$HOSTNAME' in @resurrect-dir
- add zsh history saving and restoring
- delete resurrect files older than 30 days, but keep at least 5 files
- add save and restore hooks
- always use `-ao` flags for `ps` command to detect commands
- Deprecate restoring shell history feature.
- `view` added to the list of automatically restored programs
- Enable vim session strategy to work with custom session files,
e.g. `vim -S Session1.vim`.
- Enable restoring command arguments for inline strategies with `*` character.
- Kill session "0" if it wasn't restored.
- Add `@resurrect-delete-backup-after` option to specify how many days of
backups to keep - default is 30.
### v2.4.0, 2015-02-23
- add "tmux-test"
- add test for "resurrect save" feature
- add test for "resurrect restore" feature
- make the tests work and pass on travis
- add travis badge to the readme
### v2.3.0, 2015-02-12
- Improve fetching proper window_layout for zoomed windows. In order to fetch
proper value, window has to get unzoomed. This is now done faster so that
"unzoom,fetch value,zoom" cycle is almost unnoticable to the user.
### v2.2.0, 2015-02-12
- bugfix: zoomed windows related regression
- export save and restore script paths so that 'tmux-resurrect-save' plugin can
use them
- enable "quiet" saving (used by 'tmux-resurrect-save' plugin)
### v2.1.0, 2015-02-12
- if restore is started when there's only **1 pane in the whole tmux server**,

126
README.md
View File

@ -1,6 +1,8 @@
# Tmux Resurrect
Restore `tmux` environment after a system restart.
[![Build Status](https://travis-ci.org/tmux-plugins/tmux-resurrect.svg?branch=master)](https://travis-ci.org/tmux-plugins/tmux-resurrect)
Restore `tmux` environment after system restart.
Tmux is great, except when you have to restart the computer. You lose all the
running programs, working directories, pane layouts etc.
@ -12,7 +14,11 @@ projects.
can be completely restored after a system restart (or when you feel like it).
No configuration is required. You should feel like you never quit tmux.
It even (optionally) [restores vim and neovim sessions](#restoring-vim-and-neovim-sessions)!
It even (optionally)
[restores vim and neovim sessions](docs/restoring_vim_and_neovim_sessions.md)!
Automatic restoring and continuous saving of tmux env is also possible with
[tmux-continuum](https://github.com/tmux-plugins/tmux-continuum) plugin.
### Screencast
@ -23,11 +29,6 @@ It even (optionally) [restores vim and neovim sessions](#restoring-vim-and-neovi
- `prefix + Ctrl-s` - save
- `prefix + Ctrl-r` - restore
For custom key bindings, add to `.tmux.conf`:
set -g @resurrect-save 'S'
set -g @resurrect-restore 'R'
### About
This plugin goes to great lengths to save and restore all the details from your
@ -42,28 +43,29 @@ This plugin goes to great lengths to save and restore all the details from your
- active pane for each window
- "grouped sessions" (useful feature when using tmux with multiple monitors)
- programs running within a pane! More details in the
[configuration section](#configuration).
- restoring vim/neovim sessions (optional). More details in
[restoring vim and neovim sessions](#restoring-vim-and-neovim-sessions).
- restoring bash history (optional, \*experimental*). More details in
[restoring bash history](#restoring-bash-history-experimental).
[restoring programs doc](docs/restoring_programs.md).
Optional:
- [restoring vim and neovim sessions](docs/restoring_vim_and_neovim_sessions.md)
- [restoring pane contents](docs/restoring_pane_contents.md)
- [restoring a previously saved environment](docs/restoring_previously_saved_environment.md)
Requirements / dependencies: `tmux 1.9` or higher, `bash`.
Tested and working on Linux, OSX and Cygwin.
`tmux-resurrect` is idempotent! It will not try to restore panes or windows that
already exist.<br/>
The single exception to this is when tmux is started with only 1 pane in order
to restore previous tmux env. In this case only will this single pane be
to restore previous tmux env. Only in this case will this single pane be
overwritten.
### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended)
Add plugin to the list of TPM plugins in `.tmux.conf`:
set -g @tpm_plugins ' \
tmux-plugins/tpm \
tmux-plugins/tmux-resurrect \
'
set -g @plugin 'tmux-plugins/tmux-resurrect'
Hit `prefix + I` to fetch the plugin and source it. You should now be able to
use the plugin.
@ -78,78 +80,29 @@ Add this line to the bottom of `.tmux.conf`:
run-shell ~/clone/path/resurrect.tmux
Reload TMUX environment:
# type this in terminal
$ tmux source-file ~/.tmux.conf
Reload TMUX environment with: `$ tmux source-file ~/.tmux.conf`.
You should now be able to use the plugin.
### Configuration
### Docs
Configuration is not required, but it enables extra features.
- [Guide for migrating from tmuxinator](docs/migrating_from_tmuxinator.md)
Only a conservative list of programs is restored by default:<br/>
`vi vim nvim emacs man less more tail top htop irssi`.
**Configuration**
- Restore additional programs with the setting in `.tmux.conf`:
- [Changing the default key bindings](docs/custom_key_bindings.md).
- [Setting up hooks on save & restore](docs/hooks.md).
- Only a conservative list of programs is restored by default:<br/>
`vi vim nvim emacs man less more tail top htop irssi weechat mutt`.<br/>
[Restoring programs doc](docs/restoring_programs.md) explains how to restore
additional programs.
- [Change a directory](docs/save_dir.md) where `tmux-resurrect` saves tmux
environment.
set -g @resurrect-processes 'ssh psql mysql sqlite3'
**Optional features**
- Programs with arguments should be double quoted:
set -g @resurrect-processes 'some_program "git log"'
- Start with tilde to restore a program whose process contains target name:
set -g @resurrect-processes 'irb pry "~rails server" "~rails console"'
- Use `->` to specify a command to be used when restoring a program (useful if
the default restore command fails ):
set -g @resurrect-processes 'some_program "grunt->grunt development"'
- Don't restore any programs:
set -g @resurrect-processes 'false'
- Restore **all** programs (be careful with this!):
set -g @resurrect-processes ':all:'
#### Restoring vim and neovim sessions
- save vim/neovim sessions. I recommend
[tpope/vim-obsession](https://github.com/tpope/vim-obsession) (as almost every
plugin, it works for both vim and neovim).
- in `.tmux.conf`:
# for vim
set -g @resurrect-strategy-vim 'session'
# for neovim
set -g @resurrect-strategy-nvim 'session'
`tmux-resurrect` will now restore vim and neovim sessions if `Sessions.vim` file
is present.
#### Resurrect save dir
By default Tmux environment is saved to a file in `~/.tmux/resurrect` dir.
Change this with:
set -g @resurrect-dir '/some/path'
#### Restoring bash history (experimental)
In `.tmux.conf`:
set -g @resurrect-save-bash-history 'on'
Bash `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 history themselves,
add `HISTCONTROL=ignoreboth` to your `.bashrc` (this is set by default in Ubuntu).
- [Restoring vim and neovim sessions](docs/restoring_vim_and_neovim_sessions.md)
is nice if you're a vim/neovim user.
- [Restoring pane contents](docs/restoring_pane_contents.md) feature.
### Other goodies
@ -159,6 +112,8 @@ add `HISTCONTROL=ignoreboth` to your `.bashrc` (this is set by default in Ubuntu
highlighted text to system clipboard
- [tmux-open](https://github.com/tmux-plugins/tmux-open) - a plugin for quickly
opening highlighted file or a url
- [tmux-continuum](https://github.com/tmux-plugins/tmux-continuum) - automatic
restoring and continuous saving of tmux env
### Reporting bugs and contributing
@ -170,12 +125,5 @@ Both contributing and bug reports are welcome. Please check out
[Mislav Marohnić](https://github.com/mislav) - the idea for the plugin came from his
[tmux-session script](https://github.com/mislav/dotfiles/blob/2036b5e03fb430bbcbc340689d63328abaa28876/bin/tmux-session).
### Other
Here's another script that tries to solve the same problem:
[link](http://brainscraps.wikia.com/wiki/Resurrecting_tmux_Sessions_After_Reboot).
It even has the same name, even though I discovered it only after publishing
`v1.0` of this plugin.
### License
[MIT](LICENSE.md)

View File

@ -0,0 +1,11 @@
# Custom key bindings
The default key bindings are:
- `prefix + Ctrl-s` - save
- `prefix + Ctrl-r` - restore
To change these, add to `.tmux.conf`:
set -g @resurrect-save 'S'
set -g @resurrect-restore 'R'

33
docs/hooks.md Normal file
View File

@ -0,0 +1,33 @@
# Save & Restore Hooks
Hooks allow to set custom commands that will be executed during session save
and restore. Most hooks are called with zero arguments, unless explicitly
stated otherwise.
Currently the following hooks are supported:
- `@resurrect-hook-post-save-layout`
Called after all sessions, panes and windows have been saved.
Passed single argument of the state file.
- `@resurrect-hook-post-save-all`
Called at end of save process right before the spinner is turned off.
- `@resurrect-hook-pre-restore-all`
Called before any tmux state is altered.
- `@resurrect-hook-pre-restore-pane-processes`
Called before running processes are restored.
### Examples
Here is an example how to save and restore window geometry for most terminals in X11.
Add this to `.tmux.conf`:
set -g @resurrect-hook-post-save-all 'eval $(xdotool getwindowgeometry --shell $WINDOWID); echo 0,$X,$Y,$WIDTH,$HEIGHT > $HOME/.tmux/resurrect/geometry'
set -g @resurrect-hook-pre-restore-all 'wmctrl -i -r $WINDOWID -e $(cat $HOME/.tmux/resurrect/geometry)'

View File

@ -0,0 +1,72 @@
# Migrating from `tmuxinator`
### Why migrate to `tmux-resurrect`?
Here are some reasons why you'd want to migrate from `tmuxinator` to
`tmux-resurrect`:
- **Less dependencies**<br/>
`tmuxinator` depends on `ruby` which can be a hassle to set up if you're not a
rubyist.<br/>
`tmux-resurrect` depends just on `bash` which is virtually
omnipresent.
- **Simplicity**<br/>
`tmuxinator` has an executable, CLI interface with half dozen commands and
command completion.<br/>
`tmux-resurrect` defines just 2 tmux key bindings.
- **No configuration**<br/>
`tmuxinator` is all about config files (and their constant updating).<br/>
`tmux-resurrect` requires no configuration to work.
- **Better change handling**<br/>
When you make a change to any aspect of tmux layout, you also have to
update related `tmuxinator` project file (and test to make sure change is
ok).<br/>
With `tmux-resurrect` there's nothing to do: your change will be
remembered on the next save.
### How to migrate?
1. Install `tmux-resurrect`.
2. Open \*all* existing `tmuxinator` projects.<br/>
Verify all projects are open by pressing `prefix + s` and checking they are
all on the list.
3. Perform a `tmux-resurrect` save.
That's it! You can continue using just `tmux-resurrect` should you choose so.
Note: it probably makes no sense to use both tools at the same time as they do
the same thing (creating tmux environment for you to work in).
Technically however, there should be no issues.
### Usage differences
`tmuxinator` focuses on managing individual tmux sessions (projects).
`tmux-resurrect` keeps track of the \*whole* tmux environment: all sessions are
saved and restored together.
A couple tips if you decide to switch to `tmux-resurrect`:
- Keep all tmux sessions (projects) running all the time.<br/>
If you want to work on an existing project, you should be able to just
\*switch* to an already open session using `prefix + s`.<br/>
This is different from `tmuxinator` where you'd usually run `mux new [project]`
in order to start working on something.
- No need to kill sessions with `tmux kill-session` (unless you really don't
want to work on it ever).<br/>
It's the recurring theme by now: just keep all the sessions running all the
time. This is convenient and also cheap in terms of resources.
- The only 2 situations when you need `tmux-resurrect`:<br/>
1) Save tmux environment just before restarting/shutting down your
computer.<br/>
2) Restore tmux env after you turn the computer on.
### Other questions?
Still have questions? Feel free to open an
[issue](ihttps://github.com/tmux-plugins/tmux-resurrect/issues). We'll try to
answer it and also update this doc.

View File

@ -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"
```

View File

@ -0,0 +1,31 @@
# Restoring pane contents
This plugin enables saving and restoring tmux pane contents.
This feature can be enabled by adding this line to `.tmux.conf`:
set -g @resurrect-capture-pane-contents 'on'
##### Known issue
When using this feature, please check the value of `default-command`
tmux option. That can be done with `$ tmux show -g default-command`.
The value should NOT contain `&&` or `||` operators. If it does, simplify the
option so those operators are removed.
Example:
- this will cause issues (notice the `&&` and `||` operators):
set -g default-command "which reattach-to-user-namespace > /dev/null && reattach-to-user-namespace -l $SHELL || $SHELL -l"
- this is ok:
set -g default-command "reattach-to-user-namespace -l $SHELL"
Related [bug](https://github.com/tmux-plugins/tmux-resurrect/issues/98).
Alternatively, you can let
[tmux-sensible](https://github.com/tmux-plugins/tmux-sensible)
handle this option in a cross-platform way and you'll have no problems.

View File

@ -0,0 +1,14 @@
# Restoring previously saved environment
None of the previous saves are deleted (unless you explicitly do that). All save
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:
- make sure you start this with a "fresh" tmux instance
- `$ cd ~/.tmux/resurrect/`
- locate the save file you'd like to use for restore (file names have a timestamp)
- symlink the `last` file to the desired save file: `$ ln -sf <file_name> last`
- do a restore with `tmux-resurrect` key: `prefix + Ctrl-r`
You should now be restored to the time when `<file_name>` save happened.

205
docs/restoring_programs.md Normal file
View File

@ -0,0 +1,205 @@
# Restoring programs
- [General instructions](#general-instructions)
- [Clarifications](#clarifications)
- [Working with NodeJS](#nodejs)
- [Restoring Mosh](#mosh)
### General instructions <a name="general-instructions"></a>
Only a conservative list of programs is restored by default:<br/>
`vi vim nvim emacs man less more tail top htop irssi weechat mutt`.
This can be configured with `@resurrect-processes` option in `.tmux.conf`. It
contains space-separated list of additional programs to restore.
- Example restoring additional programs:
set -g @resurrect-processes 'ssh psql mysql sqlite3'
- Programs with arguments should be double quoted:
set -g @resurrect-processes 'some_program "git log"'
- Start with tilde to restore a program whose process contains target name:
set -g @resurrect-processes 'irb pry "~rails server" "~rails console"'
- Use `->` to specify a command to be used when restoring a program (useful if
the default restore command fails ):
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:
set -g @resurrect-processes 'false'
- Restore **all** programs (dangerous!):
set -g @resurrect-processes ':all:'
Be *very careful* with this: tmux-resurrect can not know which programs take
which context, and a `sudo mkfs.vfat /dev/sdb` that was just formatting an
external USB stick could wipe your backup hard disk if that's what's attached
after rebooting.
This option is primarily useful for experimentation (e.g., to find out which
program is recognized in a pane).
### Clarifications <a name="clarfications"></a>
> I don't understand tilde `~`, what is it and why is it used when restoring
programs?
Let's say you use `rails server` command often. You want `tmux-resurrect` to
save and restore it automatically. You might try adding `rails server` to the
list of programs that will be restored:
set -g @resurrect-processes '"rails server"' # will NOT work
Upon save, `rails server` command will actually be saved as this command:
`/Users/user/.rbenv/versions/2.0.0-p481/bin/ruby script/rails server`
(if you wanna see how is any command saved, check it yourself in
`~/.tmux/resurrect/last` file).
When programs are restored, the `rails server` command will NOT be restored
because it does not **strictly** match the long
`/Users/user/.rbenv/versions/2.0.0-p481/bin/ruby script/rails server` string.
The tilde `~` at the start of the string relaxes process name matching.
set -g @resurrect-processes '"~rails server"' # OK
The above option says: "restore full process if `rails server` string is found
ANYWHERE in the process name".
If you check long process string, there is in fact a `rails server` string at
the end, so now the process will be successfully restored.
> What is arrow `->` and why is is used?
(Please read the above clarification about tilde `~`).
Continuing with our `rails server` example, when the process is finally restored
correctly it might not look pretty as you'll see the whole
`/Users/user/.rbenv/versions/2.0.0-p481/bin/ruby script/rails server` string in
the command line.
Naturally, you'd rather want to see just `rails server` (what you initially
typed), but that information is now unfortunately lost.
To aid this, you can use arrow `->`: (**note**: there is no space before and after `->`)
set -g @resurrect-processes '"~rails server->rails server"' # OK
This option says: "when this process is restored use `rails server` as the
command name".
Full (long) process name is now ignored and you'll see just `rails server` in
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
Here's the general workflow for figuring this out:
- Set up your whole tmux environment manually.<br/>
In our example case, we'd type `rails server` in a pane where we want it to
run.
- Save tmux env (it will get saved to `~/.tmux/resurrect/last`).
- Open `~/.tmux/resurrect/last` file and try to find full process string for
your program.<br/>
Unfortunately this is a little vague but it should be easy. A smart
thing to do for our example is to search for string `rails` in the `last`
file.
- Now that you know the full and the desired process string use tilde `~` and
arrow `->` in `.tmux.conf` to make things work.
### Working with NodeJS <a name="nodejs"></a>
If you are working with NodeJS, you may get some troubles with configuring restoring programs.
Particularly, some programs like `gulp`, `grunt` or `npm` are not saved with parameters so tmux-resurrect cannot restore it. This is actually **not tmux-resurrect's issue** but more likely, those programs' issues. For example if you run `gulp watch` or `npm start` and then try to look at `ps` or `pgrep`, you will only see `gulp` or `npm`.
To deal with these issues, one solution is to use [yarn](https://yarnpkg.com/en/docs/install) which a package manager for NodeJS and an alternative for `npm`. It's nearly identical to `npm` and very easy to use. Therefore you don't have to do any migration, you can simply use it immediately. For example:
- `npm test` is equivalent to `yarn test`,
- `npm run watch:dev` is equivalent to `yarn watch:dev`
- more interestingly, `gulp watch:dev` is equivalent to `yarn gulp watch:dev`
Before continuing, please ensure that you understand the [clarifications](#clarifications) section about `~` and `->`
#### yarn
It's fairly straight forward if you have been using `yarn` already.
set -g @resurrect-processes '"~yarn watch"'
set -g @resurrect-processes '"~yarn watch->yarn watch"'
#### npm
Instead of
set -g @resurrect-processes '"~npm run watch"' # will NOT work
we use
set -g @resurrect-processes '"~yarn watch"' # OK
#### gulp
Instead of
set -g @resurrect-processes '"~gulp test"' # will NOT work
we use
set -g @resurrect-processes '"~yarn gulp test"' # OK
#### nvm
If you use `nvm` in your project, here is how you could config tmux-resurrect:
set -g @resurrect-processes '"~yarn gulp test->nvm use && gulp test"'
#### Another problem
Let take a look at this example
set -g @resurrect-processes '\
"~yarn gulp test->gulp test" \
"~yarn gulp test-it->gulp test-it" \
'
**This will not work properly**, only `gulp test` is run, although you can see the command `node /path/to/yarn gulp test-it` is added correctly in `.tmux/resurrect/last` file.
The reason is when restoring program, the **command part after the dash `-` is ignored** so instead of command `gulp test-it`, the command `gulp test` which will be run.
A work around, for this problem until it's fixed, is:
- the config should be like this:
set -g @resurrect-processes '\
"~yarn gulp test->gulp test" \
"~yarn gulp \"test-it\"->gulp test-it" \
- and in `.tmux/resurrect/last`, we should add quote to `test-it` word
... node:node /path/to/yarn gulp "test-it"
### Restoring Mosh <a name="#mosh"></a>
Mosh spawns a `mosh-client` process, so we need to specify that as the process to be resurrected.
set -g @resurrect-processes 'mosh-client'
Additionally a mosh-client strategy is provided to handle extracting the original arguments and re-run Mosh.

View File

@ -0,0 +1,19 @@
# Restoring vim and neovim sessions
- save vim/neovim sessions. I recommend
[tpope/vim-obsession](https://github.com/tpope/vim-obsession) (as almost every
plugin, it works for both vim and neovim).
- in `.tmux.conf`:
# for vim
set -g @resurrect-strategy-vim 'session'
# for neovim
set -g @resurrect-strategy-nvim 'session'
`tmux-resurrect` will now restore vim and neovim sessions if `Session.vim` file
is present.
> If you're using the vim binary provided by MacVim.app then you'll need to set `@resurrect-processes`, for example:
> ```
> set -g @resurrect-processes '~Vim -> vim'
> ```

15
docs/save_dir.md Normal file
View File

@ -0,0 +1,15 @@
# Resurrect save dir
By default Tmux environment is saved to a file in `~/.tmux/resurrect` dir.
Change this with:
set -g @resurrect-dir '/some/path'
Using environment variables or shell interpolation in this option is not
allowed as the string is used literally. So the following won't do what is
expected:
set -g @resurrect-dir '/path/$MY_VAR/$(some_executable)'
Only the following variables and special chars are allowed:
`$HOME`, `$HOSTNAME`, and `~`.

1
lib/tmux-test Submodule

@ -0,0 +1 @@
Subproject commit c38f488f152af6f6fd688ecdcf2728498813a01d

View File

@ -22,12 +22,19 @@ set_restore_bindings() {
}
set_default_strategies() {
tmux set-option -g "${restore_process_strategy_option}irb" "default_strategy"
tmux set-option -gq "${restore_process_strategy_option}irb" "default_strategy"
tmux set-option -gq "${restore_process_strategy_option}mosh-client" "default_strategy"
}
set_script_path_options() {
tmux set-option -gq "$save_path_option" "$CURRENT_DIR/scripts/save.sh"
tmux set-option -gq "$restore_path_option" "$CURRENT_DIR/scripts/restore.sh"
}
main() {
set_save_bindings
set_restore_bindings
set_default_strategies
set_script_path_options
}
main

1
run_tests Symbolic link
View File

@ -0,0 +1 @@
lib/tmux-test/run_tests

View File

@ -0,0 +1,26 @@
#!/usr/bin/env bash
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
PANE_PID="$1"
COMMAND_PID=$(pgrep -P $PANE_PID)
exit_safely_if_empty_ppid() {
if [ -z "$PANE_PID" ]; then
exit 0
fi
}
full_command() {
[[ -z "$COMMAND_PID" ]] && exit 0
# 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() {
exit_safely_if_empty_ppid
full_command
}
main

View File

@ -10,16 +10,8 @@ exit_safely_if_empty_ppid() {
fi
}
ps_command_flags() {
case $(uname -s) in
FreeBSD) echo "-ao" ;;
OpenBSD) echo "-ao" ;;
*) echo "-eo" ;;
esac
}
full_command() {
ps "$(ps_command_flags)" "ppid command" |
ps -ao "ppid,args" |
sed "s/^ *//" |
grep "^${PANE_PID}" |
cut -d' ' -f2-

View File

@ -1,7 +1,15 @@
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"
SUPPORTED_VERSION="1.9"
RESURRECT_FILE_PREFIX="tmux_resurrect"
RESURRECT_FILE_EXTENSION="txt"
_RESURRECT_DIR=""
_RESURRECT_FILE_PATH=""
d=$'\t'
@ -51,11 +59,15 @@ remove_first_char() {
echo "$1" | cut -c2-
}
save_bash_history_option_on() {
local option="$(get_tmux_option "$bash_history_option" "off")"
capture_pane_contents_option_on() {
local option="$(get_tmux_option "$pane_contents_option" "off")"
[ "$option" == "on" ]
}
files_differ() {
! cmp -s "$1" "$2"
}
get_grouped_sessions() {
local grouped_sessions_dump="$1"
export GROUPED_SESSIONS="${d}$(echo "$grouped_sessions_dump" | cut -f2 -d"$d" | tr "\\n" "$d")"
@ -66,22 +78,82 @@ is_session_grouped() {
[[ "$GROUPED_SESSIONS" == *"${d}${session_name}${d}"* ]]
}
# pane content file helpers
pane_contents_create_archive() {
tar cf - -C "$(resurrect_dir)/save/" ./pane_contents/ |
gzip > "$(pane_contents_archive_file)"
}
pane_content_files_restore_from_archive() {
local archive_file="$(pane_contents_archive_file)"
if [ -f "$archive_file" ]; then
mkdir -p "$(pane_contents_dir "restore")"
gzip -d < "$archive_file" |
tar xf - -C "$(resurrect_dir)/restore/"
fi
}
# path helpers
resurrect_dir() {
echo $(get_tmux_option "$resurrect_dir_option" "$default_resurrect_dir")
if [ -z "$_RESURRECT_DIR" ]; then
local path="$(get_tmux_option "$resurrect_dir_option" "$default_resurrect_dir")"
# expands tilde, $HOME and $HOSTNAME if used in @resurrect-dir
echo "$path" | sed "s,\$HOME,$HOME,g; s,\$HOSTNAME,$(hostname),g; s,\~,$HOME,g"
else
echo "$_RESURRECT_DIR"
fi
}
_RESURRECT_DIR="$(resurrect_dir)"
resurrect_file_path() {
local timestamp="$(date +"%Y-%m-%dT%H:%M:%S")"
echo "$(resurrect_dir)/tmux_resurrect_${timestamp}.txt"
if [ -z "$_RESURRECT_FILE_PATH" ]; then
local timestamp="$(date +"%Y%m%dT%H%M%S")"
echo "$(resurrect_dir)/${RESURRECT_FILE_PREFIX}_${timestamp}.${RESURRECT_FILE_EXTENSION}"
else
echo "$_RESURRECT_FILE_PATH"
fi
}
_RESURRECT_FILE_PATH="$(resurrect_file_path)"
last_resurrect_file() {
echo "$(resurrect_dir)/last"
}
resurrect_history_file() {
local pane_id="$1"
echo "$(resurrect_dir)/bash_history-${pane_id}"
pane_contents_dir() {
echo "$(resurrect_dir)/$1/pane_contents/"
}
pane_contents_file() {
local save_or_restore="$1"
local pane_id="$2"
echo "$(pane_contents_dir "$save_or_restore")/pane-${pane_id}"
}
pane_contents_file_exists() {
local pane_id="$1"
[ -f "$(pane_contents_file "restore" "$pane_id")" ]
}
pane_contents_archive_file() {
echo "$(resurrect_dir)/pane_contents.tar.gz"
}
execute_hook() {
local kind="$1"
shift
local args="" hook=""
hook=$(get_tmux_option "$hook_prefix$kind" "")
# If there are any args, pass them to the hook (in a way that preserves/copes
# with spaces and unusual characters.
if [ "$#" -gt 0 ]; then
printf -v args "%q " "$@"
fi
if [ -n "$hook" ]; then
eval "$hook $args"
fi
}

View File

@ -13,6 +13,7 @@ restore_pane_process() {
local window_number="$3"
local pane_index="$4"
local dir="$5"
local command
if _process_should_be_restored "$pane_full_command" "$session_name" "$window_number" "$pane_index"; then
tmux switch-client -t "${session_name}:${window_number}"
tmux select-pane -t "$pane_index"
@ -20,15 +21,21 @@ restore_pane_process() {
local inline_strategy="$(_get_inline_strategy "$pane_full_command")" # might not be defined
if [ -n "$inline_strategy" ]; then
# inline strategy exists
tmux send-keys "$inline_strategy" "C-m"
# check for additional "expansion" of inline strategy, e.g. `vim` to `vim -S`
if _strategy_exists "$inline_strategy"; then
local strategy_file="$(_get_strategy_file "$inline_strategy")"
local inline_strategy="$($strategy_file "$pane_full_command" "$dir")"
fi
command="$inline_strategy"
elif _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"
command="$strategy_command"
else
# just invoke the command
tmux send-keys "$pane_full_command" "C-m"
# just invoke the raw command
command="$pane_full_command"
fi
tmux send-keys -t "${session_name}:${window_number}.${pane_index}" "$command" "C-m"
fi
}
@ -105,6 +112,32 @@ _get_proc_restore_element() {
echo "$1" | sed "s/.*${inline_strategy_token}//"
}
# given full command: 'ruby /Users/john/bin/my_program arg1 arg2'
# and inline strategy: '~bin/my_program->my_program *'
# returns: 'arg1 arg2'
_get_command_arguments() {
local pane_full_command="$1"
local match="$2"
if _proc_starts_with_tildae "$match"; then
match="$(remove_first_char "$match")"
fi
echo "$pane_full_command" | sed "s,^.*${match}[^ ]* *,,"
}
_get_proc_restore_command() {
local pane_full_command="$1"
local proc="$2"
local match="$3"
local restore_element="$(_get_proc_restore_element "$proc")"
if [[ "$restore_element" =~ " ${inline_strategy_arguments_token}" ]]; then
# replaces "%" with command arguments
local command_arguments="$(_get_command_arguments "$pane_full_command" "$match")"
echo "$restore_element" | sed "s,${inline_strategy_arguments_token},${command_arguments},"
else
echo "$restore_element"
fi
}
_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")"
@ -130,7 +163,7 @@ _get_inline_strategy() {
if [[ "$proc" =~ "$inline_strategy_token" ]]; then
match="$(_get_proc_match_element "$proc")"
if _proc_matches_full_command "$pane_full_command" "$match"; then
echo "$(_get_proc_restore_element "$proc")"
echo "$(_get_proc_restore_command "$pane_full_command" "$proc" "$match")"
fi
fi
done

View File

@ -18,6 +18,8 @@ EXISTING_PANES_VAR=""
RESTORING_FROM_SCRATCH="false"
RESTORE_PANE_CONTENTS="false"
is_line_type() {
local line_type="$1"
local line="$2"
@ -66,6 +68,22 @@ is_restoring_from_scratch() {
[ "$RESTORING_FROM_SCRATCH" == "true" ]
}
restore_pane_contents_true() {
RESTORE_PANE_CONTENTS="true"
}
is_restoring_pane_contents() {
[ "$RESTORE_PANE_CONTENTS" == "true" ]
}
restored_session_0_true() {
RESTORED_SESSION_0="true"
}
has_restored_session_0() {
[ "$RESTORED_SESSION_0" == "true" ]
}
window_exists() {
local session_name="$1"
local window_number="$2"
@ -86,20 +104,52 @@ tmux_socket() {
echo $TMUX | cut -d',' -f1
}
# Tmux option stored in a global variable so that we don't have to "ask"
# tmux server each time.
cache_tmux_default_command() {
local default_shell="$(get_tmux_option "default-shell" "")"
local opt=""
if [ "$(basename "$default_shell")" == "bash" ]; then
opt="-l "
fi
export TMUX_DEFAULT_COMMAND="$(get_tmux_option "default-command" "$opt$default_shell")"
}
tmux_default_command() {
echo "$TMUX_DEFAULT_COMMAND"
}
pane_creation_command() {
echo "cat '$(pane_contents_file "restore" "${1}:${2}.${3}")'; exec $(tmux_default_command)"
}
new_window() {
local session_name="$1"
local window_number="$2"
local window_name="$3"
local dir="$4"
tmux new-window -d -t "${session_name}:${window_number}" -n "$window_name" -c "$dir"
local dir="$3"
local pane_index="$4"
local pane_id="${session_name}:${window_number}.${pane_index}"
dir="${dir/#\~/$HOME}"
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")"
tmux new-window -d -t "${session_name}:${window_number}" -c "$dir" "$pane_creation_command"
else
tmux new-window -d -t "${session_name}:${window_number}" -c "$dir"
fi
}
new_session() {
local session_name="$1"
local window_number="$2"
local window_name="$3"
local dir="$4"
TMUX="" tmux -S "$(tmux_socket)" new-session -d -s "$session_name" -n "$window_name" -c "$dir"
local dir="$3"
local pane_index="$4"
local pane_id="${session_name}:${window_number}.${pane_index}"
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")"
TMUX="" tmux -S "$(tmux_socket)" new-session -d -s "$session_name" -c "$dir" "$pane_creation_command"
else
TMUX="" tmux -S "$(tmux_socket)" new-session -d -s "$session_name" -c "$dir"
fi
# change first window number if necessary
local created_window_num="$(first_window_num)"
if [ $created_window_num -ne $window_number ]; then
@ -110,25 +160,33 @@ new_session() {
new_pane() {
local session_name="$1"
local window_number="$2"
local window_name="$3"
local dir="$4"
tmux split-window -t "${session_name}:${window_number}" -c "$dir"
local dir="$3"
local pane_index="$4"
local pane_id="${session_name}:${window_number}.${pane_index}"
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")"
tmux split-window -t "${session_name}:${window_number}" -c "$dir" "$pane_creation_command"
else
tmux split-window -t "${session_name}:${window_number}" -c "$dir"
fi
# 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() {
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")"
window_name="$(remove_first_char "$window_name")"
pane_full_command="$(remove_first_char "$pane_full_command")"
if [ "$session_name" == "0" ]; then
restored_session_0_true
fi
if pane_exists "$session_name" "$window_number" "$pane_index"; then
if is_restoring_from_scratch; then
# overwrite the pane
# 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")"
new_pane "$session_name" "$window_number" "$window_name" "$dir"
new_pane "$session_name" "$window_number" "$dir" "$pane_index"
tmux kill-pane -t "$pane_id"
else
# Pane exists, no need to create it!
@ -136,12 +194,14 @@ restore_pane() {
register_existing_pane "$session_name" "$window_number" "$pane_index"
fi
elif window_exists "$session_name" "$window_number"; then
new_pane "$session_name" "$window_number" "$window_name" "$dir"
new_pane "$session_name" "$window_number" "$dir" "$pane_index"
elif session_exists "$session_name"; then
new_window "$session_name" "$window_number" "$window_name" "$dir"
new_window "$session_name" "$window_number" "$dir" "$pane_index"
else
new_session "$session_name" "$window_number" "$window_name" "$dir"
new_session "$session_name" "$window_number" "$dir" "$pane_index"
fi
# set pane title
tmux select-pane -t "$session_name:$window_number.$pane_index" -T "$pane_title"
done < <(echo "$pane")
}
@ -192,10 +252,21 @@ detect_if_restoring_from_scratch() {
fi
}
detect_if_restoring_pane_contents() {
if capture_pane_contents_option_on; then
cache_tmux_default_command
restore_pane_contents_true
fi
}
# functions called from main (ordered)
restore_all_panes() {
detect_if_restoring_from_scratch
detect_if_restoring_from_scratch # sets a global variable
detect_if_restoring_pane_contents # sets a global variable
if is_restoring_pane_contents; then
pane_content_files_restore_from_archive
fi
while read line; do
if is_line_type "pane" "$line"; then
restore_pane "$line"
@ -203,24 +274,31 @@ restore_all_panes() {
done < $(last_resurrect_file)
}
restore_pane_layout_for_each_window() {
\grep '^window' $(last_resurrect_file) |
while IFS=$d read line_type session_name window_number window_active window_flags window_layout; do
tmux select-layout -t "${session_name}:${window_number}" "$window_layout"
done
handle_session_0() {
if is_restoring_from_scratch && ! has_restored_session_0; then
local current_session="$(tmux display -p "#{client_session}")"
if [ "$current_session" == "0" ]; then
tmux switch-client -n
fi
tmux kill-session -t "0"
fi
}
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
if ! is_pane_registered_as_existing "$session_name" "$window_number" "$pane_index"; then
if [ "$pane_command" = "bash" ]; then
local pane_id="$session_name:$window_number.$pane_index"
# tmux send-keys has -R option that should reset the terminal.
# However, appending 'clear' to the command seems to work more reliably.
local read_command="history -r '$(resurrect_history_file "$pane_id")'; clear"
tmux send-keys -t "$pane_id" "$read_command" C-m
fi
restore_window_properties() {
local window_name
\grep '^window' $(last_resurrect_file) |
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"
# 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
}
@ -228,8 +306,8 @@ restore_shell_history() {
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_resurrect_file) |
while IFS=$d read session_name window_number pane_index dir pane_full_command; do
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
dir="$(remove_first_char "$dir")"
pane_full_command="$(remove_first_char "$pane_full_command")"
restore_pane_process "$pane_full_command" "$session_name" "$window_number" "$pane_index" "$dir"
@ -238,7 +316,7 @@ restore_all_pane_processes() {
}
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
tmux switch-client -t "${session_name}:${window_number}"
tmux select-pane -t "$active_pane"
@ -246,7 +324,7 @@ restore_active_pane_for_each_window() {
}
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
tmux resize-pane -t "${session_name}:${window_number}" -Z
done
@ -262,7 +340,7 @@ restore_grouped_sessions() {
}
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, $5, $3; }' $(last_resurrect_file) |
sort -u |
while IFS=$d read session_name active_window window_number; do
tmux switch-client -t "${session_name}:${window_number}"
@ -277,14 +355,22 @@ restore_active_and_alternate_sessions() {
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() {
if supported_tmux_version_ok && check_saved_session_exists; then
start_spinner "Restoring..." "Tmux restore complete!"
execute_hook "pre-restore-all"
restore_all_panes
restore_pane_layout_for_each_window >/dev/null 2>&1
if save_bash_history_option_on; then
restore_shell_history
fi
handle_session_0
restore_window_properties >/dev/null 2>&1
execute_hook "pre-restore-pane-processes"
restore_all_pane_processes
# below functions restore exact cursor positions
restore_active_pane_for_each_window
@ -292,6 +378,8 @@ main() {
restore_grouped_sessions # also restores active and alt windows for grouped sessions
restore_active_and_alternate_windows
restore_active_and_alternate_sessions
cleanup_restored_pane_contents
execute_hook "post-restore-all"
stop_spinner
display_message "Tmux restore complete!"
fi

View File

@ -10,6 +10,9 @@ source "$CURRENT_DIR/spinner_helpers.sh"
d=$'\t'
delimiter=$'\t'
# if "quiet" script produces no output
SCRIPT_OUTPUT="$1"
grouped_sessions_format() {
local format
format+="#{session_grouped}"
@ -30,14 +33,14 @@ pane_format() {
format+="${delimiter}"
format+="#{window_index}"
format+="${delimiter}"
format+=":#{window_name}"
format+="${delimiter}"
format+="#{window_active}"
format+="${delimiter}"
format+=":#{window_flags}"
format+="${delimiter}"
format+="#{pane_index}"
format+="${delimiter}"
format+="#{pane_title}"
format+="${delimiter}"
format+=":#{pane_current_path}"
format+="${delimiter}"
format+="#{pane_active}"
@ -45,6 +48,8 @@ pane_format() {
format+="#{pane_current_command}"
format+="${delimiter}"
format+="#{pane_pid}"
format+="${delimiter}"
format+="#{history_size}"
echo "$format"
}
@ -56,6 +61,8 @@ window_format() {
format+="${delimiter}"
format+="#{window_index}"
format+="${delimiter}"
format+=":#{window_name}"
format+="${delimiter}"
format+="#{window_active}"
format+="${delimiter}"
format+=":#{window_flags}"
@ -82,6 +89,11 @@ dump_windows_raw(){
tmux list-windows -a -F "$(window_format)"
}
toggle_window_zoom() {
local target="$1"
tmux resize-pane -Z -t "$target"
}
_save_command_strategy_file() {
local save_command_strategy="$(get_tmux_option "$save_command_strategy_option" "$default_save_command_strategy")"
local strategy_file="$CURRENT_DIR/../save_command_strategies/${save_command_strategy}.sh"
@ -100,17 +112,35 @@ pane_full_command() {
$strategy_file "$pane_pid"
}
save_shell_history() {
number_nonempty_lines_on_screen() {
local pane_id="$1"
local pane_command="$2"
local full_command="$3"
if [ "$pane_command" = "bash" ] && [ "$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")'"
# 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" C-e C-u "$write_command" C-m
tmux capture-pane -pJ -t "$pane_id" |
sed '/^$/d' |
wc -l |
sed 's/ //g'
}
# tests if there was any command output in the current pane
pane_has_any_content() {
local pane_id="$1"
local history_size="$(tmux display -p -t "$pane_id" -F "#{history_size}")"
local cursor_y="$(tmux display -p -t "$pane_id" -F "#{cursor_y}")"
# doing "cheap" tests first
[ "$history_size" -gt 0 ] || # history has any content?
[ "$cursor_y" -gt 0 ] || # cursor not in first line?
[ "$(number_nonempty_lines_on_screen "$pane_id")" -gt 1 ]
}
capture_pane_contents() {
local pane_id="$1"
local start_line="-$2"
local pane_contents_area="$3"
if pane_has_any_content "$pane_id"; then
if [ "$pane_contents_area" = "visible" ]; then
start_line="0"
fi
# the printf hack below removes *trailing* empty lines
printf '%s\n' "$(tmux capture-pane -epJ -S "$start_line" -t "$pane_id")" > "$(pane_contents_file "save" "$pane_id")"
fi
}
@ -159,29 +189,28 @@ fetch_and_dump_grouped_sessions(){
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; 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
if is_session_grouped "$session_name"; then
continue
fi
# check if current pane is part of a maximized window and if the pane is active
if [[ "${window_flags}" == *Z* ]] && [[ ${pane_active} == 1 ]]; then
# unmaximize the pane
tmux resize-pane -Z -t "${session_name}:${window_number}"
fi
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}"
dir=$(echo $dir | sed 's/ /\\ /') # escape all spaces in directory path
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
}
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_name window_active window_flags window_layout; 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}"
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
}
@ -189,33 +218,61 @@ dump_state() {
tmux display-message -p "$(state_format)"
}
dump_bash_history() {
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
save_shell_history "$session_name:$window_number.$pane_index" "$pane_command" "$full_command"
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_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"
done
}
remove_old_backups() {
# 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 -a files
files=($(ls -t $(resurrect_dir)/${RESURRECT_FILE_PREFIX}_*.${RESURRECT_FILE_EXTENSION} | tail -n +6))
[[ ${#files[@]} -eq 0 ]] ||
find "${files[@]}" -type f -mtime "+${delete_after}" -exec rm -v "{}" \; > /dev/null
}
save_all() {
local resurrect_file_path="$(resurrect_file_path)"
local last_resurrect_file="$(last_resurrect_file)"
mkdir -p "$(resurrect_dir)"
fetch_and_dump_grouped_sessions > "$resurrect_file_path"
dump_panes >> "$resurrect_file_path"
dump_windows >> "$resurrect_file_path"
dump_state >> "$resurrect_file_path"
ln -fs "$(basename "$resurrect_file_path")" "$(last_resurrect_file)"
if save_bash_history_option_on; then
dump_bash_history
execute_hook "post-save-layout" "$resurrect_file_path"
if files_differ "$resurrect_file_path" "$last_resurrect_file"; then
ln -fs "$(basename "$resurrect_file_path")" "$last_resurrect_file"
else
rm "$resurrect_file_path"
fi
restore_zoomed_windows
if capture_pane_contents_option_on; then
mkdir -p "$(pane_contents_dir "save")"
dump_pane_contents
pane_contents_create_archive
rm "$(pane_contents_dir "save")"/*
fi
remove_old_backups
execute_hook "post-save-all"
}
show_output() {
[ "$SCRIPT_OUTPUT" != "quiet" ]
}
main() {
if supported_tmux_version_ok; then
start_spinner "Saving..." "Tmux environment saved!"
if show_output; then
start_spinner "Saving..." "Tmux environment saved!"
fi
save_all
stop_spinner
display_message "Tmux environment saved!"
if show_output; then
stop_spinner
display_message "Tmux environment saved!"
fi
fi
}
main

View File

@ -1,13 +1,15 @@
# key bindings
default_save_key="C-s"
save_option="@resurrect-save"
save_path_option="@resurrect-save-script-path"
default_restore_key="C-r"
restore_option="@resurrect-restore"
restore_path_option="@resurrect-restore-script-path"
# default processes that are restored
default_proc_list_option="@resurrect-default-processes"
default_proc_list='vi vim nvim emacs man less more tail top htop irssi'
default_proc_list='vi vim view nvim emacs man less more tail top htop irssi weechat mutt'
# User defined processes that are restored
# 'false' - nothing is restored
@ -23,11 +25,24 @@ restore_processes=""
restore_process_strategy_option="@resurrect-strategy-"
inline_strategy_token="->"
inline_strategy_arguments_token="*"
save_command_strategy_option="@resurrect-save-command-strategy"
default_save_command_strategy="ps"
bash_history_option="@resurrect-save-bash-history"
# Pane contents capture options.
# @resurrect-pane-contents-area option can be:
# 'visible' - capture only the visible pane area
# 'full' - capture the full pane contents
pane_contents_option="@resurrect-capture-pane-contents"
pane_contents_area_option="@resurrect-pane-contents-area"
default_pane_contents_area="full"
# set to 'on' to ensure panes are never ever overwritten
overwrite_option="@resurrect-never-overwrite"
# Hooks are set via ${hook_prefix}${name}, i.e. "@resurrect-hook-post-save-all"
hook_prefix="@resurrect-hook-"
delete_backup_after_option="@resurrect-delete-backup-after"
default_delete_backup_after="30" # days

View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
# "mosh-client default strategy"
#
# Example mosh-client process:
# mosh-client -# charm tmux at | 198.199.104.142 60001
#
# When executed, the above will fail. This strategy handles that.
ORIGINAL_COMMAND="$1"
DIRECTORY="$2"
mosh_command() {
local args="$ORIGINAL_COMMAND"
args="${args#*-#}"
args="${args%|*}"
echo "mosh $args"
}
main() {
echo "$(mosh_command)"
}
main

View File

@ -13,18 +13,9 @@ vim_session_file_exists() {
[ -e "${DIRECTORY}/Session.vim" ]
}
original_command_contains_session_flag() {
[[ "$ORIGINAL_COMMAND" =~ "-S" ]]
}
main() {
if vim_session_file_exists; then
echo "vim -S"
elif original_command_contains_session_flag; then
# Session file does not exist, yet the original vim command contains
# session flag `-S`. This will cause an error, so we're falling back to
# starting plain vim.
echo "vim"
else
echo "$ORIGINAL_COMMAND"
fi

21
tests/fixtures/restore_file.txt vendored Normal file
View File

@ -0,0 +1,21 @@
pane 0 0 :bash 1 :* 0 :/tmp 1 bash :
pane blue 0 :vim 0 : 0 :/tmp 1 vim :vim foo.txt
pane blue 1 :man 0 :- 0 :/tmp 0 bash :
pane blue 1 :man 0 :- 1 :/usr/share/man 1 man :man echo
pane blue 2 :bash 1 :* 0 :/tmp 1 bash :
pane red 0 :bash 0 : 0 :/tmp 1 bash :
pane red 1 :bash 0 :-Z 0 :/tmp 0 bash :
pane red 1 :bash 0 :-Z 1 :/tmp 0 bash :
pane red 1 :bash 0 :-Z 2 :/tmp 1 bash :
pane red 2 :bash 1 :* 0 :/tmp 0 bash :
pane red 2 :bash 1 :* 1 :/tmp 1 bash :
pane yellow 0 :bash 1 :* 0 :/tmp/bar 1 bash :
window 0 0 1 :* ce9e,200x49,0,0,1
window blue 0 0 : ce9f,200x49,0,0,2
window blue 1 0 :- 178b,200x49,0,0{100x49,0,0,3,99x49,101,0,4}
window blue 2 1 :* cea2,200x49,0,0,5
window red 0 0 : cea3,200x49,0,0,6
window red 1 0 :-Z 135b,200x49,0,0[200x24,0,0,7,200x24,0,25{100x24,0,25,8,99x24,101,25,9}]
window red 2 1 :* db81,200x49,0,0[200x24,0,0,10,200x24,0,25,11]
window yellow 0 1 :* 6781,200x49,0,0,12
state yellow blue

21
tests/fixtures/save_file.txt vendored Normal file
View File

@ -0,0 +1,21 @@
pane 0 0 :bash 1 :* 0 :/tmp 1 bash :
pane blue 0 :vim 0 :! 0 :/tmp 1 vim :vim foo.txt
pane blue 1 :man 0 :!- 0 :/tmp 0 bash :
pane blue 1 :man 0 :!- 1 :/usr/share/man 1 man :man echo
pane blue 2 :bash 1 :* 0 :/tmp 1 bash :
pane red 0 :bash 0 : 0 :/tmp 1 bash :
pane red 1 :bash 0 :-Z 0 :/tmp 0 bash :
pane red 1 :bash 0 :-Z 1 :/tmp 0 bash :
pane red 1 :bash 0 :-Z 2 :/tmp 1 bash :
pane red 2 :bash 1 :* 0 :/tmp 0 bash :
pane red 2 :bash 1 :* 1 :/tmp 1 bash :
pane yellow 0 :bash 1 :* 0 :/tmp/bar 1 bash :
window 0 0 1 :* ce9d,200x49,0,0,0
window blue 0 0 :! cea4,200x49,0,0,7
window blue 1 0 :!- 9797,200x49,0,0{100x49,0,0,8,99x49,101,0,9}
window blue 2 1 :* 677f,200x49,0,0,10
window red 0 0 : ce9e,200x49,0,0,1
window red 1 0 :-Z 52b7,200x49,0,0[200x24,0,0,2,200x24,0,25{100x24,0,25,3,99x24,101,25,4}]
window red 2 1 :* bd68,200x49,0,0[200x24,0,0,5,200x24,0,25,6]
window yellow 0 1 :* 6780,200x49,0,0,11
state yellow blue

View File

@ -0,0 +1,42 @@
#!/usr/bin/env expect
source "./tests/helpers/expect_helpers.exp"
expect_setup
spawn tmux
# delay with sleep to compensate for tmux starting time
sleep 1
run_shell_command "cd /tmp"
# session red
new_tmux_session "red"
new_tmux_window
horizontal_split
vertical_split
toggle_zoom_pane
new_tmux_window
horizontal_split
# session blue
new_tmux_session "blue"
run_shell_command "touch foo.txt"
run_shell_command "vim foo.txt"
new_tmux_window
vertical_split
run_shell_command "man echo"
new_tmux_window
# session yellow
new_tmux_session "yellow"
run_shell_command "cd /tmp/bar"
start_resurrect_save
run_shell_command "tmux kill-server"

View File

@ -0,0 +1,70 @@
# a set of expect helpers
# basic setup for each script
proc expect_setup {} {
# disables script output
log_user 0
# standard timeout
set timeout 5
}
proc new_tmux_window {} {
send "c"
send "cd /tmp\r"
sleep 0.2
}
proc rename_current_session {name} {
send "$"
# delete existing name with ctrl-u
send ""
send "$name\r"
sleep 0.2
}
proc new_tmux_session {name} {
send "TMUX='' tmux new -d -s $name\r"
sleep 1
send "tmux switch-client -t $name\r"
send "cd /tmp\r"
sleep 0.5
}
proc horizontal_split {} {
send "\""
sleep 0.2
send "cd /tmp\r"
sleep 0.1
}
proc vertical_split {} {
send "%"
sleep 0.2
send "cd /tmp\r"
sleep 0.1
}
proc toggle_zoom_pane {} {
send "z"
sleep 0.2
}
proc run_shell_command {command} {
send "$command\r"
sleep 1
}
proc start_resurrect_save {} {
send ""
sleep 5
}
proc start_resurrect_restore {} {
send ""
sleep 10
}
proc clear_screen_for_window {target} {
send "tmux send-keys -t $target C-l\r"
sleep 0.2
}

1
tests/helpers/helpers.sh Symbolic link
View File

@ -0,0 +1 @@
../../lib/tmux-test/tests/helpers/helpers.sh

View File

@ -0,0 +1,18 @@
#!/usr/bin/env expect
source "./tests/helpers/expect_helpers.exp"
expect_setup
spawn tmux
# delay with sleep to compensate for tmux starting time
sleep 1
start_resurrect_restore
# delete all existing resurrect save files
run_shell_command "rm ~/.tmux/resurrect/*"
start_resurrect_save
run_shell_command "tmux kill-server"

View File

@ -0,0 +1,11 @@
# we want "fixed" dimensions no matter the size of real display
set_screen_dimensions_helper() {
stty cols 200
stty rows 50
}
last_save_file_differs_helper() {
local original_file="$1"
diff "$original_file" "${HOME}/.tmux/resurrect/last"
[ $? -ne 0 ]
}

View File

@ -0,0 +1 @@
../lib/tmux-test/tests/run_tests_in_isolation

33
tests/test_resurrect_restore.sh Executable file
View File

@ -0,0 +1,33 @@
#!/usr/bin/env bash
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source $CURRENT_DIR/helpers/helpers.sh
source $CURRENT_DIR/helpers/resurrect_helpers.sh
setup_before_restore() {
# setup restore file
mkdir -p ~/.tmux/resurrect/
cp tests/fixtures/restore_file.txt "${HOME}/.tmux/resurrect/restore_file.txt"
ln -sf restore_file.txt "${HOME}/.tmux/resurrect/last"
# directory used in restored tmux session
mkdir -p /tmp/bar
}
restore_tmux_environment_and_save_again() {
set_screen_dimensions_helper
$CURRENT_DIR/helpers/restore_and_save_tmux_test_environment.exp
}
main() {
install_tmux_plugin_under_test_helper
setup_before_restore
restore_tmux_environment_and_save_again
if last_save_file_differs_helper "tests/fixtures/restore_file.txt"; then
fail_helper "Saved file not correct after restore"
fi
exit_helper
}
main

23
tests/test_resurrect_save.sh Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source $CURRENT_DIR/helpers/helpers.sh
source $CURRENT_DIR/helpers/resurrect_helpers.sh
create_tmux_test_environment_and_save() {
set_screen_dimensions_helper
$CURRENT_DIR/helpers/create_and_save_tmux_test_environment.exp
}
main() {
install_tmux_plugin_under_test_helper
mkdir -p /tmp/bar # setup required dirs
create_tmux_test_environment_and_save
if last_save_file_differs_helper "tests/fixtures/save_file.txt"; then
fail_helper "Saved file not correct (initial save)"
fi
exit_helper
}
main