Skip to content

Fixing commandbar autocomplete regression from #4028 - #4200

Open
Neko-Box-Coder wants to merge 1 commit into
micro-editor:masterfrom
Neko-Box-Coder:FixRegression4028
Open

Fixing commandbar autocomplete regression from #4028#4200
Neko-Box-Coder wants to merge 1 commit into
micro-editor:masterfrom
Neko-Box-Coder:FixRegression4028

Conversation

@Neko-Box-Coder

@Neko-Box-Coder Neko-Box-Coder commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Fixing commandbar autocomplete regression from #4028

Previously, commandcomplete calls the buffer autocomplete directly and there was an autocomplete guard in the action autocomplete.

#4028 moved the guard from action autocomplete to the buffer autocomplete, which now applies to commandcomplete which it wasn't applied before.

The causes the command bar autocomplete to not behave as before (not autocomplete until a character is entered), it also affected plugin that uses the buffer autocomplete.

This PR restores the previous behavior by adding a check callback variant that allows the caller to specify the check for autocomplete if needed.

@JoeKar

JoeKar commented Aug 27, 2026

Copy link
Copy Markdown
Member

From @Andriamanitra's #4028 (comment):

This also broke plugins that autocomplete sequences with non-word characters. For example jlabbrev lets you autocomplete \^ to various LaTeX superscript expressions (\^2, \^alpha, \^(, ...). I confirmed that #4200 fixes that issue for single cursor but it won't work with multiple cursors

If there's a better solution that doesn't require this hack, I am more than happy to use/implement it instead.

We could solve both cases, as we did in the past multiple times:
We encapsulate the different behaviors with different internal/external interfaces and an additional parameter.
Requires some internal caller changes as well.

EDIT:
Maybe something like this? 🤔
Yes, the names are ugly, but I couldn't find better so far.

diff --git a/internal/action/actions.go b/internal/action/actions.go
index ebd51899..2ad2a0a2 100644
--- a/internal/action/actions.go
+++ b/internal/action/actions.go
@@ -916,7 +916,7 @@ func (h *BufPane) Autocomplete() bool {
 		return true
 	}
 
-	return b.Autocomplete(buffer.BufferComplete)
+	return b.AutocompleteCheck(buffer.BufferComplete, true)
 }
 
 // CycleAutocompleteBack cycles back in the autocomplete suggestion list
