-
Notifications
You must be signed in to change notification settings - Fork 183
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
Allow suppressing UI blocking dialogs #2546
base: main
Are you sure you want to change the base?
Conversation
plugin/tooling.py
Outdated
sublime.error_message("The clipboard content must be a URL to a package.json file.") | ||
msg = "The clipboard content must be a URL to a package.json file." | ||
status = "Clipboard must be a URL to package.json" | ||
notify_err(msg, status) |
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 honestly don't think we are gonna accept any of these changes (not in this form). It doesn't make sense to just blindly change all instance of modals. Especially in this file it's a case of explicit user action and it makes sense to report the error in the dialog (the user won't be surprised by it) instead of having to dig for more info in the console or potentially miss the status field message.
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 users to whom it makes sense to see these kind of dialogs or who worry about missing a status field message can simply continue to use the defaults. Or they can set the regular dialog suppression setting, but leave the error setting on.
So this setting is simply not for them, but for the other group who have never had an issue of missing a status field message (by the way, you could add ❗ symbol if you think this is a very important message, that's harder to miss), don't see the point of a blocking modal for a simple error message. For them these bad interface design patterns don't make sense because they do not reflect the importance of the messages.
explicit user action and it makes sense to report the error in the dialog (the user won't be surprised by it)
The issue here isn't surprise, but, requiring additional user action for no good reason.
What's your alternative - group/code all the messages and ask the user to provide a list of those that should be suppressed like in lints?
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.
In this case the error is a direct response to user action so it's fine to present a dialog that can be dismissed easily with a single button press.
If you don't like dialogs so much then maybe just create a plugin that overrides sublime.error_message
(if that's possible but I think it should)? It's not sensible to expect every package to introduce an option to switch between error dialogs and status field messages.
For some cases I would also prefer to not have dialogs but as discussed in related conversation, there is not necessarily a better way due to ST's limitations.
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.
In this case the error is a direct response to user action
Showing a status message is also a direct response
so it's fine to present a dialog that can be dismissed easily with a single button press.
It's not fine, you need to provide value to the user to demand action from every single user (this is an optional config, disabled by default, so most of the users will continue to suffer through needless actions the way you want them), and in this case you don't - this is simply not an important error message.
Also for some of these cases a blocking message prevents a much better UI: for example, in the next error that appears after theparse VSCode package JSON
action instead of a blocking URL must end with 'package.json'"
it'd be better to show the same input field again with the old user value and show a non-blocking error message (e.g., in the status bar or maybe in some popup) so you don't lose valuable user input data and allow for the next user action to be error correction instead of UI unblocking
If you don't like dialogs so much then maybe just create a plugin that overrides sublime.error_message (if that's possible but I think it should)?
I don't like needless user actionn, not dialogs, so I don't want to override all the error messages, just the ones that aren't important. None in your plugin are, so I'd be fine with overriding all of them.
It's not sensible to expect every package to introduce an option to switch between error dialogs and status field messages.
I don't expect that, there are plenty of plugins that don't show dialogs, or use less intrusive notifications, and this is a PR for a single package optionally supressing unimportant error messages, not for Sublime core changing everything
Here is my opinion:
|
Yes, should be possible. Just load settings via |
show became suppress, so dialogs reversed with status messages
Updated the PR per the following:
switched to suppress by default
Left the setting given that it's suppressed by default, also re the extra button: Sublime still hasn't learned to properly roundtrip user configs, and this button would change files in the User folder, thus breaking subtle formatting, so I'd just leave it in the currently less convenient format
Added a shorter text, otherwise it might not fit
switched
They address @rchl concern of users not noticing notifications, |
I do think that there will be a good portion of users that will not notice something showing up in the status field for a few seconds. Or if they do notice something changing, they might not realize what has changed (if the status field is busy). So as I said, I don't think that status messages are a good solution in general. I suppose when user is doing an explicit action then he/she might be more looking for some feedback/result and might pay more attention. If the user doesn't expect anything then it might be easy to miss status change completely. |
31a5fd2
to
5876ba0
Compare
fallback sublime functions
86acd06
to
88f4c62
Compare
from .settings import userprefs | ||
if userprefs().suppress_error_dialogs: | ||
if window: | ||
window.status_message(status) # print short message to statusbar |
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 don't think we need those inline comments because it's obvious from the method name.
@@ -39,3 +39,33 @@ def exception_log(message: str, ex: Exception) -> None: | |||
def printf(*args: Any, prefix: str = 'LSP') -> None: | |||
"""Print args to the console, prefixed by the plugin name.""" | |||
print(prefix + ":", *args) | |||
|
|||
|
|||
def notify(window: Optional[sublime.Window], message: str, status: str = 'LSP: see console log…') -> None: |
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.
Should be sublime.Window | None
I'd say status
doesn't need a default value if it given in each function call anyway. Maybe rename to status_message
"""Pick either of the 2 ways to show a user notification message: | ||
- via a detailed console message and a short status message | ||
- via a blocking modal dialog""" | ||
from .settings import userprefs |
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.
Can this be a global import at the top of the file? If there is an import cycle it might be necessary to refactor / move some code around between the files.
sublime.message_dialog(message) | ||
|
||
|
||
def notify_error(window: Optional[sublime.Window], message: str, status: str = '❗LSP: see console log…') -> None: |
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 think we don't need 2 separate functions. Current use of sublime.mesage_dialog
and sublime.error_message
looks pretty arbitrary. I think all of them are errors, so I'd use only sublime.error_message
. If the severity is important it could be another parameter severety
, but I don't think that's necessary. notify_error
sounds like the appropriate function name, so I would remove the other function.
else: | ||
sublime.status_message(status) |
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 assume you used this to satisfy the type checker. I believe window = None
is only a theoretical case, and if there is no (active) window, I think we don't need to log anyway. So you can just put
if not window:
return
at the top of the function.
@@ -295,12 +296,13 @@ def start_async(self, config: ClientConfig, initiating_view: sublime.View) -> No | |||
"Re-enable by running \"LSP: Enable Language Server In Project\" from the Command Palette.", | |||
"\n\n--- Error: ---\n{1}" | |||
)).format(config.name, str(e)) | |||
status = f"LSP: Failed to start {config.name}… See console" |
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.
Do we need the LSP:
prefix in the status messages? It should be obvious if there is either the config.name
or when it was something directly triggered by the user.
Add 2 user configuration options that would allow to suppress the attention-demanding UI blocking dialogs, instead redirecting warnings/errors to a status message and the full console message
Simple way to close #2545 while preserving the current defaults
Though not all modals are affected since some are invoked by the lsp_utils dependency
Question: is it possible to make that dependency respect config options from this plugin? Or do dependencies "by design" ignore their clients?