How to get tmux resurrect to restore neovim sessions

Hi All,

I’ve recently moved to NixOS, as part of my workflow I use both tmux and neovim.
On Arch I was able to restore my neovim sessions automatically using tmux resurrect (and continuum) plugins. However I cannot seem to get it to work correctly on NixOS, specifically to restore my nvim session.

My current tmux config: https://github.com/hmajid2301/dotfiles/blob/386d96028783bb31ca14dcda728190822225c7c3/home-manager/programs/tmux.nix#L108-L110

Taking a look at my resurrect/last file:

# bat ~/.tmux/resurrect/last --plain

pane    dotfiles    0   1   :*  0   nvim ~/dotfiles :/home/haseeb/dotfiles  1   nvim    :/home/haseeb/.nix-profile/bin/nvim --cmd lua vim.g.loaded_node_provider=0;vim.g.loaded_perl_provider=0;vim.g.loaded_python_provider=0;vim.g.python3_host_prog='/nix/store/4n4d0f1xd14gl4pfymdcqb9pmagcyyfj-neovim-0.9.1/bin/nvim-python3';vim.g.ruby_host_prog='/nix/store/4n4d0f1xd14gl4pfymdcqb9pmagcyyfj-neovim-0.9.1/bin/nvim-ruby'

Is it trying to run /home/haseeb/.nix-profile/bin/nvim --cmd lua vim.g.loaded_node_provider=0;vim.g.loaded_perl_provider=0;vim.g.loaded_python_provider=0;vim.g.python3_host_prog='/nix/store/4n4d0f1xd14gl4pfymdcqb9pmagcyyfj-neovim-0.9.1/bin/nvim-python3';vim.g.ruby_host_prog='/nix/store/4n4d0f1xd14gl4pfymdcqb9pmagcyyfj-neovim-0.9.1/bin/nvim-ruby' ?

Has anyone got tmux resurrect to work with nvim on NixOS?

Thanks in advance for any help!

Related Issues:

I came across the same issue and the problem is with the way that tmux-resurrect saves the names of the process it later needs to resurrect, This issue is not specific to NixOS and is caused once the name of the process deviates from the one tmux-resurrect plugin expects when it parses its state file(file named last that points at some tmux_resurrect_*).

The workaround is to leverage a tmux-resurrect hook that will be triggered each time tmux state is saved. I ended adding the
following 4 lines to the configurations of the tmux-resurrect plugin
as will be in the generated .tmux.conf

resurrect_dir=“$HOME/.tmux/resurrect”
set -g @resurrect-dir $resurrect_dir
set -g @resurrect-hook-post-save-all ‘target=$(readlink -f $resurrect_dir/last); sed “s| --cmd .*-vim-pack-dir||g; s|/etc/profiles/per-user/$USER/bin/||g” $target | sponge $target’

You can see the actual code in my repo

2 Likes

Hi thanks for getting back to me!

I added it:

resurrect_dir="$HOME/.tmux/resurrect"
set -g @resurrect-dir $resurrect_dir
set -g @resurrect-hook-post-save-all 'target=$(readlink -f $resurrect_dir/last); sed "s| --cmd .*-vim-pack-dir||g; s|/etc/profiles/per-user/$USER/bin/||g" $target | sponge $target'

I then created a session.vim file using :mksession but when I kill and start the tmux server again, it doesnt auto load nvim still :/.

Where my resurrect file looks like:

bat ~/.tmux/resurrect/last --plain
pane    dooit   0   1   :*  0   ~/.l/s/dooit    :/home/haseebmajid/.local/share/dooit   1   fish    :
pane    dotfiles    0   1   :*  0   nvim ~/dotfiles :/home/haseebmajid/dotfiles 1   nvim    :/home/haseebmajid/.nix-profile/bin/nvim
pane    dotfiles    1   0   :-  0   ~/dotfiles  :/home/haseebmajid/dotfiles 1   fish    :
pane    notes   0   1   :*  0   ~/notes :/home/haseebmajid/notes    0   fish    :
pane    notes   0   1   :*  1   ~/p/blog    :/home/haseebmajid/projects/blog    1   fish    :
window  dooit   0   :fish   1   :*  bd3d,309x72,0,0,0   :
window  dotfiles    0   :nvim   1   :*  babe,152x72,0,0,1   :
window  dotfiles    1   :fish   0   :-  babf,152x72,0,0,2   :
window  notes   0   :fish   1   :*  68da,309x72,0,0{154x72,0,0,3,154x72,155,0,4}    :

tmux: https://gitlab.com/hmajid2301/dotfiles/-/blob/bugs-gix/home-manager/programs/multiplexers/tmux.nix?ref_type=heads#L156-158

Any ideas what I’m missing ? Thanks

Are you failing to restore nvim or you are failing to restore nvim with its session? and what about other software such as “man” and htop?

I tried both man and htop. Initially htop was restored fine however man (and neovim) were not!

iMy resurrect file looked like:

pane    dotfiles    0   1   :*  0   nvim ~/dotfiles :/home/haseeb/dotfiles  0   nvim    :/home/haseeb/.nix-profile/bin/nvim
pane    dotfiles    0   1   :*  1   man cat ~/dotfiles  :/home/haseeb/dotfiles  1   man :/home/haseeb/.nix-profile/bin/man cat
pane    dotfiles    0   1   :*  2   htop ~/dotfiles :/home/haseeb/dotfiles  0   htop    :htop

So I manually changed it to remove the .nix-profiles folder and leave it like htop like so (scroll across to see the final column):

pane    dotfiles    0   1   :*  0   nvim ~/dotfiles :/home/haseeb/dotfiles  0   nvim    :nvim
pane    dotfiles    0   1   :*  1   man cat ~/dotfiles  :/home/haseeb/dotfiles  1   man :man cat
pane    dotfiles    0   1   :*  2   htop ~/dotfiles :/home/haseeb/dotfiles  0   htop    :htop

Then it worked!

EDIT: The following lines in my tmux config fixed it :slight_smile:

resurrect_dir="$HOME/.tmux/resurrect"
set -g @resurrect-dir $resurrect_dir
set -g @resurrect-hook-post-save-all 'target=$(readlink -f $resurrect_dir/last); sed "s| --cmd .*-vim-pack-dir||g; s|/etc/profiles/per-user/$USER/bin/||g; s|/home/$USER/.nix-profile/bin/||g" $target | sponge $target'

To add to this, I needed remove the bash variables from the strings in my tmux.nix to get it to work because tmux sanatizes the eval call to resurrect-hook-post-save-all.

So I was able to get this to work:

      let
        resurrectDirPath = "<example>";
        usr="user";
      in
...
        {
          plugin = resurrect;
          extraConfig = ''
          set -g @resurrect-strategy-vim 'session'
          set -g @resurrect-strategy-nvim 'session'

          set -g @resurrect-capture-pane-contents 'on'

          set -g @resurrect-dir ${resurrectDirPath}
          set -g @resurrect-hook-post-save-all 'sed "s| --cmd .*-vim-pack-dir||g; s|/etc/profiles/per-user/${usr}/bin/||g; s|/home/${usr}/.nix-profile/bin/||g" ${resurrectDirPath}/last | sponge ${resurrectDirPath}/last'
        } 
...

*the ellipse denotes necessary code is not present in the example above

If anyone else is struggling with this, I had to do the following to get it to work:

resurrect_dir="$HOME/.tmux/resurrect"
set -g @resurrect-dir $resurrect_dir
set -g @resurrect-capture-pane-contents 'on'
set -g @resurrect-hook-post-save-all "sed 's/--cmd[^ ]* [^ ]* [^ ]*//g' $resurrect_dir/last | sponge $resurrect_dir/last"
set -g @resurrect-processes '"~nvim"'

Hope this helps someone!

1 Like

as @Baitinq mentions also, I did the same with a script:

Hi, I’ve already tried all the solutions but none seems to work.

Here is my config:

{
  pkgs,
  lib,
  config,
  ...
}
: {
  options.tmux.enable = lib.mkEnableOption "Tmux";
  config = lib.mkIf config.tmux.enable {
    programs.tmux = {
      enable = true;
      keyMode = "vi";
      mouse = true;
      baseIndex = 1;
      clock24 = true;

      extraConfig = ''
        # Shift Alt vim keys to switch windows
        bind -n M-H previous-window
        bind -n M-L next-window

        # Visual mode keybind to act like vim
        bind-key -T copy-mode-vi v send-keys -X begin-selection
        bind-key -T copy-mode-vi S-v send-keys -X rectangle-toggle

        # Create new session with C-n
        bind C-n command-prompt -p "New Session:" "new-session -A -s '%%' -c '~'"

        # Open panes in current directory
        bind '"' split-window -v -c "#{pane_current_path}"
        bind % split-window -h -c "#{pane_current_path}"

        # Open windows in current directory
        bind c new-window -c "#{pane_current_path}"
      '';

      plugins = with pkgs; [
        tmuxPlugins.vim-tmux-navigator
        tmuxPlugins.yank
        tmuxPlugins.open
        tmuxPlugins.sensible
        tmuxPlugins.better-mouse-mode
        {
          plugin = tmuxPlugins.gruvbox;
          extraConfig = ''
            set -g @tmux-gruvbox 'dark' # or 'light'
          '';
        }
        {
          plugin = tmuxPlugins.resurrect;
          extraConfig = ''
            resurrect_dir="$HOME/.tmux/resurrect"
            set -g @resurrect-dir $resurrect_dir
            set -g @resurrect-hook-post-save-all 'target=$(readlink -f $resurrect_dir/last); sed "s| --cmd .*-vim-pack-dir||g; s|/etc/profiles/per-user/$USER/bin/||g; s|/home/$USER/.nix-profile/bin/||g" $target | sponge $target'
          '';
        }
        {
          plugin = tmuxPlugins.continuum;
          extraConfig = ''
            # Restore environment automatically
            set -g @continuum-restore 'on'
            set -g @continuum-save-interval '1'
          '';
        }
      ];
    };
  };
}

Can anyone help?"

So code stopped working (neovim restore stopped working) for some reason and I noticed $target file being created inside of the directory I was in at the moment of tmux session save.

here is a more simple and working version

set -g @resurrect-dir ${resurrectDirPath}
set -g @resurrect-hook-post-save-all ‘sed -i -E “s|(pane.nvim\s:)[^;]+;.*\s([^ ]+)$|\1nvim \2|” ${resurrectDirPath}/last’

with resurrectDirPath variable being the pathto my resurrect directory.
source can be found here.

For anyone else seeking a solution while using nixvim, and for whom the above did not work:

  plugins = with pkgs; [
    {
      plugin = tmuxPlugins.resurrect;
      extraConfig = ''
        resurrect_dir="$HOME/.tmux/resurrect"
        set -g @resurrect-dir $resurrect_dir
        set -g @resurrect-hook-post-save-all "sed -i 's/--cmd lua.*--cmd set packpath/--cmd \"lua/g; s/--cmd set rtp.*\$/\"/' $resurrect_dir/last"
        set -g @resurrect-capture-pane-contents 'on'
        set -g @resurrect-processes '"~nvim"'
      '';
    }
  ];

This seems to do the trick for me.

For anyone else for who all of the above did not work, this did work for me:

extraConfig =  ''
    <your-other-settings>
    set -g @resurrect-save-command-strategy 'ps'
    set -g @resurrect-hook-post-save-all 'sed -E "s|:/nix/store/[^ ]+/bin/nvim.*nvim-ruby'\'''([[:space:]]+([^[:space:]]+))?|:nvim \\2|" -i <full-path-to-resurrect-dir>/last'
    set -g @resurrect-processes '"~nvim"'
'';

I am not entirely certain why this works though. I had to do some funky stuff with the quotes because my tmux-resurrect files looked like this for neovim commands:

pane	programming	1	1	:*	1	v .	:/home/tim/nixos	0	nvim	:/nix/store/n081rbw0hcs7qbrzg5ndx1k0h3p4f1qy-neovim-unwrapped-0.10.2/bin/nvim --cmd lua vim.g.loaded_node_provider=0;vim.g.loaded_perl_provider=0;vim.g.loaded_python_provider=0;vim.g.python3_host_prog='/nix/store/3asx6fispwary7bvc6gwrk6k6b0mf673-neovim-0.10.2/bin/nvim-python3';vim.g.ruby_host_prog='/nix/store/3asx6fispwary7bvc6gwrk6k6b0mf673-neovim-0.10.2/bin/nvim-ruby' .

So to replace that last part with nvim . I had to include the single quote from nvim-ruby' near the end. I kept getting invalid octal escape errors when trying to source the tmux.conf file. Eventually I fixed it using magical combinations of quotes that eventually worked. This did made it so that any variables were not being included within the full string so the full path had to be used for the resurrect dir.