From 0b9c7c0c4afbe17ab6e64b6f74340d0be4c70db7 Mon Sep 17 00:00:00 2001 From: cutelisp Date: Fri, 5 Sep 2025 19:56:02 +0100 Subject: [PATCH] Add toggle & togglelocal command (#3783) --- internal/action/command.go | 127 ++++++++++++++++++++++++++---------- internal/config/settings.go | 5 +- runtime/help/commands.md | 17 +++-- 3 files changed, 109 insertions(+), 40 deletions(-) diff --git a/internal/action/command.go b/internal/action/command.go index d46ae49d..7cb5e523 100644 --- a/internal/action/command.go +++ b/internal/action/command.go @@ -32,39 +32,41 @@ var commands map[string]Command func InitCommands() { commands = map[string]Command{ - "set": {(*BufPane).SetCmd, OptionValueComplete}, - "reset": {(*BufPane).ResetCmd, OptionValueComplete}, - "setlocal": {(*BufPane).SetLocalCmd, OptionValueComplete}, - "show": {(*BufPane).ShowCmd, OptionComplete}, - "showkey": {(*BufPane).ShowKeyCmd, nil}, - "run": {(*BufPane).RunCmd, nil}, - "bind": {(*BufPane).BindCmd, nil}, - "unbind": {(*BufPane).UnbindCmd, nil}, - "quit": {(*BufPane).QuitCmd, nil}, - "goto": {(*BufPane).GotoCmd, nil}, - "jump": {(*BufPane).JumpCmd, nil}, - "save": {(*BufPane).SaveCmd, nil}, - "replace": {(*BufPane).ReplaceCmd, nil}, - "replaceall": {(*BufPane).ReplaceAllCmd, nil}, - "vsplit": {(*BufPane).VSplitCmd, buffer.FileComplete}, - "hsplit": {(*BufPane).HSplitCmd, buffer.FileComplete}, - "tab": {(*BufPane).NewTabCmd, buffer.FileComplete}, - "help": {(*BufPane).HelpCmd, HelpComplete}, - "eval": {(*BufPane).EvalCmd, nil}, - "log": {(*BufPane).ToggleLogCmd, nil}, - "plugin": {(*BufPane).PluginCmd, PluginComplete}, - "reload": {(*BufPane).ReloadCmd, nil}, - "reopen": {(*BufPane).ReopenCmd, nil}, - "cd": {(*BufPane).CdCmd, buffer.FileComplete}, - "pwd": {(*BufPane).PwdCmd, nil}, - "open": {(*BufPane).OpenCmd, buffer.FileComplete}, - "tabmove": {(*BufPane).TabMoveCmd, nil}, - "tabswitch": {(*BufPane).TabSwitchCmd, nil}, - "term": {(*BufPane).TermCmd, nil}, - "memusage": {(*BufPane).MemUsageCmd, nil}, - "retab": {(*BufPane).RetabCmd, nil}, - "raw": {(*BufPane).RawCmd, nil}, - "textfilter": {(*BufPane).TextFilterCmd, nil}, + "set": {(*BufPane).SetCmd, OptionValueComplete}, + "setlocal": {(*BufPane).SetLocalCmd, OptionValueComplete}, + "toggle": {(*BufPane).ToggleCmd, OptionValueComplete}, + "togglelocal": {(*BufPane).ToggleLocalCmd, OptionValueComplete}, + "reset": {(*BufPane).ResetCmd, OptionValueComplete}, + "show": {(*BufPane).ShowCmd, OptionComplete}, + "showkey": {(*BufPane).ShowKeyCmd, nil}, + "run": {(*BufPane).RunCmd, nil}, + "bind": {(*BufPane).BindCmd, nil}, + "unbind": {(*BufPane).UnbindCmd, nil}, + "quit": {(*BufPane).QuitCmd, nil}, + "goto": {(*BufPane).GotoCmd, nil}, + "jump": {(*BufPane).JumpCmd, nil}, + "save": {(*BufPane).SaveCmd, nil}, + "replace": {(*BufPane).ReplaceCmd, nil}, + "replaceall": {(*BufPane).ReplaceAllCmd, nil}, + "vsplit": {(*BufPane).VSplitCmd, buffer.FileComplete}, + "hsplit": {(*BufPane).HSplitCmd, buffer.FileComplete}, + "tab": {(*BufPane).NewTabCmd, buffer.FileComplete}, + "help": {(*BufPane).HelpCmd, HelpComplete}, + "eval": {(*BufPane).EvalCmd, nil}, + "log": {(*BufPane).ToggleLogCmd, nil}, + "plugin": {(*BufPane).PluginCmd, PluginComplete}, + "reload": {(*BufPane).ReloadCmd, nil}, + "reopen": {(*BufPane).ReopenCmd, nil}, + "cd": {(*BufPane).CdCmd, buffer.FileComplete}, + "pwd": {(*BufPane).PwdCmd, nil}, + "open": {(*BufPane).OpenCmd, buffer.FileComplete}, + "tabmove": {(*BufPane).TabMoveCmd, nil}, + "tabswitch": {(*BufPane).TabSwitchCmd, nil}, + "term": {(*BufPane).TermCmd, nil}, + "memusage": {(*BufPane).MemUsageCmd, nil}, + "retab": {(*BufPane).RetabCmd, nil}, + "raw": {(*BufPane).RawCmd, nil}, + "textfilter": {(*BufPane).TextFilterCmd, nil}, } } @@ -730,6 +732,65 @@ func (h *BufPane) SetLocalCmd(args []string) { } } +func (h *BufPane) toggleOption(option string, local bool) error { + var curVal, newVal any + + if local { + curVal = h.Buf.Settings[option] + } else { + curVal = config.GetGlobalOption(option) + } + if curVal == nil { + return config.ErrInvalidOption + } + + if choices, ok := config.OptionChoices[option]; ok && len(choices) == 2 { + if curVal == choices[0] { + newVal = choices[1] + } else { + newVal = choices[0] + } + } else if curValBool, ok := curVal.(bool); ok { + newVal = !curValBool + } else { + return config.ErrOptNotToggleable + } + + if local { + if err := h.Buf.SetOptionNative(option, newVal); err != nil { + return err + } + } else { + if err := SetGlobalOptionNative(option, newVal); err != nil { + return err + } + } + + return nil +} + +// ToggleCmd toggles a toggleable option +func (h *BufPane) ToggleCmd(args []string) { + if len(args) < 1 { + InfoBar.Error("Not enough arguments: provide a toggleable option") + return + } + if err := h.toggleOption(args[0], false); err != nil { + InfoBar.Error(err) + } +} + +// ToggleCmd toggles a toggleable option local to the buffer +func (h *BufPane) ToggleLocalCmd(args []string) { + if len(args) < 1 { + InfoBar.Error("Not enough arguments: provide a toggleable option") + return + } + if err := h.toggleOption(args[0], true); err != nil { + InfoBar.Error(err) + } +} + // ShowCmd shows the value of the given option func (h *BufPane) ShowCmd(args []string) { if len(args) < 1 { diff --git a/internal/config/settings.go b/internal/config/settings.go index edfa76c0..52d45752 100644 --- a/internal/config/settings.go +++ b/internal/config/settings.go @@ -139,8 +139,9 @@ var LocalSettings = []string{ } var ( - ErrInvalidOption = errors.New("Invalid option") - ErrInvalidValue = errors.New("Invalid value") + ErrInvalidOption = errors.New("Invalid option") + ErrInvalidValue = errors.New("Invalid value") + ErrOptNotToggleable = errors.New("Option not toggleable") // The options that the user can set GlobalSettings map[string]any diff --git a/runtime/help/commands.md b/runtime/help/commands.md index a20c8c39..73b25fbc 100644 --- a/runtime/help/commands.md +++ b/runtime/help/commands.md @@ -72,8 +72,20 @@ 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. Only works with options that accept + exactly two values. This will modify your `settings.json` with the new value. + +* `togglelocal 'option'`: toggles the option locally (only in the + current buffer). Only works with options that accept exactly two values. + This will *not* modify `settings.json`. + +* `reset 'option'`: resets the given option to its default value. + * `show 'option'`: shows the current value of the given option. +* `showkey 'key'`: Show the action(s) bound to a given key. For example + running `> showkey Ctrl-c` will display `Copy`. + * `run 'sh-command'`: runs the given shell command in the background. The command's output will be displayed in one line when it finishes running. @@ -129,8 +141,6 @@ quotes here but these are not necessary when entering the command in micro. * `reopen`: Reopens the current file from disk. -* `reset 'option'`: resets the given option to its default value - * `retab`: Replaces all leading tabs with spaces or leading spaces with tabs depending on the value of `tabstospaces`. @@ -139,9 +149,6 @@ quotes here but these are not necessary when entering the command in micro. the terminal and helps you see which bindings aren't possible and why. This is most useful for debugging keybindings. -* `showkey 'key'`: Show the action(s) bound to a given key. For example - running `> showkey Ctrl-c` will display `Copy`. - * `term ['exec']`: Open a terminal emulator running the given executable. If no executable is given, this will open the default shell in the terminal emulator.