-
-
Notifications
You must be signed in to change notification settings - Fork 489
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
feat: add support for persisting user preferences using a default configuration in the REPL #2559
base: develop
Are you sure you want to change the base?
Conversation
Signed-off-by: Snehil Shah <[email protected]>
Signed-off-by: Snehil Shah <[email protected]>
Regarding |
I would think that a hard reset would only reset back to the state of the REPL at instantiation. So whatever is passed or used in the constructor, that should be restored. |
What about configuration then? What if the user wants to reset back to the very default settings (like deleting the configuration file) |
Hmm...I am not sure. I'd say let's punt on this. If a user wants to reset back to default settings, they can do as you say: namely, delete the configuration file. I don't think we need a command for doing this. |
Signed-off-by: Snehil Shah <[email protected]>
Currently, if a user loads a custom config, that is saved to the default config upon closing. Should this be expected behavior? |
I don't think this should be expected behavior. Simply because I load a config into the REPL does not mean that I want it saved as the default. It's fine to save it as the "last session" config, but not the default. |
By default I meant the last session config. Just to clear things up, by last session config do you mean |
I'm referring to this comment: #2510 (comment). Although, my mind may not be entirely clear on this, as we've iterated on what configs should be stored and my mental model may be outdated at this point. |
In short, it is not clear to me that what is loaded by default equals what state the settings were when the REPL last closed. |
...certain things make sense to persist and be the default next time around (e.g., themes?), but other things less so. E.g., if I temporarily disable auto-closing and forget to re-enable before exiting the REPL, I don't want to have to explicitly re-enable the next time I fire up the REPL. That is just a recipe for user confusion, as it forces them to remember what they did in the last session when starting a new session when certain REPL features no longer work. It's possible that we could explicitly give users the option to "restore" the last session on startup (e.g., similar to how some web browsers, such as Chrome, may ask you whether you want to restore your last browser session, reopening tabs, etc). |
I get your use case but it's more likely that if the user disabled auto-closing, they just don't want it. And them having to change all settings to their preferences everytime they boot up the REPL seems more annoying/confusing as it's pretty standard (in IDEs or any application) that once they change a setting, they want it that way. In short, it would be more confusing not saving by default as it would force a user to remember what they changed in the last session so they can change it back again to what they wanted everytime they enter the REPL. |
Why don't we avoid this discussion altogether and just prompt a user before exiting the REPL as to whether they want to save current REPL settings when the current REPL settings differ from what's on file? In short, punt the decision to the user. |
BTW: you'd still need a |
In short, here is a possible summary:
|
Signed-off-by: Snehil Shah <[email protected]>
@kgryte I decided to let them just use a key binding while exiting if they want to save preferences. This way we don't add any additional steps that the user probably wouldn't appreciate. Maybe we can add a command as well And I think we can figure out restoring a session upon a crash when we work on being able to save the entire REPL state along with variables etc, is that fine? |
Yes, that is fine. So long as in the meantime we are saving the current session settings while a REPL session is underway to a file, such as
Maybe instead, and only when settings have actually changed during the current REPL session,
When no settings have changed,
When a user opts not to save settings.
|
I am not a fan of having multiple keybindings for exiting the REPL. Having two is almost too many. Having three just creates confusion. |
Being explicitly prompted to save or affirming that one is okay navigating away from some page when changes have not been persisted is a common user interface pattern. Given that users are unlikely to be changing settings during every session, but once in a while, being explicitly prompted, without the additional cognitive overload of a separate keybinding, is a minor inconvenience at worst. A REPL is not an IDE or a typical application. It's very essence is for doing ephemeral things. So we don't always need to treat it as an IDE where a user explicitly navigates to a settings panel or updates a specific configuration file, where it is assumed that changing a setting results in persistence. In a REPL, most user actions assume the very opposite. And I don't think we should assume that simply because a user changed a setting (e.g., a theme), that this automatically means they want to live with this change forever more (i.e., to persist). So having a separate explicit prompt, independent of exiting keybindings, seems a reasonable compromise and a minor speed bump. |
When the user is inside a "profile" meaning they have a custom configuration in any of their parent directories, and then the user saves when exiting, do we update their custom configuration or update the default |
Good question. I think we need to remember the configuration file path of whatever configuration file was resolved and loaded on REPL startup. E.g., if we resolve a config in the current working directory, we should save to that file on exit. But oof. That is tricky and could potentially lead to some unexpected behavior if people move around directories with local configs, but, similar to |
But what if the configuration was loaded from a |
Ugh. 🐉 's everywhere. Sure, |
and also, should we prompt them to save after the second confirmation?
Because there is a possibility they might not want to actually quit so it's better to confirm if they are, before prompting them if they want to save..? |
If they don't want to exit, they can also just hit |
I don't know, I think it would make things confusing and the user might think ^C is for saving and not exiting? |
Okay. This is something we can always change later. |
Signed-off-by: Snehil Shah <[email protected]>
config.mp4 |
@Snehil-Shah Is it possible to avoid the second |
That is there for a reason, as it's not confirmed yet if the user wants to quit or stay. The prompt is there if they want to type again, or they can use ctrl+c again to quit (and if applicable save) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, exiting the REPL via quit()
will not prompt the user for whether they want to save their preferences. Since this command is not described as "force quit", this behavior seems unintuitive to me and I would argue that we should be consistent and have it behave the same as if I would exit via one of the other ways when greeted with:
To exit, enter ^D or ^C again or enter quit().
There is also no indication in the above message that ^D
/ ^C
behave differently from typing quit()
.
In my view, the current behavior of quit()
only makes sense if we had an additional saveAndQuit()
command as suggested above. But personally, I think it's not too much of an inconvenience if one is prompted when exiting via quit()
for whether one wants to save preferences, as this won't be the case that often.
PR otherwise looks good to me!
@Planeshifter Agreed, the user should be prompted the same way when using the |
var mergeOptions = mergeFcn({ | ||
'level': 2 // to merge individual settings and themes | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am still skeptical if this is the best way to do this. For context, after resolving the options from the configuration file, I am merging it with the defaults()
, till level 2. My main concern being, we might not always want to merge all things till level 2 (and things like the input and output stream properties might also get wrongly merged creating corrupted data), should we have a custom merger (similar to the validate
function)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you be able to show in code what you are concerned about? In particular, can you provide example config which gets merged and creates "corrupted" opts
? Would help me, as I am having trouble visualizing the potential issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the defaults()
also has opts.input
which is a stream object (with many nested properties at diff levels), say someone makes a custom configuration, with an input
option to a different object, they can potentially inject and corrupt the stream object at some levels because of the merge. We do have a list of PERSISTABLE_OPTIONS
(L94), that we are using to allow saving only those specific properties that we want to persist. Maybe we can use it to also enforce that only the PERSISTABLE_OPTIONS
can be loaded through a custom configuration. But again, this isn't future-proof, as it can be something else other than streams as well that we might later support.
Currently, in the validate
function, we manually check if the given options (at REPL instantiation) has the prop or not (for a property, say settings
), if yes, we merge or replace the default with the given property manually for each option. So, should we do something similar to merge 1) defaults, 2) configuration, and 3) REPL options into a final opts
object?
Resolves #2510
Description
This pull request:
~/.stdlib/repl.json
file.Related Issues
This pull request:
Questions
We are not persisting:
Is this okay?
Other
No.
Checklist
@stdlib-js/reviewers