Check if the command entered after : is the abbreviation of an existing
command and run that instead. This is only done if there is no complete
name matching first-hand and if the abbreviation matches just one
command.
Signed-off-by: Vitaly Ovchinnikov <v@postbox.nz>
---
The reason behind the patch is that I want to exit aerc with :q -
something that I used to do with vim.
I tried making a command alias (like: quit/exit/q), but this appears in
the completion list which is not a good idea.
I also tried adding a binding: :q = :quit, but it crashes aerc when
pressed. Stack overflow? Didn't check it too deep...
The final implementation runs through all the commands sets and checks
if there is a partial or full match there. If there is no full match and
there is a single partial match - the command abbreviation is replaced
with the full command name. Then the command is processed as usual.
- v1 - initial version
- v2 - commit message refined
- v3 - multiple command sets support
main.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/main.go b/main.go
index 4705c43..e0c4f89 100644
--- a/main.go+++ b/main.go
@@ -62,11 +62,68 @@ func getCommands(selected libui.Drawable) []*commands.Commands {
}
}
+// gets the command as an array of items and the array of command sets+// checks the first element of the command array against the command names in all sets+// if the first element matches one of the command names directly - does nothing+// if the first element is an abbreviation of one and only one command name in the sets+// it replaces the first element with the full command name+// if it matches nothing - does nothing, too+func expandAbbreviations(cmd []string, sets []*commands.Commands) []string {+ if len(cmd) == 0 {+ return cmd+ }++ name := cmd[0]+ candidate := ""+ for _, set := range sets {+ // do we have a direct match?+ if set.ByName(name) != nil {+ if candidate != "" {+ log.Tracef("found perfectly matched command '%s', ignoring the previous candidate '%s'", name, candidate)+ }+ return cmd+ }++ // check for partial+ for _, n := range set.Names() {+ if !strings.HasPrefix(n, name) {+ continue+ }++ log.Tracef("command '%s' matches abbreviation '%s'", n, name)++ // ok, we have a partial match+ // do we have one already?+ if candidate != "" {+ log.Tracef("that's the second command matching that abbreviation, we cannot process that")+ // we have more than one command partially matching the input+ // we can't expand such an abbreviation, so return the command as is+ // so it can raise an error later+ return cmd+ }++ candidate = n+ }+ }++ // as we are here, we could have a command name matching our partial name in `cmd`+ // in that case we replace the name in `cmd` with the full name, otherwise we simply+ // return `cmd` as is++ if candidate != "" {+ log.Tracef("expanding command abbreviation '%s' to '%s'", name, candidate)+ cmd[0] = candidate+ }++ return cmd+}+func execCommand(
aerc *widgets.Aerc, ui *libui.UI, cmd []string,
acct *config.AccountConfig, msg *models.MessageInfo,
) error {
cmds := getCommands(aerc.SelectedTabContent())
+ cmd = expandAbbreviations(cmd, cmds) // :q -> :quit for i, set := range cmds {
err := set.ExecuteCommand(aerc, cmd, acct, msg)
if err != nil {
--
2.39.2 (Apple Git-143)
aerc/patches: FAILED in 4m43s
[commands: run a command by its first letters][0] v3 from [Vitaly Ovchinnikov][1]
[0]: https://lists.sr.ht/~rjarry/aerc-devel/patches/44811
[1]: mailto:v@postbox.nz
✗ #1058916 FAILED aerc/patches/openbsd.yml https://builds.sr.ht/~rjarry/job/1058916
✓ #1058915 SUCCESS aerc/patches/alpine-edge.yml https://builds.sr.ht/~rjarry/job/1058915