diff --git a/internal/action/infopane.go b/internal/action/infopane.go
index 6ecd9552..2537873c 100644
--- a/internal/action/infopane.go
+++ b/internal/action/infopane.go
@@ -192,7 +192,7 @@ func (h *InfoPane) HistorySearchDown() {
 func (h *InfoPane) CommandComplete() {
 	b := h.Buf
 	if b.HasSuggestions {
-		b.CycleAutocomplete(true)
+		b.CycleAutocompleteCheck(true, false)
 		return
 	}
 
@@ -205,15 +205,15 @@ func (h *InfoPane) CommandComplete() {
 
 	if h.PromptType == "Command" {
 		if len(args) == 1 {
-			b.Autocomplete(CommandComplete)
+			b.AutocompleteCheck(CommandComplete, false)
 		} else if action, ok := commands[cmd]; ok {
 			if action.completer != nil {
-				b.Autocomplete(action.completer)
+				b.AutocompleteCheck(action.completer, false)
 			}
 		}
 	} else {
 		// by default use filename autocompletion
-		b.Autocomplete(buffer.FileComplete)
+		b.AutocompleteCheck(buffer.FileComplete, false)
 	}
 }
 
diff --git a/internal/buffer/autocomplete.go b/internal/buffer/autocomplete.go
index d0832557..26f83bde 100644
--- a/internal/buffer/autocomplete.go
+++ b/internal/buffer/autocomplete.go
@@ -25,7 +25,11 @@ func (b *Buffer) GetSuggestions() {
 
 // Autocomplete starts the autocomplete process
 func (b *Buffer) Autocomplete(c Completer) bool {
-	if !b.GetActiveCursor().CanAutocomplete() {
+	return b.AutocompleteCheck(c, false)
+}
+
+func (b *Buffer) AutocompleteCheck(c Completer, check bool) bool {
+	if check && !b.GetActiveCursor().CanAutocomplete() {
 		return false
 	}
 	b.Completions, b.Suggestions = c(b)
@@ -33,12 +37,16 @@ func (b *Buffer) Autocomplete(c Completer) bool {
 		return false
 	}
 	b.CurSuggestion = -1
-	b.CycleAutocomplete(true)
+	b.CycleAutocompleteCheck(true, check)
 	return true
 }
 
 // CycleAutocomplete moves to the next suggestion
 func (b *Buffer) CycleAutocomplete(forward bool) {
+	b.CycleAutocompleteCheck(forward, true)
+}
+
+func (b *Buffer) CycleAutocompleteCheck(forward bool, check bool) {
 	prevSuggestion := b.CurSuggestion
 
 	if forward {
@@ -56,7 +64,7 @@ func (b *Buffer) CycleAutocomplete(forward bool) {
 	activeWord := make([]byte, len(tmpWord))
 	copy(activeWord, tmpWord)
 	for _, c := range b.cursors {
-		if !c.CanAutocomplete() {
+		if check && !c.CanAutocomplete() {
 			continue
 		}
 

@Neko-Box-Coder

Neko-Box-Coder commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

@Andriamanitra

This also broke plugins that autocomplete sequences with non-word characters. For example jlabbrev lets you autocomplete \^ to various LaTeX superscript expressions (\^2, \^alpha, \^(, ...). I confirmed that #4200 fixes that issue for single cursor but it won't work with multiple cursors

I will have a try at it, but I don't understand how it was working before 🤔 since we do perform the same guard when auto-completing before #4200.

@JoeKar

EDIT:
Maybe something like this? 🤔
Yes, the names are ugly, but I couldn't find better so far.

Thanks for the patch. Just wondering have we ever considered versioning the functions (Since I am seeing more of this happening)? Something like AutocompleteV2(...)?
Just a random thought again, could be a bad/confusing way of naming functions, idk.

@Neko-Box-Coder
Neko-Box-Coder force-pushed the FixRegression4028 branch 2 times, most recently from e5f5213 to 867c0a9 Compare August 27, 2026 19:10
@dmaluka

dmaluka commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

If not those plugins, we could fix this very easily:

diff --git a/internal/buffer/autocomplete.go b/internal/buffer/autocomplete.go
index d0832557..8741538d 100644
--- a/internal/buffer/autocomplete.go
+++ b/internal/buffer/autocomplete.go
@@ -86,6 +86,10 @@ func (c *Cursor) autocomplete(prevSuggestion int) {
 }
 
 func (c *Cursor) CanAutocomplete() bool {
+	if c.buf.Type == BTInfo {
+		return true
+	}
+
 	if c.X == 0 {
 		return false
 	}

Comment thread internal/action/infopane.go Outdated
if h.PromptType == "Command" {
if len(args) == 1 {
b.Autocomplete(CommandComplete)
b.AutocompleteCheck(CommandComplete, false)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What for?

Comment thread internal/buffer/autocomplete.go Outdated
return b.AutocompleteCheck(c, false)
}

func (b *Buffer) AutocompleteCheck(c Completer, check bool) bool {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Yes, the name sucks. AutocompleteWithCheck()? Or, don't know, just AutocompleteEx() or whatever?
  2. Instead of this ad-hoc non-extensible check flag, why not pass a callback? We know that bufpane.go is the only user of Autocomplete() that wants this check (and before Add multicursor autocompletions #4028 it was bufpane.go that was performing this check), so, let bufpane.go pass a callback implementing this check, and let others (i.e. infopane and plugins) pass a stub callback which always returns true?

Comment thread internal/buffer/autocomplete.go Outdated

// CycleAutocomplete moves to the next suggestion
func (b *Buffer) CycleAutocomplete(forward bool) {
b.CycleAutocompleteCheck(forward, true)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not be consistent with Autocomplete() and pass false by default, not true? And thereby also avoid breaking plugins that are using CycleAutocomplete() if there are any, exactly the same way and exactly for the same reasons as for Autocomplete()?

@Neko-Box-Coder

Copy link
Copy Markdown
Contributor Author

@dmaluka

If not those plugins, we could fix this very easily:

diff --git a/internal/buffer/autocomplete.go b/internal/buffer/autocomplete.go
index d0832557..8741538d 100644
--- a/internal/buffer/autocomplete.go
+++ b/internal/buffer/autocomplete.go
@@ -86,6 +86,10 @@ func (c *Cursor) autocomplete(prevSuggestion int) {
 }
 
 func (c *Cursor) CanAutocomplete() bool {
+	if c.buf.Type == BTInfo {
+		return true
+	}
+
 	if c.X == 0 {
 		return false
 	}

Maybe I am missing something but this works no?

@dmaluka

dmaluka commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Maybe I am missing something but this works no?

This (i.e. my "fix") only fixes the regression for the command bar, it doesn't fix the regression for plugins pointed out by @Andriamanitra, right?

Frankly I didn't try to reproduce that plugins regression myself, but @Andriamanitra 's description of it sounds quite clear to me.

I will have a try at it, but I don't understand how it was working before 🤔

That jlabbrev plugin calls the buffer's Autocomplete() method: https://github.com/masflam/jlabbrev/blob/master/jlabbrev.lua#L2555, not the bufpane's one. #4028 changed the behavior of the buffer's Autocomplete() method, by moving the "are we after a word?" check logic from the bufpane's Autocomplete() method into the buffer's one. So it's quite clear how it caused the regression?

@Neko-Box-Coder

Neko-Box-Coder commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

@dmaluka

This (i.e. my "fix") only fixes the regression for the command bar, it doesn't fix the regression for plugins [...]

Ah...right, fair enough.

That jlabbrev plugin calls the buffer's Autocomplete() method [...]

I hadn't read the plugin code when I was asking, but I see. Yeah, now it makes sense.

@Andriamanitra
I have installed the jlabbrev plugin and tested against this PR latest changes. It will work like before for single cursor, but it won't work (or rather behaves slightly better...but still doesn't work) for multi-cursor....like before.

It's simply because it wasn't designed to work with multi-cursor (reasonably so) judging from it does its own text replacement, and also because it was doing preInsertTab() instead of preAutocomplete() (micro default for tab is Autocomplete|IndentSelection|InsertTab).

@dmaluka

dmaluka commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

I have installed the jlabbrev plugin and tested against this PR latest changes. It will work like before for single cursor

No. I've just tried that myself and I see exactly the behavior described by @Andriamanitra : with that plugin installed, before #4028, if I type \^ and press Tab, it autocompletes it with abbreviations (whatever that is):

image

After #4028, it doesn't.

Although, the plugin's behavior doesn't seem quite friendly in this particular case when before pressing Tab we type \^ only, not \^ plus an abbreviation (or more generally, when there are multiple autocompletion suggestions for the given abbreviation prefix, so that pressing Tab cycles though those suggestions): in order to actually substitute the autocompleted abbreviation with the Unicode symbol, we can't just press Tab once again (since Tab will cycle to the next autocompletion suggestion, instead of handling the current one), we need to, for example, press Space, then press Backspace to delete this space, and then press Tab again.

But that's another story. #4028 still caused a regression, making this not work at all.

Comment thread internal/action/actions.go Outdated

return b.Autocomplete(buffer.BufferComplete)
return b.AutocompleteWithCheckCB(buffer.BufferComplete, func(c *buffer.Cursor) bool {
return c.CanAutocomplete()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not move the implementation of CanAutocomplete() into actions.go so we can just pass it to AutocompleteWithCheckCB() as a callback as is? The very idea is that this CanAutocomplete() check is bufpane-specific, i.e. no one except these bufpane's Autocomplete and CycleAutocompleteBack actions will use it, thus it belongs here in the bufpane package, not in the buffer package?

Comment thread internal/buffer/autocomplete.go Outdated
func (b *Buffer) Autocomplete(c Completer) bool {
if !b.GetActiveCursor().CanAutocomplete() {
return b.AutocompleteWithCheckCB(c, func(*Cursor) bool {
return true

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it was me who suggested to "pass a stub callback which always returns true", but now looking e.g. at our SaveCB() or SaveAsCB(), we can just pass nil and let AutocompleteWithCheckCB() check it? That would make the code a bit shorter and more readable?

...While we're at it, maybe let's also rename AutocompleteWithCheckCB() to just AutocompleteCB()? That would at least make it look much less ugly.

@Neko-Box-Coder

Copy link
Copy Markdown
Contributor Author

I have installed the jlabbrev plugin and tested against this PR latest changes. It will work like before for single cursor

No. I've just tried that myself and I see exactly the behavior described by @Andriamanitra : with that plugin installed, before #4028, if I type \^ and press Tab, it autocompletes it with abbreviations (whatever that is):
image

After #4028, it doesn't.

Although, the plugin's behavior doesn't seem quite friendly in this particular case when before pressing Tab we type \^ only, not \^ plus an abbreviation (or more generally, when there are multiple autocompletion suggestions for the given abbreviation prefix, so that pressing Tab cycles though those suggestions): in order to actually substitute the autocompleted abbreviation with the Unicode symbol, we can't just press Tab once again (since Tab will cycle to the next autocompletion suggestion, instead of handling the current one), we need to, for example, press Space, then press Backspace to delete this space, and then press Tab again.

But that's another story. #4028 still caused a regression, making this not work at all.

I am confused... Do you mean #4200 or #4028 ? That quote from me was meant for this PR, not #4028
Autocomplete works for #4200 , unless I am missing something?

Peek 2026-08-30 17-13

And yes you need to get out of the autocomplete and press tab to do the transformation, which was the behavior before #4028

Comment thread internal/action/actions.go Outdated
return false
}

func CanAutocomplete(c *buffer.Cursor) bool {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to make this function public?

...Also regarding the commit message, it would be useful to provide a bit of details on what regression this commit is fixing. I know there are details provided in the PR description, but it is useful to be able to see the essential info in the git log right away, without the need to switch to the web browser and go to github and find the PR to read its description.

BTW now looking at that PR description, it doesn't seem to clearly describe the problem either (i.e., like, what exactly got broken from the user perspective).

@dmaluka

dmaluka commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

Do you mean #4200 or #4028 ? That quote from me was meant for this PR, not #4028
Autocomplete works for #4200 , unless I am missing something?

Sorry, I meant #4028, yes. I thought what you meant was that #4028 didn't break anything for that plugin.

PR micro-editor#4028 moved the check for autocomplete from action autocomplete to
the buffer one, which caused a few regression for upstream callers
(commandbar autocomplete & plugins that use buffer autocomplete)
that use the buffer autocomplete.

This commit restores pre micro-editor#4028 behavior by adding a callback variant
for buffer autocomplete functions while keeping the multi-cursor
autocomplete function.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants