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

[REQUEST] Remember tabs between sessions #241

Open
Sonico98 opened this issue Dec 14, 2022 · 11 comments
Open

[REQUEST] Remember tabs between sessions #241

Sonico98 opened this issue Dec 14, 2022 · 11 comments
Labels
enhancement New feature or request

Comments

@Sonico98
Copy link

It would be great if joshuto could remember which tabs were opened the last session, and restore them when opening the file manager again.

@kamiyaa kamiyaa added the enhancement New feature or request label Jan 4, 2023
@DLFW
Copy link
Contributor

DLFW commented Apr 18, 2023

Just an idea:

  1. We add a “placeholder” %t for shell/spawn arguments that expands to a list of the current directories of all open tabs
  2. We add a command that reads a list of directories from an external script and opens them as tabs

With that, the user can:

  • Write a script that saves the current set of tabs to a certain text-file and bind it to a key-chord
  • Write a script that reads from that files and bind it to another key-chord to recover the tab-set

Additionally, the user can:

  • Write a script that saves the current set of tabs to a file whose name can be chosen (for example with rofi or dmenu)
  • Write a script that opens dmenu or rofi where one can select one of these stored “sessions” (tab-sets) and Joshuto would open them

This second thing would also be really useful for me. There are certain directory-sets I often open at the same time.
This would allow me to prepare such dir-lists in text files and quickly choose a tab-set with rofi.

The command for opening tabs from a list could have an argument switch to choose if the current tabs shall be closed/replaced, or kept open (and the new dirs would open in additional tabs/appended).

That would also allow to use any other source of dir-lists to open a corresponding tab-set.

This solution would not include an “auto-save” when closing Joshuto though.
Maybe we could add a general feature to execute a list of commands to be executed when opening and another one to be executed when closing later on?

Opinions?

@Sonico98
Copy link
Author

It sounds useful when thinking about the rofi script for managing sessions. However, it sounds like a bit of a pain from the development side (speaking for you and kamiyaa, as I don't know Rust), and overly complicated for new users to set up (they're already finding it dificult to figure out how to implement previews).
Also IMHO the autocommands on opening and closing would be mandatory because we as humans tend to make errors, and I can see users forgetting to save their tabs every time they want to close the editor.

If you decide to go the script route, maybe it's possible to ship joshuto with the scripts in the ~/.config folder by default? That way users would have it a bit easier to set up. Also I may be able to help with the documentation.

Of course I'm just another user, so @kamiyaa's opinion is much more important.

@DLFW
Copy link
Contributor

DLFW commented May 4, 2023

it sounds like a bit of a pain from the development side

No, I don't think that this would be a particularly hard one. But thanks for the sympathy. 😉 ❤️

overly complicated for new users to set up

Hm, yeah. You have a point there. I might argue that this is not a very important feature that needs to work out-of-the-box, but still, you have a point there...

But then maybe a more important question about the resulting user-workflow:

You want that Joshuto open the last set of tabs automatically and every time Joshuto is started? For me, that would be super-annoying. I would - as a new user - expect to just see the working dir and in most cases, that's also the dir I'm interested in. (Beside the fact that I mostly have multiple Joshutos open and it would not help me personally at all to restore the tabs from the last closed session. That might be any random set of tabs...)

In your idea, would there also be a tab for the working dir when starting Joshuto? So would Joshuto open with all tabs from the last closed session plus one for the cwd?

I could maybe think about a restore-command, but I have my doubts with this “auto-restore”. Do you know how other file managers (ranger, lf) do this?

@Sonico98
Copy link
Author

Thinking about it, you're right.
The way I use joshuto is pretty much the opposite to the way you do: most of the time, as soon as I open a terminal, I open joshuto as well, and try to keep a single session in which I open multiple tabs. Then, if I have to execute some other command in the directory joshuto is currently at, I have a keybind set to open a new kitty tab in said directory.
Of course when thinking about the feature I didn't really think about some other way to use the file manager, and restoring the tabs every single time I open joshuto makes sense only when using the program like I mentioned above.

So, this is how I imagine how the feature could work now. This will probably be just expanding your initial idea more :P

  • Implement your idea, where users would have a script that writes the currently open tabs to a file, and overwrite it if it exists.

  • Implement a way to always execute a command when exiting joshuto (e.g to run a script that writes the tabs file every time the file manager is closed). In the configuration file, there could be a boolean to enable or disable the auto-execute on exit, and a variable that points to the script file to execute.

  • The user can also set a keybind to run said script at any given time. Alternatively, the user could assign a separate script that asks the user how to name the file. This would allow storing multiple sessions

  • Add a command that takes multiple directories as arguments and opens them in new tabs.
    It would have an optional parameter to read a script's output and open those directories (--from-script maybe?).
    This command should also take an optional parameter to discard all currently open tabs and replace them with the ones found in the file (--discard-current maybe?). This means that by default, the command will keep all currently open tabs, and append the new ones.

  • Assign said command to a keybind. It'll be up to the user to modify the configuration file and use the --discard-current option. Of course a user could have 2 different keybinds, one to discard the cwd and another to not discard it.

This way:
1 - The user could run on demand a script that opens rofi/dmenu and shows all possible sessions.
2 - A session with a fixed name would always get saved automatically.
3 - The user could also run on demand a script that simply opens the session that always gets saved automatically.
4 - Joshuto would always open the cwd. It'll be up to the user to discard that tab or not when restoring a session (if the user decides to restore a session, that is).
5 - The user could set keybinds to open certain directories without having to store a session file.

The command should open all directories that exist as tabs first, and then inform the user if there were problems (e.g some dir doesn't exist anymore).
I'm not sure what to do if a tab present in a saved session is already open. Would you duplicate it?
What do you think?

I could maybe think about a restore-command, but I have my doubts with this “auto-restore”. Do you know how other file managers (ranger, lf) do this?

I haven't really used other file managers, but ranger seems to always restore automatically ranger/ranger@b327b73. Also, they store their tabs in a stack and restore the oldest saved tabs first.

@DLFW
Copy link
Contributor

DLFW commented May 14, 2023

I think that goes in a good direction. If I would pick this up (that would not be in the next ~6 weeks at least, maybe later... too busy and another Joshuto feature comes before in my mental queue - a nicer tab-representation in the top-bar), I would still clear my mind about a few details first.

For example, I would like to avoid overly specific commands and command-arguments to Joshuto. Instead, I would like to add some "command chaining", so that a key-bindings can execute a sequence of commands. And I would like to add a general feature to provide various additional data as parameters to shell and spawn commands (not only %s) with some simple template-engine.

That would allow for keybindings like these:

keymap = [
  {
    keys = [ " ", "s", "s" ],    # session save
      command = [
        "shell save-session.sh {tabs}",     # {tabs} gets substituted with the list of dirs of the open tabs
      ]
  },
  {
    keys = [ " ", "s", "a" ],    # session append
      command = [
        "shell pick-a-session-w-dmenu.sh",
        "new_tab {stdout}"      # {stdout} gets substituted with the stdout of the last `shell` command
      ]
  },
  {
    keys = [ " ", "s", "r" ],    # session replace
      command = [
        "shell pick-a-session-w-dmenu.sh",
        "close_tab --all",       # --all switch is missing and needs to be added
        "new_tab {stdout}"      # {stdout} gets substituted with the stdout of the last `shell` command
      ]
  },
  # With that, storing and saving to a default-file is trivial,
  # and something like a dmenu/rofi tab-switcher now comes for free:
  {
    keys = [ " ", "t", "j" ],    # tab jump
      command = [
        "shell pick-entry-w-dmenu-and-print-index.sh {tabs}",
        "tab-switch-index {stdout}"
      ]
  },

]

So, your issue would be solved by a couple of more generic features, playing together.

(This would also give a clean and easy base to solve #208 and if Joshuto would track the history of visited directories and can provide that as a parameter to shell, it may help for issues like #268.)

Some details may come into our way though. For example, I'm not sure if implementing close_tab --all would create any problems as an application state without any tab does practically not exist right now.

Not sure how much time all of that may need. My capacities are limited. 🙃

The execution of commands “on start” and “on quit” would be another feature to complete your use case. I don't think that I would take them up any time soon. Let's see.

I'm not sure what to do if a tab present in a saved session is already open. Would you duplicate it?
What do you think?

Yes, with the logic above and by the law of simplicity, I would just stupidly open all tabs of that session.
One may add a feature like close_tab --duplicates later and put it into the command-chains of the key-mappings.

...but ranger seems to always restore automatically...

Hmm, I just tried it quickly and at least there is no restore on startup by default. I personally think that handling this by configuration somehow as we discussed is good choice. Avoids feature creep.

OK, these are just my thoughts. If I pick this up, I will add a little to-do list.

@Sonico98
Copy link
Author

Sounds good!
But yes, would definitely take some time to implement. I can only wish you luck for now 😅 and thanks.

@kamiyaa
Copy link
Owner

kamiyaa commented Aug 28, 2023

Hey, sorry for not looking at this earlier!
Seems to have been buried in all the different issues.
I've been busy and haven't had the time to look over everything.
I'll get back to this once I have some time to sit down and go over the designs proposed 👍

@kamiyaa
Copy link
Owner

kamiyaa commented Aug 28, 2023

I like the idea that @DLFW proposed of chaining commands.
This would make things much simpler on the dev side of things; rather than creating multiple commands that do the same things slightly differently, by chaining commands, we can have more composability.

It may also solve your issue @Sonico98 with opening specific directories.
Instead of having a "restore on open" behaviour, maybe it could just be a

  {
    keys = [ "a", "b", "c" ],
      command = [
        "new_tab path/to/dir1",
        "new_tab path/to/dir2",
        "new_tab path/to/dir3",
        "new_tab path/to/dir4",
      ]
  },

or does this not cover your use case?

@DLFW I can take on implementing command chaining if you are cool with that.
Will definitely have breaking changes in the config 👍

@DLFW
Copy link
Contributor

DLFW commented Aug 28, 2023

Hi @kamiyaa!

I can take on implementing command chaining if you are cool with that

I'm totally cool with that! Very much appreciated! 😊

Will definitely have breaking changes in the config

Hm, if we only accept lists, yes. I don't know serde that well, but I guess it would be an option to allow both, a string or a vector of strings as command. I would guess that that's possible by using an enum there. One could also allow for command (str) and commands (vec<str>) to avoid a breaking change. But maybe that adds too much clutter to the app. One also needs to check then that exactly one of both variants is used.

Side note 1:
It would also be a good thing to not issue a full app cycle (with a redraw) for each command in a chain, but only after the last one. I think at the moment, both are handled in one linear loop.

Side note 2:
When #370 came in, I started to think that it could make more sense to allow such custom commands in a macro-like way, where the actual chaining could take place inside these custom-commands. Then, key-chords could still be just a binding to a custom-command which calls the other commands. Would be a cleaner solution. But I think #370 is implemented not very generic and adding support for “macros” could be way more effort than just the command-chaining for key-chords.
Just a thought....

Have fun! Looking forward to it!

@kamiyaa
Copy link
Owner

kamiyaa commented Aug 29, 2023

Side note 1:
It would also be a good thing to not issue a full app cycle (with a redraw) for each command in a chain, but only after the last one. I think at the moment, both are handled in one linear loop.

Yeah, good point. I'll keep that in mind

Side note 2:
When #370 came in, I started to think that it could make more sense to allow such custom commands in a macro-like way, where the actual chaining could take place inside these custom-commands. Then, key-chords could still be just a binding to a custom-command which calls the other commands. Would be a cleaner solution. But I think #370 is implemented not very generic and adding support for “macros” could be way more effort than just the command-chaining for key-chords.
Just a thought....

I think these two are kind of separate? One is mapping :x to :doX,
the other is mapping ctrl+a to doX, doY.
Or am I missing something here?

@DLFW
Copy link
Contributor

DLFW commented Aug 29, 2023

I think these two are kind of separate? One is mapping :x to :doX,
the other is mapping ctrl+a to doX, doY.
Or am I missing something here?

Hm, maybe it's just a knot in my brain. For me, the first is for defining custom-commands, currently just mapping :foo to :bar, but basically enhancing the list of available commands. The latter maps a key-chord to some command. So my thought was, why not allowing those custom-commands to do more than just call one other command, like command sequences and conditional commands, and then allowing to bind key-chords to any kind of command (custom or not). That would enable users to invoke a command-chain in both ways, :myCommand and x-y-z. It would also feel cleaner in architecture for me. But anyway, it may come with too much overhead/effort. As long as everybody is fine with just using key-chords to invoke such command-chains, and does not want a custom-command for such things, we're good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants