aerc: commands: run a command by its first letters v3 SUPERSEDED

Vitaly Ovchinnikov: 1
 commands: run a command by its first letters

 1 files changed, 57 insertions(+), 0 deletions(-)
#1058915 alpine-edge.yml success
#1058916 openbsd.yml failed
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~rjarry/aerc-devel/patches/44811/mbox | git am -3
Learn more about email & git

[PATCH aerc v3] commands: run a command by its first letters Export this patch

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

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) {

			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