[
  {
    "path": ".gitattributes",
    "content": "# Force text files to have unix eols, so Windows/Cygwin does not break them\n*.* eol=lf\n\n# Except for images because then on checkout the files have been altered.\n*.png binary\n"
  },
  {
    "path": ".gitignore",
    "content": "run_tests\ntests/run_tests_in_isolation\ntests/helpers/helpers.sh\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"lib/tmux-test\"]\n\tpath = lib/tmux-test\n\turl = https://github.com/tmux-plugins/tmux-test.git\n"
  },
  {
    "path": ".travis.yml",
    "content": "# generic packages and tmux\nbefore_install:\n  - sudo apt-get update\n  - sudo apt-get install -y git-core expect\n  - sudo apt-get install -y python-software-properties software-properties-common\n  - sudo apt-get install -y libevent-dev libncurses-dev\n  - git clone https://github.com/tmux/tmux.git\n  - cd tmux\n  - git checkout 2.5\n  - sh autogen.sh\n  - ./configure && make && sudo make install\n\ninstall:\n  - git fetch --unshallow --recurse-submodules || git fetch --recurse-submodules\n  # manual `git clone` required for testing `tmux-test` plugin itself\n  - git clone https://github.com/tmux-plugins/tmux-test lib/tmux-test; true\n  - lib/tmux-test/setup\n\nscript: ./tests/run_tests_in_isolation\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n### master\n- Remove deprecated \"restoring shell history\" feature.\n\n### v4.0.0, 2022-04-10\n- Proper handling of `automatic-rename` window option.\n- save and restore tmux pane title (breaking change: you have to re-save to be\n  able to properly restore!)\n\n### v3.0.0, 2021-08-30\n- save and restore tmux pane contents (@laomaiweng)\n- update tmux-test to solve issue with recursing git submodules in that project\n- set options quietly in `resurrect.tmux` script\n- improve pane contents restoration: `cat <file>` is no longer shown in pane\n  content history\n- refactoring: drop dependency on `paste` command\n- bugfix for pane contents restoration\n- expand tilde char `~` if used with `@resurrect-dir`\n- do not save empty trailing lines when pane content is saved\n- do not save pane contents if pane is empty (only for 'save pane contents'\n  feature)\n- \"save pane contents\" feature saves files to a separate directory\n- archive and compress pane contents file\n- make archive & compress pane contents process more portable\n- `mutt` added to the list of automatically restored programs\n- added guide for migrating from tmuxinator\n- fixed a bug for restoring commands on tmux 2.5 (and probably tmux 2.4)\n- do not create another resurrect file if there are no changes (credit @vburdo)\n- allow using '$HOSTNAME' in @resurrect-dir\n- add zsh history saving and restoring\n- delete resurrect files older than 30 days, but keep at least 5 files\n- add save and restore hooks\n- always use `-ao` flags for `ps` command to detect commands\n- Deprecate restoring shell history feature.\n- `view` added to the list of automatically restored programs\n- Enable vim session strategy to work with custom session files,\n  e.g. `vim -S Session1.vim`.\n- Enable restoring command arguments for inline strategies with `*` character.\n- Kill session \"0\" if it wasn't restored.\n- Add `@resurrect-delete-backup-after` option to specify how many days of\n  backups to keep - default is 30.\n\n### v2.4.0, 2015-02-23\n- add \"tmux-test\"\n- add test for \"resurrect save\" feature\n- add test for \"resurrect restore\" feature\n- make the tests work and pass on travis\n- add travis badge to the readme\n\n### v2.3.0, 2015-02-12\n- Improve fetching proper window_layout for zoomed windows. In order to fetch\n  proper value, window has to get unzoomed. This is now done faster so that\n  \"unzoom,fetch value,zoom\" cycle is almost unnoticable to the user.\n\n### v2.2.0, 2015-02-12\n- bugfix: zoomed windows related regression\n- export save and restore script paths so that 'tmux-resurrect-save' plugin can\n  use them\n- enable \"quiet\" saving (used by 'tmux-resurrect-save' plugin)\n\n### v2.1.0, 2015-02-12\n- if restore is started when there's only **1 pane in the whole tmux server**,\n  assume the users wants the \"full restore\" and overrwrite that pane.\n\n### v2.0.0, 2015-02-10\n- add link to the wiki page for \"first pane/window issue\" to the README as well\n  as other tweaks\n- save and restore grouped sessions (used with multi-monitor workflow)\n- save and restore active and alternate windows in grouped sessions\n- if there are no grouped sessions, do not output empty line to \"last\" file\n- restore active and alternate windows only if they are present in the \"last\" file\n- refactoring: prefer using variable with tab character\n- remove deprecated `M-s` and `M-r` key bindings (breaking change)\n\n### v1.5.0, 2014-11-09\n- add support for restoring neovim sessions\n\n### v1.4.0, 2014-10-25\n- plugin now uses strategies when fetching pane full command. Implemented\n  'default' strategy.\n- save command strategy: 'pgrep'. It's here only if fallback is needed.\n- save command strategy: 'gdb'\n- rename default strategy name to 'ps'\n- create `expect` script that can fully restore tmux environment\n- fix default save command strategy `ps` command flags. Flags are different for\n  FreeBSD.\n- add bash history saving and restoring (@rburny)\n- preserving layout of zoomed windows across restores (@Azrael3000)\n\n### v1.3.0, 2014-09-20\n- remove dependency on `pgrep` command. Use `ps` for fetching process names.\n\n### v1.2.1, 2014-09-02\n- tweak 'new_pane' creation strategy to fix #36\n- when running multiple tmux server and for a large number of panes (120 +) when\n  doing a restore, some panes might not be created. When that is the case also\n  don't restore programs for those panes.\n\n### v1.2.0, 2014-09-01\n- new feature: inline strategies when restoring a program\n\n### v1.1.0, 2014-08-31\n- bugfix: sourcing `variables.sh` file in save script\n- add `Ctrl` key mappings, deprecate `Alt` keys mappings.\n\n### v1.0.0, 2014-08-30\n- show spinner during the save process\n- add screencast script\n- make default program running list even more conservative\n\n### v0.4.0, 2014-08-29\n- change plugin name to `tmux-resurrect`. Change all the variable names.\n\n### v0.3.0, 2014-08-29\n- bugfix: when top is running the pane `$PWD` can't be saved. This was causing\n  issues during the restore and is now fixed.\n- restoring sessions multiple times messes up the whole environment - new panes\n  are all around. This is now fixed - pane restorations are now idempotent.\n- if pane exists from before session restore - do not restore the process within\n  it. This makes the restoration process even more idempotent.\n- more panes within a window can now be restored\n- restore window zoom state\n\n### v0.2.0, 2014-08-29\n- bugfix: with vim 'session' strategy, if the session file does not exist - make\n  sure vim does not contain `-S` flag\n- enable restoring programs with arguments (e.g. \"rails console\") and also\n  processes that contain program name\n- improve `irb` restore strategy\n\n### v0.1.0, 2014-08-28\n- refactor checking if saved tmux session exists\n- spinner while tmux sessions are restored\n\n### v0.0.5, 2014-08-28\n- restore pane processes\n- user option for disabling pane process restoring\n- enable whitelisting processes that will be restored\n- expand readme with configuration options\n- enable command strategies; enable restoring vim sessions\n- update readme: explain restoring vim sessions\n\n### v0.0.4, 2014-08-26\n- restore pane layout for each window\n- bugfix: correct pane ordering in a window\n\n### v0.0.3, 2014-08-26\n- save and restore current and alternate session\n- fix a bug with non-existing window names\n- restore active pane for each window that has multiple panes\n- restore active and alternate window for each session\n\n### v0.0.2, 2014-08-26\n- saving a new session does not remove the previous one\n- make the directory where sessions are stored configurable\n- support only Tmux v1.9 or greater\n- display a nice error message if saved session file does not exist\n- added README\n\n### v0.0.1, 2014-08-26\n- started a project\n- basic saving and restoring works\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "### Contributing\n\nCode contributions are welcome!\n\n### Reporting a bug\n\nIf you find a bug please report it in the issues. When reporting a bug please\nattach:\n- a file symlinked to `~/.tmux/resurrect/last`.\n- your `.tmux.conf`\n- if you're getting an error paste it to a [gist](https://gist.github.com/) and\n  link it in the issue\n"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright (C) 2014 Bruno Sutic\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\nOR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Tmux Resurrect\n\n[![Build Status](https://travis-ci.org/tmux-plugins/tmux-resurrect.svg?branch=master)](https://travis-ci.org/tmux-plugins/tmux-resurrect)\n\nRestore `tmux` environment after system restart.\n\nTmux is great, except when you have to restart the computer. You lose all the\nrunning programs, working directories, pane layouts etc.\nThere are helpful management tools out there, but they require initial\nconfiguration and continuous updates as your workflow evolves or you start new\nprojects.\n\n`tmux-resurrect` saves all the little details from your tmux environment so it\ncan be completely restored after a system restart (or when you feel like it).\nNo configuration is required. You should feel like you never quit tmux.\n\nIt even (optionally)\n[restores vim and neovim sessions](docs/restoring_vim_and_neovim_sessions.md)!\n\nAutomatic restoring and continuous saving of tmux env is also possible with\n[tmux-continuum](https://github.com/tmux-plugins/tmux-continuum) plugin.\n\n### Screencast\n\n[![screencast screenshot](/video/screencast_img.png)](https://vimeo.com/104763018)\n\n### Key bindings\n\n- `prefix + Ctrl-s` - save\n- `prefix + Ctrl-r` - restore\n\n### About\n\nThis plugin goes to great lengths to save and restore all the details from your\n`tmux` environment. Here's what's been taken care of:\n\n- all sessions, windows, panes and their order\n- current working directory for each pane\n- **exact pane layouts** within windows (even when zoomed)\n- active and alternative session\n- active and alternative window for each session\n- windows with focus\n- active pane for each window\n- \"grouped sessions\" (useful feature when using tmux with multiple monitors)\n- programs running within a pane! More details in the\n  [restoring programs doc](docs/restoring_programs.md).\n\nOptional:\n\n- [restoring vim and neovim sessions](docs/restoring_vim_and_neovim_sessions.md)\n- [restoring pane contents](docs/restoring_pane_contents.md)\n- [restoring a previously saved environment](docs/restoring_previously_saved_environment.md)\n\nRequirements / dependencies: `tmux 1.9` or higher, `bash`.\n\nTested and working on Linux, OSX and Cygwin.\n\n`tmux-resurrect` is idempotent! It will not try to restore panes or windows that\nalready exist.<br/>\nThe single exception to this is when tmux is started with only 1 pane in order\nto restore previous tmux env. Only in this case will this single pane be\noverwritten.\n\n### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended)\n\nAdd plugin to the list of TPM plugins in `.tmux.conf`:\n\n    set -g @plugin 'tmux-plugins/tmux-resurrect'\n\nHit `prefix + I` to fetch the plugin and source it. You should now be able to\nuse the plugin.\n\n### Manual Installation\n\nClone the repo:\n\n    $ git clone https://github.com/tmux-plugins/tmux-resurrect ~/clone/path\n\nAdd this line to the bottom of `.tmux.conf`:\n\n    run-shell ~/clone/path/resurrect.tmux\n\nReload TMUX environment with: `$ tmux source-file ~/.tmux.conf`.\nYou should now be able to use the plugin.\n\n### Docs\n\n- [Guide for migrating from tmuxinator](docs/migrating_from_tmuxinator.md)\n\n**Configuration**\n\n- [Changing the default key bindings](docs/custom_key_bindings.md).\n- [Setting up hooks on save & restore](docs/hooks.md).\n- Only a conservative list of programs is restored by default:<br/>\n  `vi vim nvim emacs man less more tail top htop irssi weechat mutt`.<br/>\n  [Restoring programs doc](docs/restoring_programs.md) explains how to restore\n  additional programs.\n- [Change a directory](docs/save_dir.md) where `tmux-resurrect` saves tmux\n  environment.\n\n**Optional features**\n\n- [Restoring vim and neovim sessions](docs/restoring_vim_and_neovim_sessions.md)\n  is nice if you're a vim/neovim user.\n- [Restoring pane contents](docs/restoring_pane_contents.md) feature.\n\n### Other goodies\n\n- [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin for\n  regex searches in tmux and fast match selection\n- [tmux-yank](https://github.com/tmux-plugins/tmux-yank) - enables copying\n  highlighted text to system clipboard\n- [tmux-open](https://github.com/tmux-plugins/tmux-open) - a plugin for quickly\n  opening highlighted file or a url\n- [tmux-continuum](https://github.com/tmux-plugins/tmux-continuum) - automatic\n  restoring and continuous saving of tmux env\n\n### Reporting bugs and contributing\n\nBoth contributing and bug reports are welcome. Please check out\n[contributing guidelines](CONTRIBUTING.md).\n\n### Credits\n\n[Mislav Marohnić](https://github.com/mislav) - the idea for the plugin came from his\n[tmux-session script](https://github.com/mislav/dotfiles/blob/2036b5e03fb430bbcbc340689d63328abaa28876/bin/tmux-session).\n\n### License\n[MIT](LICENSE.md)\n"
  },
  {
    "path": "docs/custom_key_bindings.md",
    "content": "# Custom key bindings\n\nThe default key bindings are:\n\n- `prefix + Ctrl-s` - save\n- `prefix + Ctrl-r` - restore\n\nTo change these, add to `.tmux.conf`:\n\n    set -g @resurrect-save 'S'\n    set -g @resurrect-restore 'R'\n"
  },
  {
    "path": "docs/hooks.md",
    "content": "# Save & Restore Hooks\n\nHooks allow to set custom commands that will be executed during session save\nand restore. Most hooks are called with zero arguments, unless explicitly\nstated otherwise.\n\nCurrently the following hooks are supported:\n\n- `@resurrect-hook-post-save-layout`\n\n  Called after all sessions, panes and windows have been saved.\n\n  Passed single argument of the state file.\n\n- `@resurrect-hook-post-save-all`\n\n  Called at end of save process right before the spinner is turned off.\n\n- `@resurrect-hook-pre-restore-all`\n\n  Called before any tmux state is altered.\n\n- `@resurrect-hook-pre-restore-pane-processes`\n\n  Called before running processes are restored.\n\n### Examples\n\nHere is an example how to save and restore window geometry for most terminals in X11.\nAdd this to `.tmux.conf`:\n\n    set -g @resurrect-hook-post-save-all 'eval $(xdotool getwindowgeometry --shell $WINDOWID); echo 0,$X,$Y,$WIDTH,$HEIGHT > $HOME/.tmux/resurrect/geometry'\n    set -g @resurrect-hook-pre-restore-all 'wmctrl -i -r $WINDOWID -e $(cat $HOME/.tmux/resurrect/geometry)'\n"
  },
  {
    "path": "docs/migrating_from_tmuxinator.md",
    "content": "# Migrating from `tmuxinator`\n\n### Why migrate to `tmux-resurrect`?\n\nHere are some reasons why you'd want to migrate from `tmuxinator` to\n`tmux-resurrect`:\n\n- **Less dependencies**<br/>\n  `tmuxinator` depends on `ruby` which can be a hassle to set up if you're not a\n  rubyist.<br/>\n  `tmux-resurrect` depends just on `bash` which is virtually\n  omnipresent.\n\n- **Simplicity**<br/>\n  `tmuxinator` has an executable, CLI interface with half dozen commands and\n  command completion.<br/>\n  `tmux-resurrect` defines just 2 tmux key bindings.\n\n- **No configuration**<br/>\n  `tmuxinator` is all about config files (and their constant updating).<br/>\n  `tmux-resurrect` requires no configuration to work.\n\n- **Better change handling**<br/>\n  When you make a change to any aspect of tmux layout, you also have to\n  update related `tmuxinator` project file (and test to make sure change is\n  ok).<br/>\n  With `tmux-resurrect` there's nothing to do: your change will be\n  remembered on the next save.\n\n### How to migrate?\n\n1. Install `tmux-resurrect`.\n2. Open \\*all* existing `tmuxinator` projects.<br/>\n   Verify all projects are open by pressing `prefix + s` and checking they are\n   all on the list.\n3. Perform a `tmux-resurrect` save.\n\nThat's it! You can continue using just `tmux-resurrect` should you choose so.\n\nNote: it probably makes no sense to use both tools at the same time as they do\nthe same thing (creating tmux environment for you to work in).\nTechnically however, there should be no issues.\n\n### Usage differences\n\n`tmuxinator` focuses on managing individual tmux sessions (projects).\n`tmux-resurrect` keeps track of the \\*whole* tmux environment: all sessions are\nsaved and restored together.\n\nA couple tips if you decide to switch to `tmux-resurrect`:\n\n- Keep all tmux sessions (projects) running all the time.<br/>\n  If you want to work on an existing project, you should be able to just\n  \\*switch* to an already open session using `prefix + s`.<br/>\n  This is different from `tmuxinator` where you'd usually run `mux new [project]`\n  in order to start working on something.\n\n- No need to kill sessions with `tmux kill-session` (unless you really don't\n  want to work on it ever).<br/>\n  It's the recurring theme by now: just keep all the sessions running all the\n  time. This is convenient and also cheap in terms of resources.\n\n- The only 2 situations when you need `tmux-resurrect`:<br/>\n  1) Save tmux environment just before restarting/shutting down your\n  computer.<br/>\n  2) Restore tmux env after you turn the computer on.\n\n### Other questions?\n\nStill have questions? Feel free to open an\n[issue](ihttps://github.com/tmux-plugins/tmux-resurrect/issues). We'll try to\nanswer it and also update this doc.\n"
  },
  {
    "path": "docs/restoring_bash_history.md",
    "content": "tmux-ressurect no longer restores shell history for each pane, as of [this PR](https://github.com/tmux-plugins/tmux-resurrect/pull/308).\n\nAs a workaround, you can use the `HISTFILE` environment variable to preserve history for each pane separately, and modify\n`PROMPT_COMMAND` to make sure history gets saved with each new command.\n\nUnfortunately, we haven't found a perfect way of getting a unique identifier for each pane, as the `TMUX_PANE` variable\nseems to occasionally change when resurrecting. As a workaround, the example below sets a unique ID in each pane's `title`.\nThe downside of this implementation is that pane titles must all be unique across sessions/windows, and also must use the `pane_id_prefix`.\n\nAny improvements/suggestions for getting a unique, persistent ID for each pane are welcome!\n\n```bash\npane_id_prefix=\"resurrect_\"\n\n# Create history directory if it doesn't exist\nHISTS_DIR=$HOME/.bash_history.d\nmkdir -p \"${HISTS_DIR}\"\n\nif [ -n \"${TMUX_PANE}\" ]; then\n\n  # Check if we've already set this pane title\n  pane_id=$(tmux display -pt \"${TMUX_PANE:?}\" \"#{pane_title}\")\n  if [[ $pane_id != \"$pane_id_prefix\"* ]]; then\n\n    # if not, set it to a random ID\n    random_id=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16)\n    printf \"\\033]2;$pane_id_prefix$random_id\\033\\\\\"\n    pane_id=$(tmux display -pt \"${TMUX_PANE:?}\" \"#{pane_title}\")\n  fi\n\n  # use the pane's random ID for the HISTFILE\n  export HISTFILE=\"${HISTS_DIR}/bash_history_tmux_${pane_id}\"\nelse\n  export HISTFILE=\"${HISTS_DIR}/bash_history_no_tmux\"\nfi\n\n# Stash the new history each time a command runs.\nexport PROMPT_COMMAND=\"$PROMPT_COMMAND;history -a\"\n```\n"
  },
  {
    "path": "docs/restoring_pane_contents.md",
    "content": "# Restoring pane contents\n\nThis plugin enables saving and restoring tmux pane contents.\n\nThis feature can be enabled by adding this line to `.tmux.conf`:\n\n    set -g @resurrect-capture-pane-contents 'on'\n\n##### Known issue\n\nWhen using this feature, please check the value of `default-command`\ntmux option. That can be done with `$ tmux show -g default-command`.\n\nThe value should NOT contain `&&` or `||` operators. If it does, simplify the\noption so those operators are removed.\n\nExample:\n\n- this will cause issues (notice the `&&` and `||` operators):\n\n        set -g default-command \"which reattach-to-user-namespace > /dev/null && reattach-to-user-namespace -l $SHELL || $SHELL -l\"\n\n- this is ok:\n\n        set -g default-command \"reattach-to-user-namespace -l $SHELL\"\n\nRelated [bug](https://github.com/tmux-plugins/tmux-resurrect/issues/98).\n\nAlternatively, you can let\n[tmux-sensible](https://github.com/tmux-plugins/tmux-sensible)\nhandle this option in a cross-platform way and you'll have no problems.\n"
  },
  {
    "path": "docs/restoring_previously_saved_environment.md",
    "content": "# Restoring previously saved environment\n\nNone of the previous saves are deleted (unless you explicitly do that). All save\nfiles are kept in `~/.tmux/resurrect/` directory, or `~/.local/share/tmux/resurrect`\n(unless `${XDG_DATA_HOME}` says otherwise).<br/>\nHere are the steps to restore to a previous point in time:\n\n- make sure you start this with a \"fresh\" tmux instance\n- `$ cd ~/.tmux/resurrect/`\n- locate the save file you'd like to use for restore (file names have a timestamp)\n- symlink the `last` file to the desired save file: `$ ln -sf <file_name> last`\n- do a restore with `tmux-resurrect` key: `prefix + Ctrl-r`\n\nYou should now be restored to the time when `<file_name>` save happened.\n"
  },
  {
    "path": "docs/restoring_programs.md",
    "content": "# Restoring programs\n  - [General instructions](#general-instructions)\n  - [Clarifications](#clarifications)\n  - [Working with NodeJS](#nodejs)\n  - [Restoring Mosh](#mosh)\n\n### General instructions <a name=\"general-instructions\"></a>\nOnly a conservative list of programs is restored by default:<br/>\n`vi vim nvim emacs man less more tail top htop irssi weechat mutt`.\n\nThis can be configured with `@resurrect-processes` option in `.tmux.conf`. It\ncontains space-separated list of additional programs to restore.\n\n- Example restoring additional programs:\n\n        set -g @resurrect-processes 'ssh psql mysql sqlite3'\n\n- Programs with arguments should be double quoted:\n\n        set -g @resurrect-processes 'some_program \"git log\"'\n\n- Start with tilde to restore a program whose process contains target name:\n\n        set -g @resurrect-processes 'irb pry \"~rails server\" \"~rails console\"'\n\n- Use `->` to specify a command to be used when restoring a program (useful if\n  the default restore command fails ):\n\n        set -g @resurrect-processes 'some_program \"grunt->grunt development\"'\n\n- Use `*` to expand the arguments from the saved command when restoring:\n\n        set -g @resurrect-processes 'some_program \"~rails server->rails server *\"'\n\n- Don't restore any programs:\n\n        set -g @resurrect-processes 'false'\n\n- Restore **all** programs (dangerous!):\n\n        set -g @resurrect-processes ':all:'\n\n  Be *very careful* with this: tmux-resurrect can not know which programs take\n  which context, and a `sudo mkfs.vfat /dev/sdb` that was just formatting an\n  external USB stick could wipe your backup hard disk if that's what's attached\n  after rebooting.\n\n  This option is primarily useful for experimentation (e.g., to find out which\n  program is recognized in a pane).\n\n### Clarifications <a name=\"clarfications\"></a>\n\n> I don't understand tilde `~`, what is it and why is it used when restoring\n  programs?\n\nLet's say you use `rails server` command often. You want `tmux-resurrect` to\nsave and restore it automatically. You might try adding `rails server` to the\nlist of programs that will be restored:\n\n    set -g @resurrect-processes '\"rails server\"'  # will NOT work\n\nUpon save, `rails server` command will actually be saved as this command:\n`/Users/user/.rbenv/versions/2.0.0-p481/bin/ruby script/rails server`\n(if you wanna see how is any command saved, check it yourself in\n`~/.tmux/resurrect/last` file).\n\nWhen programs are restored, the `rails server` command will NOT be restored\nbecause it does not **strictly** match the long\n`/Users/user/.rbenv/versions/2.0.0-p481/bin/ruby script/rails server` string.\n\nThe tilde `~` at the start of the string relaxes process name matching.\n\n    set -g @resurrect-processes '\"~rails server\"'  # OK\n\nThe above option says: \"restore full process if `rails server` string is found\nANYWHERE in the process name\".\n\nIf you check long process string, there is in fact a `rails server` string at\nthe end, so now the process will be successfully restored.\n\n> What is arrow `->` and why is is used?\n\n(Please read the above clarification about tilde `~`).\n\nContinuing with our `rails server` example, when the process is finally restored\ncorrectly it might not look pretty as you'll see the whole\n`/Users/user/.rbenv/versions/2.0.0-p481/bin/ruby script/rails server` string in\nthe command line.\n\nNaturally, you'd rather want to see just `rails server` (what you initially\ntyped), but that information is now unfortunately lost.\n\nTo aid this, you can use arrow `->`: (**note**: there is no space before and after `->`)\n\n    set -g @resurrect-processes '\"~rails server->rails server\"'  # OK\n\nThis option says: \"when this process is restored use `rails server` as the\ncommand name\".\n\nFull (long) process name is now ignored and you'll see just `rails server` in\nthe command line when the program is restored.\n\n> What is asterisk `*` and why is it used?\n\n(Please read the above clarifications about tilde `~` and arrow `->`).\n\nContinuing with the `rails server` example, you might have added flags for e.g.\nverbose logging, but with the above configuration, the flags would be lost.\n\nTo preserve the command arguments when restoring, use the asterisk `*`: (**note**: there **must** be a space before `*`)\n\n    set -g @resurrect-processes '\"~rails server->rails server *\"'\n\nThis option says: \"when this process is restored use `rails server` as the\ncommand name, but preserve its arguments\".\n\n> Now I understand the tilde and the arrow, but things still don't work for me\n\nHere's the general workflow for figuring this out:\n\n- Set up your whole tmux environment manually.<br/>\n  In our example case, we'd type `rails server` in a pane where we want it to\n  run.\n- Save tmux env (it will get saved to `~/.tmux/resurrect/last`).\n- Open `~/.tmux/resurrect/last` file and try to find full process string for\n  your program.<br/>\n  Unfortunately this is a little vague but it should be easy. A smart\n  thing to do for our example is to search for string `rails` in the `last`\n  file.\n- Now that you know the full and the desired process string use tilde `~` and\n  arrow `->` in `.tmux.conf` to make things work.\n\n### Working with NodeJS <a name=\"nodejs\"></a>\nIf you are working with NodeJS, you may get some troubles with configuring restoring programs.\n\nParticularly, 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`.\n\nTo 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:\n- `npm test` is equivalent to `yarn test`,\n- `npm run watch:dev` is equivalent to `yarn watch:dev`\n- more interestingly, `gulp watch:dev` is equivalent to `yarn gulp watch:dev`\n\nBefore continuing, please ensure that you understand the [clarifications](#clarifications) section about `~` and `->`\n\n#### yarn\nIt's fairly straight forward if you have been using `yarn` already.\n\n    set -g @resurrect-processes '\"~yarn watch\"'\n    set -g @resurrect-processes '\"~yarn watch->yarn watch\"'\n\n\n#### npm\nInstead of\n\n    set -g @resurrect-processes '\"~npm run watch\"'  # will NOT work\n\nwe use\n\n    set -g @resurrect-processes '\"~yarn watch\"'     # OK\n\n\n#### gulp\nInstead of\n\n    set -g @resurrect-processes '\"~gulp test\"'      # will NOT work\n\nwe use\n\n    set -g @resurrect-processes '\"~yarn gulp test\"' # OK\n\n\n#### nvm\nIf you use `nvm` in your project, here is how you could config tmux-resurrect:\n\n    set -g @resurrect-processes '\"~yarn gulp test->nvm use && gulp test\"'\n\n#### Another problem\nLet take a look at this example\n\n    set -g @resurrect-processes '\\\n          \"~yarn gulp test->gulp test\" \\\n          \"~yarn gulp test-it->gulp test-it\" \\\n    '\n**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.\n\nThe 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.\n\nA work around, for this problem until it's fixed, is:\n- the config should be like this:\n\n      set -g @resurrect-processes '\\\n          \"~yarn gulp test->gulp test\" \\\n          \"~yarn gulp \\\"test-it\\\"->gulp test-it\" \\\n\n- and in `.tmux/resurrect/last`, we should add quote to `test-it` word\n\n      ... node:node /path/to/yarn gulp \"test-it\"\n\n\n### Restoring Mosh <a name=\"#mosh\"></a>\nMosh spawns a `mosh-client` process, so we need to specify that as the process to be resurrected.\n\n    set -g @resurrect-processes 'mosh-client'\n\nAdditionally a mosh-client strategy is provided to handle extracting the original arguments and re-run Mosh.\n"
  },
  {
    "path": "docs/restoring_vim_and_neovim_sessions.md",
    "content": "# Restoring vim and neovim sessions\n\n- save vim/neovim sessions. I recommend\n  [tpope/vim-obsession](https://github.com/tpope/vim-obsession) (as almost every\n  plugin, it works for both vim and neovim).\n- in `.tmux.conf`:\n\n        # for vim\n        set -g @resurrect-strategy-vim 'session'\n        # for neovim\n        set -g @resurrect-strategy-nvim 'session'\n\n`tmux-resurrect` will now restore vim and neovim sessions if `Session.vim` file\nis present.\n\n> If you're using the vim binary provided by MacVim.app then you'll need to set `@resurrect-processes`, for example:\n> ```\n> set -g @resurrect-processes '~Vim -> vim'\n> ```\n"
  },
  {
    "path": "docs/save_dir.md",
    "content": "# Resurrect save dir\n\nBy default Tmux environment is saved to a file in `~/.tmux/resurrect` dir.\nChange this with:\n\n    set -g @resurrect-dir '/some/path'\n\nUsing environment variables or shell interpolation in this option is not\nallowed as the string is used literally. So the following won't do what is\nexpected:\n\n    set -g @resurrect-dir '/path/$MY_VAR/$(some_executable)'\n\nOnly the following variables and special chars are allowed:\n`$HOME`, `$HOSTNAME`, and `~`.\n"
  },
  {
    "path": "resurrect.tmux",
    "content": "#!/usr/bin/env bash\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\nsource \"$CURRENT_DIR/scripts/variables.sh\"\nsource \"$CURRENT_DIR/scripts/helpers.sh\"\n\nset_save_bindings() {\n\tlocal key_bindings=$(get_tmux_option \"$save_option\" \"$default_save_key\")\n\tlocal key\n\tfor key in $key_bindings; do\n\t\ttmux bind-key \"$key\" run-shell \"$CURRENT_DIR/scripts/save.sh\"\n\tdone\n}\n\nset_restore_bindings() {\n\tlocal key_bindings=$(get_tmux_option \"$restore_option\" \"$default_restore_key\")\n\tlocal key\n\tfor key in $key_bindings; do\n\t\ttmux bind-key \"$key\" run-shell \"$CURRENT_DIR/scripts/restore.sh\"\n\tdone\n}\n\nset_default_strategies() {\n\ttmux set-option -gq \"${restore_process_strategy_option}irb\" \"default_strategy\"\n\ttmux set-option -gq \"${restore_process_strategy_option}mosh-client\" \"default_strategy\"\n}\n\nset_script_path_options() {\n\ttmux set-option -gq \"$save_path_option\" \"$CURRENT_DIR/scripts/save.sh\"\n\ttmux set-option -gq \"$restore_path_option\" \"$CURRENT_DIR/scripts/restore.sh\"\n}\n\nmain() {\n\tset_save_bindings\n\tset_restore_bindings\n\tset_default_strategies\n\tset_script_path_options\n}\nmain\n"
  },
  {
    "path": "save_command_strategies/gdb.sh",
    "content": "#!/usr/bin/env bash\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\nPANE_PID=\"$1\"\n\nexit_safely_if_empty_ppid() {\n\tif [ -z \"$PANE_PID\" ]; then\n\t\texit 0\n\tfi\n}\n\nfull_command() {\n\tgdb -batch --eval \"attach $PANE_PID\" --eval \"call write_history(\\\"/tmp/bash_history-${PANE_PID}.txt\\\")\" --eval 'detach' --eval 'q' >/dev/null 2>&1\n\t\\tail -1 \"/tmp/bash_history-${PANE_PID}.txt\"\n}\n\nmain() {\n\texit_safely_if_empty_ppid\n\tfull_command\n}\nmain\n"
  },
  {
    "path": "save_command_strategies/linux_procfs.sh",
    "content": "#!/usr/bin/env bash\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\nPANE_PID=\"$1\"\nCOMMAND_PID=$(pgrep -P $PANE_PID)\n\nexit_safely_if_empty_ppid() {\n\tif [ -z \"$PANE_PID\" ]; then\n\t\texit 0\n\tfi\n}\n\nfull_command() {\n\t[[ -z \"$COMMAND_PID\" ]] && exit 0\n    # See: https://unix.stackexchange.com/a/567021\n    # Avoid complications with system printf by using bash subshell interpolation.\n    # This will properly escape sequences and null in cmdline.\n    cat /proc/${COMMAND_PID}/cmdline | xargs -0 bash -c 'printf \"%q \" \"$0\" \"$@\"'\n}\n\nmain() {\n\texit_safely_if_empty_ppid\n\tfull_command\n}\nmain\n"
  },
  {
    "path": "save_command_strategies/pgrep.sh",
    "content": "#!/usr/bin/env bash\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\nPANE_PID=\"$1\"\n\nexit_safely_if_empty_ppid() {\n\tif [ -z \"$PANE_PID\" ]; then\n\t\texit 0\n\tfi\n}\n\nfull_command() {\n\t\\pgrep -lf -P \"$PANE_PID\" |\n\t\tcut -d' ' -f2-\n}\n\nmain() {\n\texit_safely_if_empty_ppid\n\tfull_command\n}\nmain\n"
  },
  {
    "path": "save_command_strategies/ps.sh",
    "content": "#!/usr/bin/env bash\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\nPANE_PID=\"$1\"\n\nexit_safely_if_empty_ppid() {\n\tif [ -z \"$PANE_PID\" ]; then\n\t\texit 0\n\tfi\n}\n\nfull_command() {\n\tps -ao \"ppid,args\" |\n\t\tsed \"s/^ *//\" |\n\t\tgrep \"^${PANE_PID}\" |\n\t\tcut -d' ' -f2-\n}\n\nmain() {\n\texit_safely_if_empty_ppid\n\tfull_command\n}\nmain\n"
  },
  {
    "path": "scripts/check_tmux_version.sh",
    "content": "#!/usr/bin/env bash\n\nVERSION=\"$1\"\nUNSUPPORTED_MSG=\"$2\"\n\nget_tmux_option() {\n\tlocal option=$1\n\tlocal default_value=$2\n\tlocal option_value=$(tmux show-option -gqv \"$option\")\n\tif [ -z \"$option_value\" ]; then\n\t\techo \"$default_value\"\n\telse\n\t\techo \"$option_value\"\n\tfi\n}\n\n# Ensures a message is displayed for 5 seconds in tmux prompt.\n# Does not override the 'display-time' tmux option.\ndisplay_message() {\n\tlocal message=\"$1\"\n\n\t# display_duration defaults to 5 seconds, if not passed as an argument\n\tif [ \"$#\" -eq 2 ]; then\n\t\tlocal display_duration=\"$2\"\n\telse\n\t\tlocal display_duration=\"5000\"\n\tfi\n\n\t# saves user-set 'display-time' option\n\tlocal saved_display_time=$(get_tmux_option \"display-time\" \"750\")\n\n\t# sets message display time to 5 seconds\n\ttmux set-option -gq display-time \"$display_duration\"\n\n\t# displays message\n\ttmux display-message \"$message\"\n\n\t# restores original 'display-time' value\n\ttmux set-option -gq display-time \"$saved_display_time\"\n}\n\n# this is used to get \"clean\" integer version number. Examples:\n# `tmux 1.9` => `19`\n# `1.9a`     => `19`\nget_digits_from_string() {\n\tlocal string=\"$1\"\n\tlocal only_digits=\"$(echo \"$string\" | tr -dC '[:digit:]')\"\n\techo \"$only_digits\"\n}\n\ntmux_version_int() {\n\tlocal tmux_version_string=$(tmux -V)\n\techo \"$(get_digits_from_string \"$tmux_version_string\")\"\n}\n\nunsupported_version_message() {\n\tif [ -n \"$UNSUPPORTED_MSG\" ]; then\n\t\techo \"$UNSUPPORTED_MSG\"\n\telse\n\t\techo \"Error, Tmux version unsupported! Please install Tmux version $VERSION or greater!\"\n\tfi\n}\n\nexit_if_unsupported_version() {\n\tlocal current_version=\"$1\"\n\tlocal supported_version=\"$2\"\n\tif [ \"$current_version\" -lt \"$supported_version\" ]; then\n\t\tdisplay_message \"$(unsupported_version_message)\"\n\t\texit 1\n\tfi\n}\n\nmain() {\n\tlocal supported_version_int=\"$(get_digits_from_string \"$VERSION\")\"\n\tlocal current_version_int=\"$(tmux_version_int)\"\n\texit_if_unsupported_version \"$current_version_int\" \"$supported_version_int\"\n}\nmain\n"
  },
  {
    "path": "scripts/helpers.sh",
    "content": "if [ -d \"$HOME/.tmux/resurrect\" ]; then\n        default_resurrect_dir=\"$HOME/.tmux/resurrect\"\nelse\n        default_resurrect_dir=\"${XDG_DATA_HOME:-$HOME/.local/share}\"/tmux/resurrect\nfi\nresurrect_dir_option=\"@resurrect-dir\"\n\nSUPPORTED_VERSION=\"1.9\"\nRESURRECT_FILE_PREFIX=\"tmux_resurrect\"\nRESURRECT_FILE_EXTENSION=\"txt\"\n_RESURRECT_DIR=\"\"\n_RESURRECT_FILE_PATH=\"\"\n\nd=$'\\t'\n\n# helper functions\nget_tmux_option() {\n\tlocal option=\"$1\"\n\tlocal default_value=\"$2\"\n\tlocal option_value=$(tmux show-option -gqv \"$option\")\n\tif [ -z \"$option_value\" ]; then\n\t\techo \"$default_value\"\n\telse\n\t\techo \"$option_value\"\n\tfi\n}\n\n# Ensures a message is displayed for 5 seconds in tmux prompt.\n# Does not override the 'display-time' tmux option.\ndisplay_message() {\n\tlocal message=\"$1\"\n\n\t# display_duration defaults to 5 seconds, if not passed as an argument\n\tif [ \"$#\" -eq 2 ]; then\n\t\tlocal display_duration=\"$2\"\n\telse\n\t\tlocal display_duration=\"5000\"\n\tfi\n\n\t# saves user-set 'display-time' option\n\tlocal saved_display_time=$(get_tmux_option \"display-time\" \"750\")\n\n\t# sets message display time to 5 seconds\n\ttmux set-option -gq display-time \"$display_duration\"\n\n\t# displays message\n\ttmux display-message \"$message\"\n\n\t# restores original 'display-time' value\n\ttmux set-option -gq display-time \"$saved_display_time\"\n}\n\n\nsupported_tmux_version_ok() {\n\t$CURRENT_DIR/check_tmux_version.sh \"$SUPPORTED_VERSION\"\n}\n\nremove_first_char() {\n\techo \"$1\" | cut -c2-\n}\n\ncapture_pane_contents_option_on() {\n\tlocal option=\"$(get_tmux_option \"$pane_contents_option\" \"off\")\"\n\t[ \"$option\" == \"on\" ]\n}\n\nfiles_differ() {\n\t! cmp -s \"$1\" \"$2\"\n}\n\nget_grouped_sessions() {\n\tlocal grouped_sessions_dump=\"$1\"\n\texport GROUPED_SESSIONS=\"${d}$(echo \"$grouped_sessions_dump\" | cut -f2 -d\"$d\" | tr \"\\\\n\" \"$d\")\"\n}\n\nis_session_grouped() {\n\tlocal session_name=\"$1\"\n\t[[ \"$GROUPED_SESSIONS\" == *\"${d}${session_name}${d}\"* ]]\n}\n\n# pane content file helpers\n\npane_contents_create_archive() {\n\ttar cf - -C \"$(resurrect_dir)/save/\" ./pane_contents/ |\n\t\tgzip > \"$(pane_contents_archive_file)\"\n}\n\npane_content_files_restore_from_archive() {\n\tlocal archive_file=\"$(pane_contents_archive_file)\"\n\tif [ -f \"$archive_file\" ]; then\n\t\tmkdir -p \"$(pane_contents_dir \"restore\")\"\n\t\tgzip -d < \"$archive_file\" |\n\t\t\ttar xf - -C \"$(resurrect_dir)/restore/\"\n\tfi\n}\n\n# path helpers\n\nresurrect_dir() {\n\tif [ -z \"$_RESURRECT_DIR\" ]; then\n\t\tlocal path=\"$(get_tmux_option \"$resurrect_dir_option\" \"$default_resurrect_dir\")\"\n\t\t# expands tilde, $HOME and $HOSTNAME if used in @resurrect-dir\n\t\techo \"$path\" | sed \"s,\\$HOME,$HOME,g; s,\\$HOSTNAME,$(hostname),g; s,\\~,$HOME,g\"\n\telse\n\t\techo \"$_RESURRECT_DIR\"\n\tfi\n}\n_RESURRECT_DIR=\"$(resurrect_dir)\"\n\nresurrect_file_path() {\n\tif [ -z \"$_RESURRECT_FILE_PATH\" ]; then\n\t\tlocal timestamp=\"$(date +\"%Y%m%dT%H%M%S\")\"\n\t\techo \"$(resurrect_dir)/${RESURRECT_FILE_PREFIX}_${timestamp}.${RESURRECT_FILE_EXTENSION}\"\n\telse\n\t\techo \"$_RESURRECT_FILE_PATH\"\n\tfi\n}\n_RESURRECT_FILE_PATH=\"$(resurrect_file_path)\"\n\nlast_resurrect_file() {\n\techo \"$(resurrect_dir)/last\"\n}\n\npane_contents_dir() {\n\techo \"$(resurrect_dir)/$1/pane_contents/\"\n}\n\npane_contents_file() {\n\tlocal save_or_restore=\"$1\"\n\tlocal pane_id=\"$2\"\n\techo \"$(pane_contents_dir \"$save_or_restore\")/pane-${pane_id}\"\n}\n\npane_contents_file_exists() {\n\tlocal pane_id=\"$1\"\n\t[ -f \"$(pane_contents_file \"restore\" \"$pane_id\")\" ]\n}\n\npane_contents_archive_file() {\n\techo \"$(resurrect_dir)/pane_contents.tar.gz\"\n}\n\nexecute_hook() {\n\tlocal kind=\"$1\"\n\tshift\n\tlocal args=\"\" hook=\"\"\n\n\thook=$(get_tmux_option \"$hook_prefix$kind\" \"\")\n\n\t# If there are any args, pass them to the hook (in a way that preserves/copes\n\t# with spaces and unusual characters.\n\tif [ \"$#\" -gt 0 ]; then\n\t\tprintf -v args \"%q \" \"$@\"\n\tfi\n\n\tif [ -n \"$hook\" ]; then\n\t\teval \"$hook $args\"\n\tfi\n}\n"
  },
  {
    "path": "scripts/process_restore_helpers.sh",
    "content": "restore_pane_processes_enabled() {\n\tlocal restore_processes=\"$(get_tmux_option \"$restore_processes_option\" \"$restore_processes\")\"\n\tif [ \"$restore_processes\" == \"false\" ]; then\n\t\treturn 1\n\telse\n\t\treturn 0\n\tfi\n}\n\nrestore_pane_process() {\n\tlocal pane_full_command=\"$1\"\n\tlocal session_name=\"$2\"\n\tlocal window_number=\"$3\"\n\tlocal pane_index=\"$4\"\n\tlocal dir=\"$5\"\n\tlocal command\n\tif _process_should_be_restored \"$pane_full_command\" \"$session_name\" \"$window_number\" \"$pane_index\"; then\n\t\ttmux switch-client -t \"${session_name}:${window_number}\"\n\t\ttmux select-pane -t \"$pane_index\"\n\n\t\tlocal inline_strategy=\"$(_get_inline_strategy \"$pane_full_command\")\" # might not be defined\n\t\tif [ -n \"$inline_strategy\" ]; then\n\t\t\t# inline strategy exists\n\t\t\t# check for additional \"expansion\" of inline strategy, e.g. `vim` to `vim -S`\n\t\t\tif _strategy_exists \"$inline_strategy\"; then\n\t\t\t\tlocal strategy_file=\"$(_get_strategy_file \"$inline_strategy\")\"\n\t\t\t\tlocal inline_strategy=\"$($strategy_file \"$pane_full_command\" \"$dir\")\"\n\t\t\tfi\n\t\t\tcommand=\"$inline_strategy\"\n\t\telif _strategy_exists \"$pane_full_command\"; then\n\t\t\tlocal strategy_file=\"$(_get_strategy_file \"$pane_full_command\")\"\n\t\t\tlocal strategy_command=\"$($strategy_file \"$pane_full_command\" \"$dir\")\"\n\t\t\tcommand=\"$strategy_command\"\n\t\telse\n\t\t\t# just invoke the raw command\n\t\t\tcommand=\"$pane_full_command\"\n\t\tfi\n\t\ttmux send-keys -t \"${session_name}:${window_number}.${pane_index}\" \"$command\" \"C-m\"\n\tfi\n}\n\n# private functions below\n\n_process_should_be_restored() {\n\tlocal pane_full_command=\"$1\"\n\tlocal session_name=\"$2\"\n\tlocal window_number=\"$3\"\n\tlocal pane_index=\"$4\"\n\tif is_pane_registered_as_existing \"$session_name\" \"$window_number\" \"$pane_index\"; then\n\t\t# Scenario where pane existed before restoration, so we're not\n\t\t# restoring the proces either.\n\t\treturn 1\n\telif ! pane_exists \"$session_name\" \"$window_number\" \"$pane_index\"; then\n\t\t# pane number limit exceeded, pane does not exist\n\t\treturn 1\n\telif _restore_all_processes; then\n\t\treturn 0\n\telif _process_on_the_restore_list \"$pane_full_command\"; then\n\t\treturn 0\n\telse\n\t\treturn 1\n\tfi\n}\n\n_restore_all_processes() {\n\tlocal restore_processes=\"$(get_tmux_option \"$restore_processes_option\" \"$restore_processes\")\"\n\tif [ \"$restore_processes\" == \":all:\" ]; then\n\t\treturn 0\n\telse\n\t\treturn 1\n\tfi\n}\n\n_process_on_the_restore_list() {\n\tlocal pane_full_command=\"$1\"\n\t# TODO: make this work without eval\n\teval set $(_restore_list)\n\tlocal proc\n\tlocal match\n\tfor proc in \"$@\"; do\n\t\tmatch=\"$(_get_proc_match_element \"$proc\")\"\n\t\tif _proc_matches_full_command \"$pane_full_command\" \"$match\"; then\n\t\t\treturn 0\n\t\tfi\n\tdone\n\treturn 1\n}\n\n_proc_matches_full_command() {\n\tlocal pane_full_command=\"$1\"\n\tlocal match=\"$2\"\n\tif _proc_starts_with_tildae \"$match\"; then\n\t\tmatch=\"$(remove_first_char \"$match\")\"\n\t\t# regex matching the command makes sure `$match` string is somewhere in the command string\n\t\tif [[ \"$pane_full_command\" =~ ($match) ]]; then\n\t\t\treturn 0\n\t\tfi\n\telse\n\t\t# regex matching the command makes sure process is a \"word\"\n\t\tif [[ \"$pane_full_command\" =~ (^${match} ) ]] || [[ \"$pane_full_command\" =~ (^${match}$) ]]; then\n\t\t\treturn 0\n\t\tfi\n\tfi\n\treturn 1\n}\n\n_get_proc_match_element() {\n\techo \"$1\" | sed \"s/${inline_strategy_token}.*//\"\n}\n\n_get_proc_restore_element() {\n\techo \"$1\" | sed \"s/.*${inline_strategy_token}//\"\n}\n\n# given full command: 'ruby /Users/john/bin/my_program arg1 arg2'\n# and inline strategy: '~bin/my_program->my_program *'\n# returns: 'arg1 arg2'\n_get_command_arguments() {\n\tlocal pane_full_command=\"$1\"\n\tlocal match=\"$2\"\n\tif _proc_starts_with_tildae \"$match\"; then\n\t\tmatch=\"$(remove_first_char \"$match\")\"\n\tfi\n\techo \"$pane_full_command\" | sed \"s,^.*${match}[^ ]* *,,\"\n}\n\n_get_proc_restore_command() {\n\tlocal pane_full_command=\"$1\"\n\tlocal proc=\"$2\"\n\tlocal match=\"$3\"\n\tlocal restore_element=\"$(_get_proc_restore_element \"$proc\")\"\n\tif [[ \"$restore_element\" =~ \" ${inline_strategy_arguments_token}\" ]]; then\n\t\t# replaces \"%\" with command arguments\n\t\tlocal command_arguments=\"$(_get_command_arguments \"$pane_full_command\" \"$match\")\"\n\t\techo \"$restore_element\" | sed \"s,${inline_strategy_arguments_token},${command_arguments},\"\n\telse\n\t\techo \"$restore_element\"\n\tfi\n}\n\n_restore_list() {\n\tlocal user_processes=\"$(get_tmux_option \"$restore_processes_option\" \"$restore_processes\")\"\n\tlocal default_processes=\"$(get_tmux_option \"$default_proc_list_option\" \"$default_proc_list\")\"\n\tif [ -z \"$user_processes\" ]; then\n\t\t# user didn't define any processes\n\t\techo \"$default_processes\"\n\telse\n\t\techo \"$default_processes $user_processes\"\n\tfi\n}\n\n_proc_starts_with_tildae() {\n\t[[ \"$1\" =~ (^~) ]]\n}\n\n_get_inline_strategy() {\n\tlocal pane_full_command=\"$1\"\n\t# TODO: make this work without eval\n\teval set $(_restore_list)\n\tlocal proc\n\tlocal match\n\tfor proc in \"$@\"; do\n\t\tif [[ \"$proc\" =~ \"$inline_strategy_token\" ]]; then\n\t\t\tmatch=\"$(_get_proc_match_element \"$proc\")\"\n\t\t\tif _proc_matches_full_command \"$pane_full_command\" \"$match\"; then\n\t\t\t\techo \"$(_get_proc_restore_command \"$pane_full_command\" \"$proc\" \"$match\")\"\n\t\t\tfi\n\t\tfi\n\tdone\n}\n\n_strategy_exists() {\n\tlocal pane_full_command=\"$1\"\n\tlocal strategy=\"$(_get_command_strategy \"$pane_full_command\")\"\n\tif [ -n \"$strategy\" ]; then # strategy set?\n\t\tlocal strategy_file=\"$(_get_strategy_file \"$pane_full_command\")\"\n\t\t[ -e \"$strategy_file\" ] # strategy file exists?\n\telse\n\t\treturn 1\n\tfi\n}\n\n_get_command_strategy() {\n\tlocal pane_full_command=\"$1\"\n\tlocal command=\"$(_just_command \"$pane_full_command\")\"\n\tget_tmux_option \"${restore_process_strategy_option}${command}\" \"\"\n}\n\n_just_command() {\n\techo \"$1\" | cut -d' ' -f1\n}\n\n_get_strategy_file() {\n\tlocal pane_full_command=\"$1\"\n\tlocal strategy=\"$(_get_command_strategy \"$pane_full_command\")\"\n\tlocal command=\"$(_just_command \"$pane_full_command\")\"\n\techo \"$CURRENT_DIR/../strategies/${command}_${strategy}.sh\"\n}\n"
  },
  {
    "path": "scripts/restore.exp",
    "content": "#!/usr/bin/env expect\n\n# start tmux\nspawn tmux -S/tmp/foo\n\n# delay with sleep to compensate for tmux starting time\nsleep 2\n\n# run restore script directly\nsend \"~/.tmux/plugins/tmux-resurrect/scripts/restore.sh\\r\"\n\n# long wait until tmux restore is complete\n# (things get messed up if expect client isn't attached)\nsleep 100\n"
  },
  {
    "path": "scripts/restore.sh",
    "content": "#!/usr/bin/env bash\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\nsource \"$CURRENT_DIR/variables.sh\"\nsource \"$CURRENT_DIR/helpers.sh\"\nsource \"$CURRENT_DIR/process_restore_helpers.sh\"\nsource \"$CURRENT_DIR/spinner_helpers.sh\"\n\n# delimiter\nd=$'\\t'\n\n# Global variable.\n# Used during the restore: if a pane already exists from before, it is\n# saved in the array in this variable. Later, process running in existing pane\n# is also not restored. That makes the restoration process more idempotent.\nEXISTING_PANES_VAR=\"\"\n\nRESTORING_FROM_SCRATCH=\"false\"\n\nRESTORE_PANE_CONTENTS=\"false\"\n\nis_line_type() {\n\tlocal line_type=\"$1\"\n\tlocal line=\"$2\"\n\techo \"$line\" |\n\t\t\\grep -q \"^$line_type\"\n}\n\ncheck_saved_session_exists() {\n\tlocal resurrect_file=\"$(last_resurrect_file)\"\n\tif [ ! -f $resurrect_file ]; then\n\t\tdisplay_message \"Tmux resurrect file not found!\"\n\t\treturn 1\n\tfi\n}\n\npane_exists() {\n\tlocal session_name=\"$1\"\n\tlocal window_number=\"$2\"\n\tlocal pane_index=\"$3\"\n\ttmux list-panes -t \"${session_name}:${window_number}\" -F \"#{pane_index}\" 2>/dev/null |\n\t\t\\grep -q \"^$pane_index$\"\n}\n\nregister_existing_pane() {\n\tlocal session_name=\"$1\"\n\tlocal window_number=\"$2\"\n\tlocal pane_index=\"$3\"\n\tlocal pane_custom_id=\"${session_name}:${window_number}:${pane_index}\"\n\tlocal delimiter=$'\\t'\n\tEXISTING_PANES_VAR=\"${EXISTING_PANES_VAR}${delimiter}${pane_custom_id}\"\n}\n\nis_pane_registered_as_existing() {\n\tlocal session_name=\"$1\"\n\tlocal window_number=\"$2\"\n\tlocal pane_index=\"$3\"\n\tlocal pane_custom_id=\"${session_name}:${window_number}:${pane_index}\"\n\t[[ \"$EXISTING_PANES_VAR\" =~ \"$pane_custom_id\" ]]\n}\n\nrestore_from_scratch_true() {\n\tRESTORING_FROM_SCRATCH=\"true\"\n}\n\nis_restoring_from_scratch() {\n\t[ \"$RESTORING_FROM_SCRATCH\" == \"true\" ]\n}\n\nrestore_pane_contents_true() {\n\tRESTORE_PANE_CONTENTS=\"true\"\n}\n\nis_restoring_pane_contents() {\n\t[ \"$RESTORE_PANE_CONTENTS\" == \"true\" ]\n}\n\nrestored_session_0_true() {\n\tRESTORED_SESSION_0=\"true\"\n}\n\nhas_restored_session_0() {\n\t[ \"$RESTORED_SESSION_0\" == \"true\" ]\n}\n\nwindow_exists() {\n\tlocal session_name=\"$1\"\n\tlocal window_number=\"$2\"\n\ttmux list-windows -t \"$session_name\" -F \"#{window_index}\" 2>/dev/null |\n\t\t\\grep -q \"^$window_number$\"\n}\n\nsession_exists() {\n\tlocal session_name=\"$1\"\n\ttmux has-session -t \"$session_name\" 2>/dev/null\n}\n\nfirst_window_num() {\n\ttmux show -gv base-index\n}\n\ntmux_socket() {\n\techo $TMUX | cut -d',' -f1\n}\n\n# Tmux option stored in a global variable so that we don't have to \"ask\"\n# tmux server each time.\ncache_tmux_default_command() {\n\tlocal default_shell=\"$(get_tmux_option \"default-shell\" \"\")\"\n\tlocal opt=\"\"\n\tif [ \"$(basename \"$default_shell\")\" == \"bash\" ]; then\n\t\topt=\"-l \"\n\tfi\n\texport TMUX_DEFAULT_COMMAND=\"$(get_tmux_option \"default-command\" \"$opt$default_shell\")\"\n}\n\ntmux_default_command() {\n\techo \"$TMUX_DEFAULT_COMMAND\"\n}\n\npane_creation_command() {\n\techo \"cat '$(pane_contents_file \"restore\" \"${1}:${2}.${3}\")'; exec $(tmux_default_command)\"\n}\n\nnew_window() {\n\tlocal session_name=\"$1\"\n\tlocal window_number=\"$2\"\n\tlocal dir=\"$3\"\n\tlocal pane_index=\"$4\"\n\tlocal pane_id=\"${session_name}:${window_number}.${pane_index}\"\n\tdir=\"${dir/#\\~/$HOME}\"\n\tif is_restoring_pane_contents && pane_contents_file_exists \"$pane_id\"; then\n\t\tlocal pane_creation_command=\"$(pane_creation_command \"$session_name\" \"$window_number\" \"$pane_index\")\"\n\t\ttmux new-window -d -t \"${session_name}:${window_number}\" -c \"$dir\" \"$pane_creation_command\"\n\telse\n\t\ttmux new-window -d -t \"${session_name}:${window_number}\" -c \"$dir\"\n\tfi\n}\n\nnew_session() {\n\tlocal session_name=\"$1\"\n\tlocal window_number=\"$2\"\n\tlocal dir=\"$3\"\n\tlocal pane_index=\"$4\"\n\tlocal pane_id=\"${session_name}:${window_number}.${pane_index}\"\n\tif is_restoring_pane_contents && pane_contents_file_exists \"$pane_id\"; then\n\t\tlocal pane_creation_command=\"$(pane_creation_command \"$session_name\" \"$window_number\" \"$pane_index\")\"\n\t\tTMUX=\"\" tmux -S \"$(tmux_socket)\" new-session -d -s \"$session_name\" -c \"$dir\" \"$pane_creation_command\"\n\telse\n\t\tTMUX=\"\" tmux -S \"$(tmux_socket)\" new-session -d -s \"$session_name\" -c \"$dir\"\n\tfi\n\t# change first window number if necessary\n\tlocal created_window_num=\"$(first_window_num)\"\n\tif [ $created_window_num -ne $window_number ]; then\n\t\ttmux move-window -s \"${session_name}:${created_window_num}\" -t \"${session_name}:${window_number}\"\n\tfi\n}\n\nnew_pane() {\n\tlocal session_name=\"$1\"\n\tlocal window_number=\"$2\"\n\tlocal dir=\"$3\"\n\tlocal pane_index=\"$4\"\n\tlocal pane_id=\"${session_name}:${window_number}.${pane_index}\"\n\tif is_restoring_pane_contents && pane_contents_file_exists \"$pane_id\"; then\n\t\tlocal pane_creation_command=\"$(pane_creation_command \"$session_name\" \"$window_number\" \"$pane_index\")\"\n\t\ttmux split-window -t \"${session_name}:${window_number}\" -c \"$dir\" \"$pane_creation_command\"\n\telse\n\t\ttmux split-window -t \"${session_name}:${window_number}\" -c \"$dir\"\n\tfi\n\t# minimize window so more panes can fit\n\ttmux resize-pane -t \"${session_name}:${window_number}\" -U \"999\"\n}\n\nrestore_pane() {\n\tlocal pane=\"$1\"\n\twhile 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\n\t\tdir=\"$(remove_first_char \"$dir\")\"\n\t\tpane_full_command=\"$(remove_first_char \"$pane_full_command\")\"\n\t\tif [ \"$session_name\" == \"0\" ]; then\n\t\t\trestored_session_0_true\n\t\tfi\n\t\tif pane_exists \"$session_name\" \"$window_number\" \"$pane_index\"; then\n\t\t\tif is_restoring_from_scratch; then\n\t\t\t\t# overwrite the pane\n\t\t\t\t# happens only for the first pane if it's the only registered pane for the whole tmux server\n\t\t\t\tlocal pane_id=\"$(tmux display-message -p -F \"#{pane_id}\" -t \"$session_name:$window_number\")\"\n\t\t\t\tnew_pane \"$session_name\" \"$window_number\" \"$dir\" \"$pane_index\"\n\t\t\t\ttmux kill-pane -t \"$pane_id\"\n\t\t\telse\n\t\t\t\t# Pane exists, no need to create it!\n\t\t\t\t# Pane existence is registered. Later, its process also won't be restored.\n\t\t\t\tregister_existing_pane \"$session_name\" \"$window_number\" \"$pane_index\"\n\t\t\tfi\n\t\telif window_exists \"$session_name\" \"$window_number\"; then\n\t\t\tnew_pane \"$session_name\" \"$window_number\" \"$dir\" \"$pane_index\"\n\t\telif session_exists \"$session_name\"; then\n\t\t\tnew_window \"$session_name\" \"$window_number\" \"$dir\" \"$pane_index\"\n\t\telse\n\t\t\tnew_session \"$session_name\" \"$window_number\" \"$dir\" \"$pane_index\"\n\t\tfi\n\t\t# set pane title\n\t\ttmux select-pane -t \"$session_name:$window_number.$pane_index\" -T \"$pane_title\"\n\tdone < <(echo \"$pane\")\n}\n\nrestore_state() {\n\tlocal state=\"$1\"\n\techo \"$state\" |\n\twhile IFS=$d read line_type client_session client_last_session; do\n\t\ttmux switch-client -t \"$client_last_session\"\n\t\ttmux switch-client -t \"$client_session\"\n\tdone\n}\n\nrestore_grouped_session() {\n\tlocal grouped_session=\"$1\"\n\techo \"$grouped_session\" |\n\twhile IFS=$d read line_type grouped_session original_session alternate_window active_window; do\n\t\tTMUX=\"\" tmux -S \"$(tmux_socket)\" new-session -d -s \"$grouped_session\" -t \"$original_session\"\n\tdone\n}\n\nrestore_active_and_alternate_windows_for_grouped_sessions() {\n\tlocal grouped_session=\"$1\"\n\techo \"$grouped_session\" |\n\twhile IFS=$d read line_type grouped_session original_session alternate_window_index active_window_index; do\n\t\talternate_window_index=\"$(remove_first_char \"$alternate_window_index\")\"\n\t\tactive_window_index=\"$(remove_first_char \"$active_window_index\")\"\n\t\tif [ -n \"$alternate_window_index\" ]; then\n\t\t\ttmux switch-client -t \"${grouped_session}:${alternate_window_index}\"\n\t\tfi\n\t\tif [ -n \"$active_window_index\" ]; then\n\t\t\ttmux switch-client -t \"${grouped_session}:${active_window_index}\"\n\t\tfi\n\tdone\n}\n\nnever_ever_overwrite() {\n\tlocal overwrite_option_value=\"$(get_tmux_option \"$overwrite_option\" \"\")\"\n\t[ -n \"$overwrite_option_value\" ]\n}\n\ndetect_if_restoring_from_scratch() {\n\tif never_ever_overwrite; then\n\t\treturn\n\tfi\n\tlocal total_number_of_panes=\"$(tmux list-panes -a | wc -l | sed 's/ //g')\"\n\tif [ \"$total_number_of_panes\" -eq 1 ]; then\n\t\trestore_from_scratch_true\n\tfi\n}\n\ndetect_if_restoring_pane_contents() {\n\tif capture_pane_contents_option_on; then\n\t\tcache_tmux_default_command\n\t\trestore_pane_contents_true\n\tfi\n}\n\n# functions called from main (ordered)\n\nrestore_all_panes() {\n\tdetect_if_restoring_from_scratch   # sets a global variable\n\tdetect_if_restoring_pane_contents  # sets a global variable\n\tif is_restoring_pane_contents; then\n\t\tpane_content_files_restore_from_archive\n\tfi\n\twhile read line; do\n\t\tif is_line_type \"pane\" \"$line\"; then\n\t\t\trestore_pane \"$line\"\n\t\tfi\n\tdone < $(last_resurrect_file)\n}\n\nhandle_session_0() {\n\tif is_restoring_from_scratch && ! has_restored_session_0; then\n\t\tlocal current_session=\"$(tmux display -p \"#{client_session}\")\"\n\t\tif [ \"$current_session\" == \"0\" ]; then\n\t\t\ttmux switch-client -n\n\t\tfi\n\t\ttmux kill-session -t \"0\"\n\tfi\n}\n\nrestore_window_properties() {\n\tlocal window_name\n\t\\grep '^window' $(last_resurrect_file) |\n\t\twhile IFS=$d read line_type session_name window_number window_name window_active window_flags window_layout automatic_rename; do\n\t\t\ttmux select-layout -t \"${session_name}:${window_number}\" \"$window_layout\"\n\n\t\t\t# Below steps are properly handling window names and automatic-rename\n\t\t\t# option. `rename-window` is an extra command in some scenarios, but we\n\t\t\t# opted for always doing it to keep the code simple.\n\t\t\twindow_name=\"$(remove_first_char \"$window_name\")\"\n\t\t\ttmux rename-window -t \"${session_name}:${window_number}\" \"$window_name\"\n\t\t\tif [ \"${automatic_rename}\" = \":\" ]; then\n\t\t\t\ttmux set-option -u -t \"${session_name}:${window_number}\" automatic-rename\n\t\t\telse\n\t\t\t\ttmux set-option -t \"${session_name}:${window_number}\" automatic-rename \"$automatic_rename\"\n\t\t\tfi\n\t\tdone\n}\n\nrestore_all_pane_processes() {\n\tif restore_pane_processes_enabled; then\n\t\tlocal pane_full_command\n\t\tawk 'BEGIN { FS=\"\\t\"; OFS=\"\\t\" } /^pane/ && $11 !~ \"^:$\" { print $2, $3, $6, $8, $11; }' $(last_resurrect_file) |\n\t\t\twhile IFS=$d read -r session_name window_number pane_index dir pane_full_command; do\n\t\t\t\tdir=\"$(remove_first_char \"$dir\")\"\n\t\t\t\tpane_full_command=\"$(remove_first_char \"$pane_full_command\")\"\n\t\t\t\trestore_pane_process \"$pane_full_command\" \"$session_name\" \"$window_number\" \"$pane_index\" \"$dir\"\n\t\t\tdone\n\tfi\n}\n\nrestore_active_pane_for_each_window() {\n\tawk 'BEGIN { FS=\"\\t\"; OFS=\"\\t\" } /^pane/ && $9 == 1 { print $2, $3, $6; }' $(last_resurrect_file) |\n\t\twhile IFS=$d read session_name window_number active_pane; do\n\t\t\ttmux switch-client -t \"${session_name}:${window_number}\"\n\t\t\ttmux select-pane -t \"$active_pane\"\n\t\tdone\n}\n\nrestore_zoomed_windows() {\n\tawk 'BEGIN { FS=\"\\t\"; OFS=\"\\t\" } /^pane/ && $5 ~ /Z/ && $9 == 1 { print $2, $3; }' $(last_resurrect_file) |\n\t\twhile IFS=$d read session_name window_number; do\n\t\t\ttmux resize-pane -t \"${session_name}:${window_number}\" -Z\n\t\tdone\n}\n\nrestore_grouped_sessions() {\n\twhile read line; do\n\t\tif is_line_type \"grouped_session\" \"$line\"; then\n\t\t\trestore_grouped_session \"$line\"\n\t\t\trestore_active_and_alternate_windows_for_grouped_sessions \"$line\"\n\t\tfi\n\tdone < $(last_resurrect_file)\n}\n\nrestore_active_and_alternate_windows() {\n\tawk 'BEGIN { FS=\"\\t\"; OFS=\"\\t\" } /^window/ && $6 ~ /[*-]/ { print $2, $5, $3; }' $(last_resurrect_file) |\n\t\tsort -u |\n\t\twhile IFS=$d read session_name active_window window_number; do\n\t\t\ttmux switch-client -t \"${session_name}:${window_number}\"\n\t\tdone\n}\n\nrestore_active_and_alternate_sessions() {\n\twhile read line; do\n\t\tif is_line_type \"state\" \"$line\"; then\n\t\t\trestore_state \"$line\"\n\t\tfi\n\tdone < $(last_resurrect_file)\n}\n\n# A cleanup that happens after 'restore_all_panes' seems to fix fish shell\n# users' restore problems.\ncleanup_restored_pane_contents() {\n\tif is_restoring_pane_contents; then\n\t\trm \"$(pane_contents_dir \"restore\")\"/*\n\tfi\n}\n\nmain() {\n\tif supported_tmux_version_ok && check_saved_session_exists; then\n\t\tstart_spinner \"Restoring...\" \"Tmux restore complete!\"\n\t\texecute_hook \"pre-restore-all\"\n\t\trestore_all_panes\n\t\thandle_session_0\n\t\trestore_window_properties >/dev/null 2>&1\n\t\texecute_hook \"pre-restore-pane-processes\"\n\t\trestore_all_pane_processes\n\t\t# below functions restore exact cursor positions\n\t\trestore_active_pane_for_each_window\n\t\trestore_zoomed_windows\n\t\trestore_grouped_sessions  # also restores active and alt windows for grouped sessions\n\t\trestore_active_and_alternate_windows\n\t\trestore_active_and_alternate_sessions\n\t\tcleanup_restored_pane_contents\n\t\texecute_hook \"post-restore-all\"\n\t\tstop_spinner\n\t\tdisplay_message \"Tmux restore complete!\"\n\tfi\n}\nmain\n"
  },
  {
    "path": "scripts/save.sh",
    "content": "#!/usr/bin/env bash\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\nsource \"$CURRENT_DIR/variables.sh\"\nsource \"$CURRENT_DIR/helpers.sh\"\nsource \"$CURRENT_DIR/spinner_helpers.sh\"\n\n# delimiters\nd=$'\\t'\ndelimiter=$'\\t'\n\n# if \"quiet\" script produces no output\nSCRIPT_OUTPUT=\"$1\"\n\ngrouped_sessions_format() {\n\tlocal format\n\tformat+=\"#{session_grouped}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{session_group}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{session_id}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{session_name}\"\n\techo \"$format\"\n}\n\npane_format() {\n\tlocal format\n\tformat+=\"pane\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{session_name}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{window_index}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{window_active}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\":#{window_flags}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{pane_index}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{pane_title}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\":#{pane_current_path}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{pane_active}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{pane_current_command}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{pane_pid}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{history_size}\"\n\techo \"$format\"\n}\n\nwindow_format() {\n\tlocal format\n\tformat+=\"window\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{session_name}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{window_index}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\":#{window_name}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{window_active}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\":#{window_flags}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{window_layout}\"\n\techo \"$format\"\n}\n\nstate_format() {\n\tlocal format\n\tformat+=\"state\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{client_session}\"\n\tformat+=\"${delimiter}\"\n\tformat+=\"#{client_last_session}\"\n\techo \"$format\"\n}\n\ndump_panes_raw() {\n\ttmux list-panes -a -F \"$(pane_format)\"\n}\n\ndump_windows_raw(){\n\ttmux list-windows -a -F \"$(window_format)\"\n}\n\ntoggle_window_zoom() {\n\tlocal target=\"$1\"\n\ttmux resize-pane -Z -t \"$target\"\n}\n\n_save_command_strategy_file() {\n\tlocal save_command_strategy=\"$(get_tmux_option \"$save_command_strategy_option\" \"$default_save_command_strategy\")\"\n\tlocal strategy_file=\"$CURRENT_DIR/../save_command_strategies/${save_command_strategy}.sh\"\n\tlocal default_strategy_file=\"$CURRENT_DIR/../save_command_strategies/${default_save_command_strategy}.sh\"\n\tif [ -e \"$strategy_file\" ]; then # strategy file exists?\n\t\techo \"$strategy_file\"\n\telse\n\t\techo \"$default_strategy_file\"\n\tfi\n}\n\npane_full_command() {\n\tlocal pane_pid=\"$1\"\n\tlocal strategy_file=\"$(_save_command_strategy_file)\"\n\t# execute strategy script to get pane full command\n\t$strategy_file \"$pane_pid\"\n}\n\nnumber_nonempty_lines_on_screen() {\n\tlocal pane_id=\"$1\"\n\ttmux capture-pane -pJ -t \"$pane_id\" |\n\t\tsed '/^$/d' |\n\t\twc -l |\n\t\tsed 's/ //g'\n}\n\n# tests if there was any command output in the current pane\npane_has_any_content() {\n\tlocal pane_id=\"$1\"\n\tlocal history_size=\"$(tmux display -p -t \"$pane_id\" -F \"#{history_size}\")\"\n\tlocal cursor_y=\"$(tmux display -p -t \"$pane_id\" -F \"#{cursor_y}\")\"\n\t# doing \"cheap\" tests first\n\t[ \"$history_size\" -gt 0 ] || # history has any content?\n\t\t[ \"$cursor_y\" -gt 0 ] || # cursor not in first line?\n\t\t[ \"$(number_nonempty_lines_on_screen \"$pane_id\")\" -gt 1 ]\n}\n\ncapture_pane_contents() {\n\tlocal pane_id=\"$1\"\n\tlocal start_line=\"-$2\"\n\tlocal pane_contents_area=\"$3\"\n\tif pane_has_any_content \"$pane_id\"; then\n\t\tif [ \"$pane_contents_area\" = \"visible\" ]; then\n\t\t\tstart_line=\"0\"\n\t\tfi\n\t\t# the printf hack below removes *trailing* empty lines\n\t\tprintf '%s\\n' \"$(tmux capture-pane -epJ -S \"$start_line\" -t \"$pane_id\")\" > \"$(pane_contents_file \"save\" \"$pane_id\")\"\n\tfi\n}\n\nget_active_window_index() {\n\tlocal session_name=\"$1\"\n\ttmux list-windows -t \"$session_name\" -F \"#{window_flags} #{window_index}\" |\n\t\tawk '$1 ~ /\\*/ { print $2; }'\n}\n\nget_alternate_window_index() {\n\tlocal session_name=\"$1\"\n\ttmux list-windows -t \"$session_name\" -F \"#{window_flags} #{window_index}\" |\n\t\tawk '$1 ~ /-/ { print $2; }'\n}\n\ndump_grouped_sessions() {\n\tlocal current_session_group=\"\"\n\tlocal original_session\n\ttmux list-sessions -F \"$(grouped_sessions_format)\" |\n\t\tgrep \"^1\" |\n\t\tcut -c 3- |\n\t\tsort |\n\t\twhile IFS=$d read session_group session_id session_name; do\n\t\t\tif [ \"$session_group\" != \"$current_session_group\" ]; then\n\t\t\t\t# this session is the original/first session in the group\n\t\t\t\toriginal_session=\"$session_name\"\n\t\t\t\tcurrent_session_group=\"$session_group\"\n\t\t\telse\n\t\t\t\t# this session \"points\" to the original session\n\t\t\t\tactive_window_index=\"$(get_active_window_index \"$session_name\")\"\n\t\t\t\talternate_window_index=\"$(get_alternate_window_index \"$session_name\")\"\n\t\t\t\techo \"grouped_session${d}${session_name}${d}${original_session}${d}:${alternate_window_index}${d}:${active_window_index}\"\n\t\t\tfi\n\t\tdone\n}\n\nfetch_and_dump_grouped_sessions(){\n\tlocal grouped_sessions_dump=\"$(dump_grouped_sessions)\"\n\tget_grouped_sessions \"$grouped_sessions_dump\"\n\tif [ -n \"$grouped_sessions_dump\" ]; then\n\t\techo \"$grouped_sessions_dump\"\n\tfi\n}\n\n# translates pane pid to process command running inside a pane\ndump_panes() {\n\tlocal full_command\n\tdump_panes_raw |\n\t\twhile 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\n\t\t\t# not saving panes from grouped sessions\n\t\t\tif is_session_grouped \"$session_name\"; then\n\t\t\t\tcontinue\n\t\t\tfi\n\t\t\tfull_command=\"$(pane_full_command $pane_pid)\"\n\t\t\tdir=$(echo $dir | sed 's/ /\\\\ /') # escape all spaces in directory path\n\t\t\techo \"${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}\"\n\t\tdone\n}\n\ndump_windows() {\n\tdump_windows_raw |\n\t\twhile IFS=$d read line_type session_name window_index window_name window_active window_flags window_layout; do\n\t\t\t# not saving windows from grouped sessions\n\t\t\tif is_session_grouped \"$session_name\"; then\n\t\t\t\tcontinue\n\t\t\tfi\n\t\t\tautomatic_rename=\"$(tmux show-window-options -vt \"${session_name}:${window_index}\" automatic-rename)\"\n\t\t\t# If the option was unset, use \":\" as a placeholder.\n\t\t\t[ -z \"${automatic_rename}\" ] && automatic_rename=\":\"\n\t\t\techo \"${line_type}${d}${session_name}${d}${window_index}${d}${window_name}${d}${window_active}${d}${window_flags}${d}${window_layout}${d}${automatic_rename}\"\n\t\tdone\n}\n\ndump_state() {\n\ttmux display-message -p \"$(state_format)\"\n}\n\ndump_pane_contents() {\n\tlocal pane_contents_area=\"$(get_tmux_option \"$pane_contents_area_option\" \"$default_pane_contents_area\")\"\n\tdump_panes_raw |\n\t\twhile 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\n\t\t\tcapture_pane_contents \"${session_name}:${window_number}.${pane_index}\" \"$history_size\" \"$pane_contents_area\"\n\t\tdone\n}\n\nremove_old_backups() {\n\t# remove resurrect files older than 30 days (default), but keep at least 5 copies of backup.\n\tlocal delete_after=\"$(get_tmux_option \"$delete_backup_after_option\" \"$default_delete_backup_after\")\"\n\tlocal -a files\n\tfiles=($(ls -t $(resurrect_dir)/${RESURRECT_FILE_PREFIX}_*.${RESURRECT_FILE_EXTENSION} | tail -n +6))\n\t[[ ${#files[@]} -eq 0 ]] ||\n\t\tfind \"${files[@]}\" -type f -mtime \"+${delete_after}\" -exec rm -v \"{}\" \\; > /dev/null\n}\n\nsave_all() {\n\tlocal resurrect_file_path=\"$(resurrect_file_path)\"\n\tlocal last_resurrect_file=\"$(last_resurrect_file)\"\n\tmkdir -p \"$(resurrect_dir)\"\n\tfetch_and_dump_grouped_sessions > \"$resurrect_file_path\"\n\tdump_panes   >> \"$resurrect_file_path\"\n\tdump_windows >> \"$resurrect_file_path\"\n\tdump_state   >> \"$resurrect_file_path\"\n\texecute_hook \"post-save-layout\" \"$resurrect_file_path\"\n\tif files_differ \"$resurrect_file_path\" \"$last_resurrect_file\"; then\n\t\tln -fs \"$(basename \"$resurrect_file_path\")\" \"$last_resurrect_file\"\n\telse\n\t\trm \"$resurrect_file_path\"\n\tfi\n\tif capture_pane_contents_option_on; then\n\t\tmkdir -p \"$(pane_contents_dir \"save\")\"\n\t\tdump_pane_contents\n\t\tpane_contents_create_archive\n\t\trm \"$(pane_contents_dir \"save\")\"/*\n\tfi\n\tremove_old_backups\n\texecute_hook \"post-save-all\"\n}\n\nshow_output() {\n\t[ \"$SCRIPT_OUTPUT\" != \"quiet\" ]\n}\n\nmain() {\n\tif supported_tmux_version_ok; then\n\t\tif show_output; then\n\t\t\tstart_spinner \"Saving...\" \"Tmux environment saved!\"\n\t\tfi\n\t\tsave_all\n\t\tif show_output; then\n\t\t\tstop_spinner\n\t\t\tdisplay_message \"Tmux environment saved!\"\n\t\tfi\n\tfi\n}\nmain\n"
  },
  {
    "path": "scripts/spinner_helpers.sh",
    "content": "start_spinner() {\n\t$CURRENT_DIR/tmux_spinner.sh \"$1\" \"$2\" &\n\texport SPINNER_PID=$!\n}\n\nstop_spinner() {\n\tkill $SPINNER_PID\n}\n"
  },
  {
    "path": "scripts/tmux_spinner.sh",
    "content": "#!/usr/bin/env bash\n\n# This script shows tmux spinner with a message. It is intended to be running\n# as a background process which should be `kill`ed at the end.\n#\n# Example usage:\n#\n#   ./tmux_spinner.sh \"Working...\" \"End message!\" &\n#   SPINNER_PID=$!\n#   ..\n#   .. execute commands here\n#   ..\n#   kill $SPINNER_PID # Stops spinner and displays 'End message!'\n\nMESSAGE=\"$1\"\nEND_MESSAGE=\"$2\"\nSPIN='-\\|/'\n\ntrap \"tmux display-message '$END_MESSAGE'; exit\" SIGINT SIGTERM\n\nmain() {\n\tlocal i=0\n\twhile true; do\n\t  i=$(( (i+1) %4 ))\n\t  tmux display-message \" ${SPIN:$i:1} $MESSAGE\"\n\t  sleep 0.1\n\tdone\n}\nmain\n"
  },
  {
    "path": "scripts/variables.sh",
    "content": "# key bindings\ndefault_save_key=\"C-s\"\nsave_option=\"@resurrect-save\"\nsave_path_option=\"@resurrect-save-script-path\"\n\ndefault_restore_key=\"C-r\"\nrestore_option=\"@resurrect-restore\"\nrestore_path_option=\"@resurrect-restore-script-path\"\n\n# default processes that are restored\ndefault_proc_list_option=\"@resurrect-default-processes\"\ndefault_proc_list='vi vim view nvim emacs man less more tail top htop irssi weechat mutt'\n\n# User defined processes that are restored\n#  'false' - nothing is restored\n#  ':all:' - all processes are restored\n#\n# user defined list of programs that are restored:\n#  'my_program foo another_program'\nrestore_processes_option=\"@resurrect-processes\"\nrestore_processes=\"\"\n\n# Defines part of the user variable. Example usage:\n#   set -g @resurrect-strategy-vim \"session\"\nrestore_process_strategy_option=\"@resurrect-strategy-\"\n\ninline_strategy_token=\"->\"\ninline_strategy_arguments_token=\"*\"\n\nsave_command_strategy_option=\"@resurrect-save-command-strategy\"\ndefault_save_command_strategy=\"ps\"\n\n# Pane contents capture options.\n# @resurrect-pane-contents-area option can be:\n#   'visible' - capture only the visible pane area\n#   'full'    - capture the full pane contents\npane_contents_option=\"@resurrect-capture-pane-contents\"\npane_contents_area_option=\"@resurrect-pane-contents-area\"\ndefault_pane_contents_area=\"full\"\n\n# set to 'on' to ensure panes are never ever overwritten\noverwrite_option=\"@resurrect-never-overwrite\"\n\n# Hooks are set via ${hook_prefix}${name}, i.e. \"@resurrect-hook-post-save-all\"\nhook_prefix=\"@resurrect-hook-\"\n\ndelete_backup_after_option=\"@resurrect-delete-backup-after\"\ndefault_delete_backup_after=\"30\" # days\n"
  },
  {
    "path": "strategies/irb_default_strategy.sh",
    "content": "#!/usr/bin/env bash\n\n# \"irb default strategy\"\n#\n# Example irb process with junk variables:\n#   irb RBENV_VERSION=1.9.3-p429 GREP_COLOR=34;47 TERM_PROGRAM=Apple_Terminal\n#\n# When executed, the above will fail. This strategy handles that.\n\nORIGINAL_COMMAND=\"$1\"\nDIRECTORY=\"$2\"\n\noriginal_command_wo_junk_vars() {\n\techo \"$ORIGINAL_COMMAND\" |\n\t\tsed 's/RBENV_VERSION[^ ]*//' |\n\t\tsed 's/GREP_COLOR[^ ]*//'    |\n\t\tsed 's/TERM_PROGRAM[^ ]*//'\n}\n\nmain() {\n\techo \"$(original_command_wo_junk_vars)\"\n}\nmain\n"
  },
  {
    "path": "strategies/mosh-client_default_strategy.sh",
    "content": "#!/usr/bin/env bash\n\n# \"mosh-client default strategy\"\n#\n# Example mosh-client process:\n#   mosh-client -# charm tmux at | 198.199.104.142 60001\n#\n# When executed, the above will fail. This strategy handles that.\n\nORIGINAL_COMMAND=\"$1\"\nDIRECTORY=\"$2\"\n\nmosh_command() {\n\tlocal args=\"$ORIGINAL_COMMAND\"\n\n\targs=\"${args#*-#}\"\n\targs=\"${args%|*}\"\n\n\techo \"mosh $args\"\n}\n\nmain() {\n\techo \"$(mosh_command)\"\n}\nmain\n"
  },
  {
    "path": "strategies/nvim_session.sh",
    "content": "#!/usr/bin/env bash\n\n# \"nvim session strategy\"\n#\n# Same as vim strategy, see file 'vim_session.sh'\n\nORIGINAL_COMMAND=\"$1\"\nDIRECTORY=\"$2\"\n\nnvim_session_file_exists() {\n\t[ -e \"${DIRECTORY}/Session.vim\" ]\n}\n\noriginal_command_contains_session_flag() {\n\t[[ \"$ORIGINAL_COMMAND\" =~ \"-S\" ]]\n}\n\nmain() {\n\tif nvim_session_file_exists; then\n\t\techo \"nvim -S\"\n\telif original_command_contains_session_flag; then\n\t\t# Session file does not exist, yet the original nvim command contains\n\t\t# session flag `-S`. This will cause an error, so we're falling back to\n\t\t# starting plain nvim.\n\t\techo \"nvim\"\n\telse\n\t\techo \"$ORIGINAL_COMMAND\"\n\tfi\n}\nmain\n"
  },
  {
    "path": "strategies/vim_session.sh",
    "content": "#!/usr/bin/env bash\n\n# \"vim session strategy\"\n#\n# Restores a vim session from 'Session.vim' file, if it exists.\n# If 'Session.vim' does not exist, it falls back to invoking the original\n# command (without the `-S` flag).\n\nORIGINAL_COMMAND=\"$1\"\nDIRECTORY=\"$2\"\n\nvim_session_file_exists() {\n\t[ -e \"${DIRECTORY}/Session.vim\" ]\n}\n\nmain() {\n\tif vim_session_file_exists; then\n\t\techo \"vim -S\"\n\telse\n\t\techo \"$ORIGINAL_COMMAND\"\n\tfi\n}\nmain\n"
  },
  {
    "path": "tests/fixtures/restore_file.txt",
    "content": "pane\t0\t0\t:bash\t1\t:*\t0\t:/tmp\t1\tbash\t:\npane\tblue\t0\t:vim\t0\t:\t0\t:/tmp\t1\tvim\t:vim foo.txt\npane\tblue\t1\t:man\t0\t:-\t0\t:/tmp\t0\tbash\t:\npane\tblue\t1\t:man\t0\t:-\t1\t:/usr/share/man\t1\tman\t:man echo\npane\tblue\t2\t:bash\t1\t:*\t0\t:/tmp\t1\tbash\t:\npane\tred\t0\t:bash\t0\t:\t0\t:/tmp\t1\tbash\t:\npane\tred\t1\t:bash\t0\t:-Z\t0\t:/tmp\t0\tbash\t:\npane\tred\t1\t:bash\t0\t:-Z\t1\t:/tmp\t0\tbash\t:\npane\tred\t1\t:bash\t0\t:-Z\t2\t:/tmp\t1\tbash\t:\npane\tred\t2\t:bash\t1\t:*\t0\t:/tmp\t0\tbash\t:\npane\tred\t2\t:bash\t1\t:*\t1\t:/tmp\t1\tbash\t:\npane\tyellow\t0\t:bash\t1\t:*\t0\t:/tmp/bar\t1\tbash\t:\nwindow\t0\t0\t1\t:*\tce9e,200x49,0,0,1\nwindow\tblue\t0\t0\t:\tce9f,200x49,0,0,2\nwindow\tblue\t1\t0\t:-\t178b,200x49,0,0{100x49,0,0,3,99x49,101,0,4}\nwindow\tblue\t2\t1\t:*\tcea2,200x49,0,0,5\nwindow\tred\t0\t0\t:\tcea3,200x49,0,0,6\nwindow\tred\t1\t0\t:-Z\t135b,200x49,0,0[200x24,0,0,7,200x24,0,25{100x24,0,25,8,99x24,101,25,9}]\nwindow\tred\t2\t1\t:*\tdb81,200x49,0,0[200x24,0,0,10,200x24,0,25,11]\nwindow\tyellow\t0\t1\t:*\t6781,200x49,0,0,12\nstate\tyellow\tblue\n"
  },
  {
    "path": "tests/fixtures/save_file.txt",
    "content": "pane\t0\t0\t:bash\t1\t:*\t0\t:/tmp\t1\tbash\t:\npane\tblue\t0\t:vim\t0\t:!\t0\t:/tmp\t1\tvim\t:vim foo.txt\npane\tblue\t1\t:man\t0\t:!-\t0\t:/tmp\t0\tbash\t:\npane\tblue\t1\t:man\t0\t:!-\t1\t:/usr/share/man\t1\tman\t:man echo\npane\tblue\t2\t:bash\t1\t:*\t0\t:/tmp\t1\tbash\t:\npane\tred\t0\t:bash\t0\t:\t0\t:/tmp\t1\tbash\t:\npane\tred\t1\t:bash\t0\t:-Z\t0\t:/tmp\t0\tbash\t:\npane\tred\t1\t:bash\t0\t:-Z\t1\t:/tmp\t0\tbash\t:\npane\tred\t1\t:bash\t0\t:-Z\t2\t:/tmp\t1\tbash\t:\npane\tred\t2\t:bash\t1\t:*\t0\t:/tmp\t0\tbash\t:\npane\tred\t2\t:bash\t1\t:*\t1\t:/tmp\t1\tbash\t:\npane\tyellow\t0\t:bash\t1\t:*\t0\t:/tmp/bar\t1\tbash\t:\nwindow\t0\t0\t1\t:*\tce9d,200x49,0,0,0\nwindow\tblue\t0\t0\t:!\tcea4,200x49,0,0,7\nwindow\tblue\t1\t0\t:!-\t9797,200x49,0,0{100x49,0,0,8,99x49,101,0,9}\nwindow\tblue\t2\t1\t:*\t677f,200x49,0,0,10\nwindow\tred\t0\t0\t:\tce9e,200x49,0,0,1\nwindow\tred\t1\t0\t:-Z\t52b7,200x49,0,0[200x24,0,0,2,200x24,0,25{100x24,0,25,3,99x24,101,25,4}]\nwindow\tred\t2\t1\t:*\tbd68,200x49,0,0[200x24,0,0,5,200x24,0,25,6]\nwindow\tyellow\t0\t1\t:*\t6780,200x49,0,0,11\nstate\tyellow\tblue\n"
  },
  {
    "path": "tests/helpers/create_and_save_tmux_test_environment.exp",
    "content": "#!/usr/bin/env expect\n\nsource \"./tests/helpers/expect_helpers.exp\"\n\nexpect_setup\n\nspawn tmux\n# delay with sleep to compensate for tmux starting time\nsleep 1\n\nrun_shell_command \"cd /tmp\"\n\n# session red\nnew_tmux_session \"red\"\n\nnew_tmux_window\nhorizontal_split\nvertical_split\ntoggle_zoom_pane\n\nnew_tmux_window\nhorizontal_split\n\n# session blue\nnew_tmux_session \"blue\"\n\nrun_shell_command \"touch foo.txt\"\nrun_shell_command \"vim foo.txt\"\n\nnew_tmux_window\nvertical_split\nrun_shell_command \"man echo\"\n\nnew_tmux_window\n\n# session yellow\nnew_tmux_session \"yellow\"\nrun_shell_command \"cd /tmp/bar\"\n\nstart_resurrect_save\n\nrun_shell_command \"tmux kill-server\"\n"
  },
  {
    "path": "tests/helpers/expect_helpers.exp",
    "content": "# a set of expect helpers\n\n# basic setup for each script\nproc expect_setup {} {\n  # disables script output\n  log_user 0\n  # standard timeout\n  set timeout 5\n}\n\nproc new_tmux_window {} {\n  send \"\u0002c\"\n  send \"cd /tmp\\r\"\n  sleep 0.2\n}\n\nproc rename_current_session {name} {\n  send \"\u0002$\"\n  # delete existing name with ctrl-u\n  send \"\u0015\"\n  send \"$name\\r\"\n  sleep 0.2\n}\n\nproc new_tmux_session {name} {\n  send \"TMUX='' tmux new -d -s $name\\r\"\n  sleep 1\n  send \"tmux switch-client -t $name\\r\"\n  send \"cd /tmp\\r\"\n  sleep 0.5\n}\n\nproc horizontal_split {} {\n  send \"\u0002\\\"\"\n  sleep 0.2\n  send \"cd /tmp\\r\"\n  sleep 0.1\n}\n\nproc vertical_split {} {\n  send \"\u0002%\"\n  sleep 0.2\n  send \"cd /tmp\\r\"\n  sleep 0.1\n}\n\nproc toggle_zoom_pane {} {\n  send \"\u0002z\"\n  sleep 0.2\n}\n\nproc run_shell_command {command} {\n  send \"$command\\r\"\n  sleep 1\n}\n\nproc start_resurrect_save {} {\n  send \"\u0002\u0013\"\n  sleep 5\n}\n\nproc start_resurrect_restore {} {\n  send \"\u0002\u0012\"\n  sleep 10\n}\n\nproc clear_screen_for_window {target} {\n  send \"tmux send-keys -t $target C-l\\r\"\n  sleep 0.2\n}\n"
  },
  {
    "path": "tests/helpers/restore_and_save_tmux_test_environment.exp",
    "content": "#!/usr/bin/env expect\n\nsource \"./tests/helpers/expect_helpers.exp\"\n\nexpect_setup\n\nspawn tmux\n# delay with sleep to compensate for tmux starting time\nsleep 1\n\nstart_resurrect_restore\n\n# delete all existing resurrect save files\nrun_shell_command \"rm ~/.tmux/resurrect/*\"\n\nstart_resurrect_save\n\nrun_shell_command \"tmux kill-server\"\n"
  },
  {
    "path": "tests/helpers/resurrect_helpers.sh",
    "content": "# we want \"fixed\" dimensions no matter the size of real display\nset_screen_dimensions_helper() {\n\tstty cols 200\n\tstty rows 50\n}\n\nlast_save_file_differs_helper() {\n\tlocal original_file=\"$1\"\n\tdiff \"$original_file\" \"${HOME}/.tmux/resurrect/last\"\n\t[ $? -ne 0 ]\n}\n"
  },
  {
    "path": "tests/test_resurrect_restore.sh",
    "content": "#!/usr/bin/env bash\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\nsource $CURRENT_DIR/helpers/helpers.sh\nsource $CURRENT_DIR/helpers/resurrect_helpers.sh\n\nsetup_before_restore() {\n\t# setup restore file\n\tmkdir -p ~/.tmux/resurrect/\n\tcp tests/fixtures/restore_file.txt \"${HOME}/.tmux/resurrect/restore_file.txt\"\n\tln -sf restore_file.txt \"${HOME}/.tmux/resurrect/last\"\n\n\t# directory used in restored tmux session\n\tmkdir -p /tmp/bar\n}\n\nrestore_tmux_environment_and_save_again() {\n\tset_screen_dimensions_helper\n\t$CURRENT_DIR/helpers/restore_and_save_tmux_test_environment.exp\n}\n\nmain() {\n\tinstall_tmux_plugin_under_test_helper\n\tsetup_before_restore\n\trestore_tmux_environment_and_save_again\n\n\tif last_save_file_differs_helper \"tests/fixtures/restore_file.txt\"; then\n\t\tfail_helper \"Saved file not correct after restore\"\n\tfi\n\texit_helper\n}\nmain\n"
  },
  {
    "path": "tests/test_resurrect_save.sh",
    "content": "#!/usr/bin/env bash\n\nCURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n\nsource $CURRENT_DIR/helpers/helpers.sh\nsource $CURRENT_DIR/helpers/resurrect_helpers.sh\n\ncreate_tmux_test_environment_and_save() {\n\tset_screen_dimensions_helper\n\t$CURRENT_DIR/helpers/create_and_save_tmux_test_environment.exp\n}\n\nmain() {\n\tinstall_tmux_plugin_under_test_helper\n\tmkdir -p /tmp/bar # setup required dirs\n\tcreate_tmux_test_environment_and_save\n\n\tif last_save_file_differs_helper \"tests/fixtures/save_file.txt\"; then\n\t\tfail_helper \"Saved file not correct (initial save)\"\n\tfi\n\texit_helper\n}\nmain\n"
  },
  {
    "path": "video/script.md",
    "content": "# Screencast script\n\n1. Intro\n========\nLet's demo tmux resurrect plugin.\n\nTmux resurrect enables persisting tmux sessions, so it can survive the dreaded\nsystem restarts.\n\nThe benefit is uninterrupted workflow with no configuration required.\n\n2. Working session\n==================\nScript\n------\nLet me show you what I have in this tmux demo session.\n\nFirst of all, I have vim open and it has a couple files loaded.\n\nThen there's a tmux window with a couple splits in various directories across\nthe system.\n\nNext window contains tmux man page,\n  and then there's `htop` program.\n\nAnd this is just one of many projects I'm currently running.\n\nActions\n-------\n- blank tmux window\n- vim\n  - `ls` to show open files\n- multiple pane windows (3)\n- man tmux\n- htop\n- psql\n- show a list of session\n\n3. Saving the environment\n=========================\nScript\n------\nWith vanilla tmux, when I restart the computer this whole environment will be\nlost and I'll have to invest time to restore it.\n\ntmux resurrect gives you the ability to persist everything with\nprefix plus alt-s.\n\nNow tmux environment is saved and I can safely shut down tmux with a\nkill server command.\n\nActions\n-------\n- prefix + M-s\n- :kill-server\n\n4. Restoring the environment\n============================\nScript\n------\nAt this point restoring everything back is easy.\n\nI'll fire up tmux again. Notice it's completely empty.\n\nNow, I'll press prefix plus alt-r and everything will restore.\n\nLet's see how things look now.\nFirst of all, I'm back to the exact same window I was in when the environment\nwas saved. Second - you can see the `htop` program was restored.\n\nGoing back there's tmux man page\n  a window with multiple panes with the exact same layout as before\n  and vim.\n\n\ntmux resurrect takes special care of vim. By leveraging vim's sessions, it\npreserves vim's split windows, open files, even the list of files edited before.\n\nCheck out the project readme for more details about special treatment for vim.\n\nThat was just one of the restored tmux sessions. If I open tmux session list you\ncan see all the other projects are restored as well.\n\n\nWhen you see all these programs running you might be concerned that this plugin\nstarted a lot of potentially destructive processes.\n\nFor example, when you restore tmux you don't want to accidentally start backups,\nresource intensive or sensitive programs.\n\nThere's no need to be worried though. By default, this plugin starts only a\nconservative list of programs like vim, less, tail, htop and similar.\nThis list of programs restored by default is in the project readme. Also, you\ncan easily add more programs to it.\n\nIf you feel paranoid, there's an option that prevents restoring any program.\n\nActions\n-------\n- tmux\n- prefix + M-r\n\n- open previous windows\n- in vim hit :ls\n\n- prefix + s for a list of panes\n\n5. Outro\n========\nThat's it for this demo. I hope you'll find tmux resurrect useful.\n"
  }
]