-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add toggle & togglelocal command #3783
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
Conversation
runtime/help/commands.md
Outdated
| * `setlocal 'option' 'value'`: sets the option to value locally (only in the | ||
| current buffer). This will *not* modify `settings.json`. | ||
|
|
||
| * `toggle 'option'`: toggles the option to `on/off`. See the `options` help |
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.
Just "toggles the option on/off"?
runtime/help/commands.md
Outdated
| current buffer). This will *not* modify `settings.json`. | ||
|
|
||
| * `toggle 'option'`: toggles the option to `on/off`. See the `options` help | ||
| topic for a list of options you can toggle, only works with `on/off` options. This will modify your |
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 options help refers to their values mostly as true and false, not on and off... Instead of this entire sentence "See the...", maybe just "Only works with boolean options"?
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.
Seems good, I'll change it.
Your comment made me wonder, maybe we could improve the toggle suggestions - i.e. when the user types toggle and hit tab the options that show up as suggestions are only boolean options. You think it would be a good idea? Maybe it's a problem for another PR, it could be done also for setlocal.
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.
Surely sounds like a good idea.
Side note: I've just tried using setlocal for a global-only option (infobar), and (besides the fact that it shows up among suggestions), the error displayed after setlocal infobar off is: Invalid option. It would be nice to make it more informative / less confusing, to make it clear why it is invalid in this case.
Side note 2: I've just taken a glance at the code in OptionValueComplete(), what a mess.
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.
Ye, I got confused plenty of times as well with settings code in general.
Starting with, a setting can be global or local but then we have GlobalSettings map[string]interface{} at first sight I'd say its a list of global-only settings, but it's, in fact, a list of all settings. Inside there's a list of settings that should never be globally modified. Why not call it just Settings or AllSettings?
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.
Surely sounds like a good idea.
Thinking in advance I could already create a function isBooleanOption(opt) booleanto use on toggleCmd & toggleLocalCmd and in the future on the suggestion logic, wt do you think?
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'm not sure what for.
|
Made changes base on your feedback. |
Thanks. It's better to squash them into the first commit. Fortunately github is capable of displaying diffs between force-pushes (even though is not as good at that as gerrit, for example), so there is little value in keeping them in a separate commit, it only clutters the commit history. Splitting changes into separate commits is useful not in such cases, but in cases when those changes are actually logically separate, so that splitting them actually makes review easier (for example, changing the order of the existing options in the documentation, which you've done, would make sense to do in a separate commit).
You mean that not all users are programmers and know what "boolean" is? Well, OTOH it sounds the least mouthful... We might clarify it a bit, e.g.: "...Only works with boolean options, i.e. options with values |
Yes
That may answer my question, maybe "boolean" is indeed friendly |
cc5927c to
0046b74
Compare
runtime/help/commands.md
Outdated
|
|
||
| * `setlocal 'option' 'value'`: sets the option to value locally (only in the | ||
| current buffer). This will *not* modify `settings.json`. | ||
|
|
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.
Just noticed (thanks to git show): unneeded trailing spaces added here.
runtime/help/commands.md
Outdated
| This will modify your `settings.json` with the new value. | ||
|
|
||
| * `togglelocal 'option'`: toggles the option true/false locally | ||
| (only in the current buffer). Only works with boolean options. |
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.
nit: I'd split the lines this way, to keep the lines width more or less the same as in the surroundings (i.e. not too wide, not too narrow):
diff --git a/runtime/help/commands.md b/runtime/help/commands.md
index ad5ba7db..fde3a4e0 100644
--- a/runtime/help/commands.md
+++ b/runtime/help/commands.md
@@ -72,12 +72,12 @@ quotes here but these are not necessary when entering the command in micro.
* `setlocal 'option' 'value'`: sets the option to value locally (only in the
current buffer). This will *not* modify `settings.json`.
-* `toggle 'option'`: toggles the option true/false. Only works with boolean options.
- This will modify your `settings.json` with the new value.
+* `toggle 'option'`: toggles the option true/false. Only works with boolean
+ options. This will modify your `settings.json` with the new value.
-* `togglelocal 'option'`: toggles the option true/false locally
- (only in the current buffer). Only works with boolean options.
- This will *not* modify `settings.json`.
+* `togglelocal 'option'`: toggles the option true/false locally (only in the
+ current buffer). Only works with boolean options. This will *not* modify
+ `settings.json`.
* `reset 'option'`: resets the given option to its default value
runtime/help/commands.md
Outdated
| * `toggle 'option'`: toggles the option true/false. Only works with boolean | ||
| options. This will modify your `settings.json` with the new value. | ||
|
|
||
| * `togglelocal 'option'`: toggles the option true/false locally(only in the |
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.
nit: missing space before parenthesis. :)
|
@dmaluka lacking anything? |
Last time I checked, just this comment: #3783 (comment) :) |
I've read #3783 (comment) and force pushed a patched version (I thought). I wonder how I failed to add a space. My bad 😞 |
internal/action/command.go
Outdated
| curValBool, ok := curVal.(bool) | ||
| if !ok { | ||
| InfoBar.Error("Not a boolean option") | ||
| return | ||
| } |
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 can remember #3021 (comment) 😉
Is there really the need to limit the (local) toggling to boolean options, since we could cycle through the other as well?
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.
cycle through the other
What other means here? Every option?
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.
Every option isn't possible, since we've integers and custom strings as well, but OptionChoices and colorscheme are additionally toggle-able...at least from my perspective.
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.
Erm, from my POV, a toggle would be on/off. I think the only non-boolean toggleable options are fileformat and helpsplit from OptionChoices.
Aside from naming, I don't think creating a cycling command would be useful. We could make options with exactly two values toggleable, though.
Going further, we could enhance RegisterCommonOption and RegisterGlobalOption to accept option choices directly (and other verifications?).
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.
Cycling through colorschemes with a command/keybinding might be nice but I agree that wouldn't really be called "toggling" any more.
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.
Just out of curiosity, what's the use case?
Cycling through all the colorschemes is something you do occasionally to either pick the one you like the best or to check that they all work as expected. I know it can be done in a plugin but having it built-in could help new users pick a colorscheme.
I'm not sure if it is worth implementing, but if it is I definitely think it shouldn't be part of the toggle command.
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.
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 can remember #3021 (comment) 😉
Actually prior to that comment there was this discussion: #2876 (comment)
starting from this comment of mine:
One note though: perhaps it's better to go a simpler route and, instead of this "generic and extensible"
matchbracestyleoption withhighlightandunderlinevalues, add a simple boolean option e.g.matchbracehighlight? An advantage is that, if we implement a generic support for easy toggling on/off arbitrary options (see #2086), then it will be readily usable for thismatchbracehighlightoption as well, to easily toggle between highlighting and underlining.
And now, I tend to agree with @cutelisp and @Andriamanitra that toggle for options with 3 or more choices would be rather weird [*]. But, for options with exactly 2 choices, like this matchbracestyle, it seems like a nice idea indeed. And that would also address precisely the concern from my quoted comment above.
[*] Even though, as I've realized just now, it was me who suggested that stupid idea, in #2876 (comment).
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'll give it a try on including "2-choice options"
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.
Ok, you guys convinced me.
We give it a try for the "2-choice options". 👍
|
Added support for "2-choice options" |
| curVal = config.GetGlobalOption(option) | ||
| } | ||
| if curVal == nil { | ||
| return config.ErrInvalidOption |
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 we bother saying it's an invalid option or should we just say it's not a toggleable option anyway.
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.
At this position it is invalid.
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 point is what is invalid? An invalid option or a invalid option for this command?
For example: setlocal autosave 0 -> invalid option
Autosave is indeed a valid option but it's not a local option.
I was willing to improve error messages that's why I created ErrOptNotToggleable.
At this position it is invalid.
Note that at this point it might be a valid option yet a global-only.
To improve accuracy in this command and other parts of the code, we could encapsulate the logic into dedicated functions, something like this:
func GetGlobalOption*(name string) (interface{}, error) {
if v, ok := GlobalSettings[name]; ok {
return v, nil
}
return nil, ErrInvalidOption
}
func (b *Buffer) GetOption(name string) (interface{}, error) {
if v, ok := b.Settings[name]; ok {
return v, nil
}
if _, err := GetGlobalOption(name); err != nil {
return nil, err
}
return nil, ErrNotLocalOpt
}What do you think?
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 point is what is invalid? An invalid option or a invalid option for this command?
When toggleOption() is called with local set to false and calls config.GetGlobalOption(option) with a option not tracked within, then it is indeed an ErrInvalidOption. If it is toggleable will be checked later on.
GetGlobalOption() is already exported to plugins:
Line 90 in dbdf753
| ulua.L.SetField(pkg, "GetGlobalOption", luar.New(ulua.L, config.GetGlobalOption)) |
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.
GetGlobalOption()is already exported to plugins:
Yes, and used on go side as well. Thats why GetGlobalOption*, it would be a different function.
Note that we already use this logic.
if _, ok := config.GlobalSettings[option]; !ok {
return config.ErrInvalidOption
}When
toggleOption()is called withlocalset tofalseand callsconfig.GetGlobalOption(option)with aoptionnot tracked within, then it is indeed an ErrInvalidOption. If it is toggleable will be checked later on.
I am aware, the edge case comes when we call it with local set to true and we give a valid global-only option.
(b *Buffer) GetOption() would handle it with a specific error
internal/action/command.go
Outdated
| if !local { | ||
| if err := SetGlobalOptionNative(option, newVal); err == nil { | ||
| return nil | ||
| } | ||
| } | ||
|
|
||
| if err := h.Buf.SetOptionNative(option, newVal); err != nil { | ||
| return err | ||
| } |
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 took this logic from SetCmd().
err := SetGlobalOption(option, value)
if err == config.ErrInvalidOption {
err := h.Buf.SetOption(option, value)
if err != nil {
InfoBar.Error(err)
}
} else if err != nil {
InfoBar.Error(err)
}But now I wonder if making this fallback makes sense at all?
SetGlobalOption is just a SetGlobalOptionNative wrapper.
SetGlobalOptionNative have a fallback for local settings itself.
micro/internal/action/command.go
Lines 636 to 641 in 3a7705a
| // check for local option first... | |
| for _, s := range config.LocalSettings { | |
| if s == option { | |
| return MainTab().CurPane().Buf.SetOptionNative(option, nativeValue) | |
| } | |
| } |
Maybe I am missing something but I don't see a way where config.ErrInvalidOption is returned and makes sense to call Buf.SetOption*()
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.
Indeed, looks like we can simplify that and just switch based on if !local {} without fallback.
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.
Right.
As I pointed here SetGlobalOptionNative has some odd behavior. I just realized that, with the current logic, setting a global-only value it also populates the Settings field of each buffer in openBuffers. IMO, the current variable and function names related to settings are misleading, and we should consider renaming them if we eventually patch these functions.
|
The error logic is consistent with other commands, so I'll keep things as they are and probably create a PR to improve error handling across commands. |
internal/action/command.go
Outdated
| return config.ErrOptNotToggleable | ||
| } | ||
|
|
||
| if !local { |
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.
nit: flip the order of the if/else branches (just to keep it the same as at the beginning of the function)?
|
It looks like this stalled out with one last nit to address? Any chance it could land without that? Thanks for your work on this @cutelisp and reviewers. |
217ef4a to
160c13a
Compare
160c13a to
595c0cf
Compare
|
Sorry for delay. |
|
Thanks everyone. :-) |
This adds toggle
andtogglelocal` command as requested here #2086.Not sure if this is the most correct approach, I found settings code a bit confusing and with non-intuitive variable names and behaviors.
Feedback is appreciated.