joshuto
joshuto copied to clipboard
[REQUEST] Remember tabs between sessions
It would be great if joshuto could remember which tabs were opened the last session, and restore them when opening the file manager again.
Just an idea:
- We add a “placeholder”
%t
for shell/spawn arguments that expands to a list of the current directories of all open tabs - 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?
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.
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. :wink: :heart:
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?
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@b327b7352e10909d4713d3c802c4c34945523e2b. Also, they store their tabs in a stack and restore the oldest saved tabs first.
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.
Sounds good! But yes, would definitely take some time to implement. I can only wish you luck for now :sweat_smile: and thanks.
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 :+1:
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 :+1:
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!
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 https://github.com/kamiyaa/joshuto/pull/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 https://github.com/kamiyaa/joshuto/pull/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?
I think these two are kind of separate? One is mapping
:x
to:doX
, the other is mappingctrl+a
todoX, 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.