Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multiple Sessionx support #14547

Open
ColinKennedy opened this issue Apr 14, 2024 · 8 comments
Open

Add multiple Sessionx support #14547

ColinKennedy opened this issue Apr 14, 2024 · 8 comments

Comments

@ColinKennedy
Copy link
Contributor

ColinKennedy commented Apr 14, 2024

Is your feature request about something that is currently impossible or hard to do? Please describe the problem.
This came up while handling SessionWritePost. #14242 (comment).

If two plugins, plugin A and B, wish to add their settings to a Sessionx.vim after SessionWritePost is triggered, you get into some funky scenarios where neither plugin knows if they're allowed to create the Sessionx.vim from scratch or if it should append.

If a plugin deletes then the execution order...

  • plugin A
  • plugin B

Would result in a Sessionx.vim containing only the contents of plugin B. And reversed,

  • plugin B
  • plugin A

Would only have plugin A's contents.

If the plugins are set to append then you're in a situation where a plugin might write its contents to the same Sessionx.vim 2+ times by accident

:mksession

  • plugin A
  • plugin B

:mksession!

  • plugin A
  • plugin B
  • plugin A
  • plugin B

Describe the solution you'd like
If the Session.vim logic could be "execute all Sessionx*.vim files" then each plugin can have their own dedicated SessionxPluginA.vim and SessionxPluginB.vim, which then can safely overwrite the contents of without accidentally stepping on anyone else's toes.

Also if possible it'd be nice to allow Sessionx*.lua for Neovim users. But this isn't that big of a deal because we can just lua << EOF ... EOF the SessionxPluginA.vim file.

Describe alternatives you've considered
Currently it's possible for plugin A and B to go into a single Sessionx.vim but it would require some sort of "import guard" like "don't clear the file, only clear lines # -- Start -- my plugin A to line # -- End -- my plugin B. Every plugin would need their own logic to do this, which is a lot of bookkeeping, I think.

@chrisbra
Copy link
Member

So like this?

diff --git a/src/session.c b/src/session.c
index eea57a233..9d3f58b7f 100644
--- a/src/session.c
+++ b/src/session.c
@@ -982,11 +982,12 @@ makeopens(
            goto fail;
     }

-    // Lastly, execute the x.vim file if it exists.
-    if (put_line(fd, "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"") == FAIL
-           || put_line(fd, "if filereadable(s:sx)") == FAIL
-           || put_line(fd, "  exe \"source \" . fnameescape(s:sx)") == FAIL
-           || put_line(fd, "endif") == FAIL)
+    // Lastly, execute the x*.vim file if it exists.
+    if (put_line(fd, "for s:sx in glob(expand(\"<sfile>:p:r\").\"x*.vim\", 0, 1)") == FAIL
+           || put_line(fd, "  if filereadable(s:sx)") == FAIL
+           || put_line(fd, "    exe \"source \" . fnameescape(s:sx)") == FAIL
+           || put_line(fd, "  endif") == FAIL
+           || put_line(fd, "endfor") == FAIL)
        goto fail;

     ret = OK;

@Shane-XB-Qian
Copy link
Contributor

Shane-XB-Qian commented Apr 19, 2024 via email

@ColinKennedy
Copy link
Contributor Author

ColinKennedy commented Apr 19, 2024

I'll try that diff and see if it fits my use case. Just going by sight, it does look like it will do exactly what I need.

is it possible you use different sess name for each of them?

I'm not sure what you're asking here exactly but if you mean "do you have multiple sessions for a single directory" then no, I use only one session per directory.

On disk:

- ~/
    - repositories/
        - something/
            - Session.vim
            - SessionxPluginA.vim
            - SessionxPluginB.vim
        - another/
            - Session.vim
            - SessionxPluginA.vim

If I ever really needed different sessions I guess I could make an inner directory to keep them all.

- ~/
    - repositories/
        - something/  <-- Needed .sessions folder because there's multiple
            - .sessions/
                - session_a/
                    - Session.vim
                    - SessionxPluginA.vim
                    - SessionxPluginB.vim
                - session_b/
                    - Session.vim
                    - SessionxPluginB.vim
        - another/  <-- No .sessions folder needed because there's only one
            - Session.vim
            - SessionxPluginA.vim

That said a directory structure like this is probably better suited for a plugin or bash to manage. Just the multiple x*.vim should be enough. I'll give it a try over the weekend to see if it suits my use-cases. (It should)

@ColinKennedy
Copy link
Contributor Author

I tried this out and was surprised - Vim doesn't appear to keep buffer numbers consistent between mksession and loading the buffers back with vim -S. For example if I made two vertical splits, the resulting bufnr() each are 3, 1, 2. Then I load the same session back up and the buffers restore as bufnr: 1, 3, 2. I could understand window IDs being unknowable perhaps. And since Session.vim files are of course vim scripts that could someone could :source so you wouldn't expect consistency there. But if a user calls Vim from scratch or sources the script after :%bwipeout! I would've expected the buffer numbers to be consistent.

Without a consistent buffer number I'm not sure how I would implement things like "save and restore this terminal buffer's highlight groups" since the bufnr() is able to accidentally change. Is what I'm describing a bug or am I meant to save and restore data without using buffer or window numbers? If it is a bug, I have a repro and can make a separate ticket.

@chrisbra
Copy link
Member

I think buffer numbers where never meant to be persistent across sessions. You should not rely on stable buffer numbers even so we have fixed a few bugs in the session creation code.

@ColinKennedy
Copy link
Contributor Author

If not buffer numbers, what would plugin authors looking to take advantage of session support use to consistently target their buffers? I suppose someone could include localsoptions in 'sessionoptions' and work backwards from buffer-local variables. That seems like it would be a lot of effort.

@chrisbra
Copy link
Member

Why do you need stable buffer numbers? You should care about the buffers being loaded, not about what exact number those buffers use. In othre words what do you need those numbers for, that you cannot already do with those buffers already?

@ColinKennedy
Copy link
Contributor Author

ColinKennedy commented Apr 21, 2024

It depends on what the buffers do. Maybe we don't need stable buffer numbers. That said I have some plugin use-cases that I think could benefit unless there's a better alternative. "Purposeful" buffers typically come up in 3 classes of (Neo)vim plugins:

Paired Buffers

Buffers/Plugins that are meant to display or interact with another buffer in some meaningful way. Some examples could be

These buffers aren't just meant to load, they're meant to "sync" to another buffer in some way. It depends heavily on what the plugins does of course but I'd imagine you'd want session description that includes

A. Where is the plugin-related buffer
B. Which buffer(s) does the plugin need to care about.

And if the plugin cannot work simply by loading, I think the Sessionx.vim would need to have an answer to A and B and call some code for the plugin to work.

Initialized Buffers

Buffers/Plugins that, once initialized, can function as independent buffers. But that initialization is still needed as the plugin author may or may no store all of that buffer's relevant data in Session-compatible ways. This was my starting point. I wanted to make toggleterm.nvim play better with sessions, which it currently doesn't.

Dashboard-ish Buffers

These buffers/plugins may use one or even multiple buffers in sync at the same time to achieve some goal. Ironically, despite these plugins being typically pretty complicated, in theory they should be easiest to session-ify because their initialization usually just needs a consistent $PWD which the user already has. The Sessionx.vim file would just need to call some :DoThePlugin entry point, no buffer number or anything needed. Though another issue does come up - When :mksession is called, Vim saves the "dashboard plugin" windows / buffers to the Session.vim. Those windows and buffers are uninitialized when the user later vim -S Session.vim. The zombie windows are already present before any Sessionx.vim can call :DoThePlugin which tends to lead to weird result. I thought I read once there's a way to mark buffers / windows so that Sessions won't try to save them to the Session.vim. That would avoid this issue but I can't remember it right now.

If I have a set of favorite plugins that fall under "Paired Buffers" or "Initialized Buffers" and I want to add session-support myself to them, what is the consistent method that I can use to add do it? Ideally I would want something that I can write for my own plugin and then let other plugin authors know "by the way, your plugin could be supporting sessions. Here's how I did mine (link to the diff). Would you be open to a PR?"

I hoped to do that by quickly identifying the buffers via buffer number for a start but maybe there's another, better way. Do you have something in mind?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants