[GH-ISSUE #776] Handling keys in InputField -> autocomplete list #568

Closed
opened 2026-03-04 01:06:05 +03:00 by kerem · 21 comments
Owner

Originally created by @carpii on GitHub (Dec 9, 2022).
Original GitHub issue: https://github.com/rivo/tview/issues/776

I have an InputField with an autocomplete function...


I'd like more control over handling key input inside this list. Ive looked at the source but it seems autocomplete list is internal to InputField, and theres no way to access it or add input handlers to it

1) Handling tab and page up/down keys
2) When an autocomplete list item is selected (using arrow keys), I do not want to update the TextInput text. This should only happen when I hit Enter

Maybe I need to write a custom component, or try to handle it from App.SetInputHandler() ?

Any advice much appreciated, thanks

package main

import (
	"strings"

	"github.com/gdamore/tcell/v2"
	"github.com/rivo/tview"
)

func UI_test() {
	app := tview.NewApplication()
	testlist := []string{
		"Taxes: Import Tax",
		"Taxes: Income Tax",
		"Taxes: National Insurance",
		"Taxes: Road Tax",
		"Taxes: VAT Bill",
		"TaxDummy: foobar",
		"TaxDummy: lorem ipsum",
		"TaxFoo: foo",
		"Random: TaxFoobar",
	}

	category_search_input := tview.NewInputField().
		SetLabel("Category: ").
		SetFieldWidth(30)

	category_search_input.SetDoneFunc(func(key tcell.Key) {
		if key == tcell.KeyTab {
			category_search_input.SetText("TABBED")
		} else if key == tcell.KeyEscape {
			category_search_input.SetText("ESCAPED")
		} else if key == tcell.KeyEnter {
			category_search_input.SetText("ENTER")
		}
	})

	category_search_input.SetAutocompleteFunc(func(currentText string) (entries []string) {
		for i := range testlist {
			if strings.Contains(strings.ToUpper(testlist[i]), strings.ToUpper(currentText)) {
				entries = append(entries, testlist[i])
			}
		}
		if len(entries) < 1 {
			entries = nil
		}
		return
	})

	form := tview.NewForm().
		AddFormItem(category_search_input).
		AddInputField("Dummy Input", "", 0, nil, nil)

	if err := app.SetRoot(form, true).SetFocus(form).Run(); err != nil {
		panic(err)
	}
}
Originally created by @carpii on GitHub (Dec 9, 2022). Original GitHub issue: https://github.com/rivo/tview/issues/776 I have an InputField with an autocomplete function... ![](https://i.imgur.com/EM8DtxN.png) ---- I'd like more control over handling key input inside this list. Ive looked at the source but it seems autocomplete list is internal to InputField, and theres no way to access it or add input handlers to it ##### 1) Handling tab and page up/down keys ##### 2) When an autocomplete list item is selected (using arrow keys), I do not want to update the TextInput text. This should only happen when I hit Enter ---- Maybe I need to write a custom component, or try to handle it from App.SetInputHandler() ? Any advice much appreciated, thanks ```` package main import ( "strings" "github.com/gdamore/tcell/v2" "github.com/rivo/tview" ) func UI_test() { app := tview.NewApplication() testlist := []string{ "Taxes: Import Tax", "Taxes: Income Tax", "Taxes: National Insurance", "Taxes: Road Tax", "Taxes: VAT Bill", "TaxDummy: foobar", "TaxDummy: lorem ipsum", "TaxFoo: foo", "Random: TaxFoobar", } category_search_input := tview.NewInputField(). SetLabel("Category: "). SetFieldWidth(30) category_search_input.SetDoneFunc(func(key tcell.Key) { if key == tcell.KeyTab { category_search_input.SetText("TABBED") } else if key == tcell.KeyEscape { category_search_input.SetText("ESCAPED") } else if key == tcell.KeyEnter { category_search_input.SetText("ENTER") } }) category_search_input.SetAutocompleteFunc(func(currentText string) (entries []string) { for i := range testlist { if strings.Contains(strings.ToUpper(testlist[i]), strings.ToUpper(currentText)) { entries = append(entries, testlist[i]) } } if len(entries) < 1 { entries = nil } return }) form := tview.NewForm(). AddFormItem(category_search_input). AddInputField("Dummy Input", "", 0, nil, nil) if err := app.SetRoot(form, true).SetFocus(form).Run(); err != nil { panic(err) } } ````
kerem closed this issue 2026-03-04 01:06:06 +03:00
Author
Owner

@carpii commented on GitHub (Dec 14, 2022):

Happy to extend the InputField API myself, and submit a pull request

But would appreciate your thoughts on how you see the design working, to maximise likelihood of pull request being accepted. Thanks

<!-- gh-comment-id:1352368055 --> @carpii commented on GitHub (Dec 14, 2022): Happy to extend the InputField API myself, and submit a pull request But would appreciate your thoughts on how you see the design working, to maximise likelihood of pull request being accepted. Thanks
Author
Owner

@rivo commented on GitHub (Dec 17, 2022):

I think you're right. It currently doesn't work as it's supposed to. Specifically your point (2), I agree it should not update (or especially trigger a changed event) when the user simply browses the autocomplete results. I'm open to changing this despite it being this way right now. (This will fall under the " something that does not work as originally intended" exception regarding backwards compatibility.)

Can you elaborate on your first point, though? I can imagine what PageUp and PageDown should do, but what about Tab?

<!-- gh-comment-id:1356402876 --> @rivo commented on GitHub (Dec 17, 2022): I think you're right. It currently doesn't work as it's supposed to. Specifically your point (2), I agree it should not update (or especially trigger a changed event) when the user simply browses the autocomplete results. I'm open to changing this despite it being this way right now. (This will fall under the _" something that does not work as originally intended"_ exception regarding backwards compatibility.) Can you elaborate on your first point, though? I can imagine what <kbd>PageUp</kbd> and <kbd>PageDown</kbd> should do, but what about <kbd>Tab</kbd>?
Author
Owner

@carpii commented on GitHub (Dec 17, 2022):

I'm open to changing this despite it being this way right now.

Awesome, thanks.

Can you elaborate on your first point, though? I can imagine what PageUp and PageDown should do, but what about Tab?

Sorry, my issue originally explained why I wanted to handle Tab, but I edited it out as it didn't seem relevant.

It's application-specific, in the above list I'd like to type 'Taxe' and then hit Tab.

At this point it would autocomplete the input text to 'Taxes: ' (delimited by colon, and sinces Taxes: would be the only remaining prefix). But the issue is I don't have any way to run a callback when tab is pressed

<!-- gh-comment-id:1356404869 --> @carpii commented on GitHub (Dec 17, 2022): > I'm open to changing this despite it being this way right now. Awesome, thanks. > Can you elaborate on your first point, though? I can imagine what PageUp and PageDown should do, but what about Tab? Sorry, my issue originally explained why I wanted to handle Tab, but I edited it out as it didn't seem relevant. It's application-specific, in the above list I'd like to type 'Taxe' and then hit Tab. At this point it would autocomplete the input text to 'Taxes: ' (delimited by colon, and sinces Taxes: would be the only remaining prefix). But the issue is I don't have any way to run a callback when tab is pressed
Author
Owner

@rivo commented on GitHub (Dec 17, 2022):

What would be the difference between hitting Tab and Enter?

<!-- gh-comment-id:1356492005 --> @rivo commented on GitHub (Dec 17, 2022): What would be the difference between hitting <kbd>Tab</kbd> and <kbd>Enter</kbd>?
Author
Owner

@carpii commented on GitHub (Dec 17, 2022):

Unless I've misunderstood, Enter would accept the currently selected list item, set the TextInput to match that item, and then close the autocomplete list

Instead, I want to handle Tab so I can amend the TextInput from 'taxe' into 'Taxes:', then either select an item from list, or keep typing and add a new 'Taxes: FooBar'.

This is very application-specific though, so would not need any Tab-specific code added to InputField (maybe just a way to add a generic hook to the autcomplete list, so any KeyEvent could be handled?)

<!-- gh-comment-id:1356495434 --> @carpii commented on GitHub (Dec 17, 2022): Unless I've misunderstood, `Enter` would accept the currently selected list item, set the TextInput to match that item, and then close the autocomplete list Instead, I want to handle `Tab` so I can amend the TextInput from 'taxe' into 'Taxes:', then either select an item from list, or keep typing and add a new 'Taxes: FooBar'. This is very application-specific though, so would not need any Tab-specific code added to InputField (maybe just a way to add a generic hook to the autcomplete list, so any KeyEvent could be handled?)
Author
Owner

@carpii commented on GitHub (Dec 22, 2022):

@rivo - I will try to make these changes after Xmas, and submit a pull request.

If you find yourself in the mood to tackle it yourself at any point, I am offering a $100 bounty for it

Cheers

<!-- gh-comment-id:1363384663 --> @carpii commented on GitHub (Dec 22, 2022): @rivo - I will try to make these changes after Xmas, and submit a pull request. If you find yourself in the mood to tackle it yourself at any point, I am offering a $100 bounty for it Cheers
Author
Owner

@rivo commented on GitHub (Dec 22, 2022):

I will work on this but I can't do it before Christmas. No need to submit a PR.

I noticed there are some other bugs related to the autocomplete functionality so I need to take a look at them, too.

<!-- gh-comment-id:1363409001 --> @rivo commented on GitHub (Dec 22, 2022): I will work on this but I can't do it before Christmas. No need to submit a PR. I noticed there are some other bugs related to the autocomplete functionality so I need to take a look at them, too.
Author
Owner

@carpii commented on GitHub (Dec 22, 2022):

@rivo - I was not sure how it was left, whether you were planning to do it, or whether you were saying you would accept a PR from me. But thanks for looking into it.

I wouldn't expect anyone to work over Xmas though. Maybe if we can be approaching a solution by 1st Feb, the bounty is all yours

Thanks

<!-- gh-comment-id:1363413771 --> @carpii commented on GitHub (Dec 22, 2022): @rivo - I was not sure how it was left, whether you were planning to do it, or whether you were saying you would accept a PR from me. But thanks for looking into it. I wouldn't expect anyone to work over Xmas though. Maybe if we can be approaching a solution by 1st Feb, the bounty is all yours Thanks
Author
Owner

@rivo commented on GitHub (Dec 22, 2022):

I appreciate it, thanks.

I haven't thought about the Enter vs. Tab thing in detail so I wasn't able to give an informed response yet. But as long as these issues are open, I usually get back to them.

<!-- gh-comment-id:1363415586 --> @rivo commented on GitHub (Dec 22, 2022): I appreciate it, thanks. I haven't thought about the <kbd>Enter</kbd> vs. <kbd>Tab</kbd> thing in detail so I wasn't able to give an informed response yet. But as long as these issues are open, I usually get back to them.
Author
Owner

@rivo commented on GitHub (Dec 29, 2022):

Ok, so b86a50a512 introduces a new function called SetAutocompletedFunc() which gives you more control over how the autocomplete drop-down behaves. If you don't set it, it remains the way it was implemented before (due to backwards compatibility).

I believe this should allow you to implement what you needed. Have a look and let me know in case you find any issues.

<!-- gh-comment-id:1367502062 --> @rivo commented on GitHub (Dec 29, 2022): Ok, so b86a50a5126c604126c5ee1847833849b9d3b6b4 introduces a new function called [`SetAutocompletedFunc()`](https://pkg.go.dev/github.com/rivo/tview#InputField.SetAutocompletedFunc) which gives you more control over how the autocomplete drop-down behaves. If you don't set it, it remains the way it was implemented before (due to backwards compatibility). I believe this should allow you to implement what you needed. Have a look and let me know in case you find any issues.
Author
Owner

@carpii commented on GitHub (Dec 30, 2022):

Thanks so much for making these changes. It looks like a nice solution from the diff

I will start integrating it as soon as I can, and let you know how I get on

Cheers

<!-- gh-comment-id:1368078194 --> @carpii commented on GitHub (Dec 30, 2022): Thanks so much for making these changes. It looks like a nice solution from the diff I will start integrating it as soon as I can, and let you know how I get on Cheers
Author
Owner

@carpii commented on GitHub (Jan 1, 2023):

Key handling seems to be working well, I'm just unsure how to use the index parameter

Is there a way to retrieve the current entries from the autocomplete dropdown?

Or is the expectation to rerun the same function I use for SetAutocompleteFunc (which would then mean it can no longer be passed as an anonymous fn)

<!-- gh-comment-id:1368526751 --> @carpii commented on GitHub (Jan 1, 2023): Key handling seems to be working well, I'm just unsure how to use the index parameter Is there a way to retrieve the current entries from the autocomplete dropdown? Or is the expectation to rerun the same function I use for SetAutocompleteFunc (which would then mean it can no longer be passed as an anonymous fn)
Author
Owner

@rivo commented on GitHub (Jan 1, 2023):

Or is the expectation to rerun the same function I use for SetAutocompleteFunc

That's pretty much it. You might want to cache the results from that function. I didn't want to require a huge function signature repeating information that could be found elsewhere.

You don't have to use the index parameter if you don't need it. You're getting the text anyway.

<!-- gh-comment-id:1368533024 --> @rivo commented on GitHub (Jan 1, 2023): > Or is the expectation to rerun the same function I use for SetAutocompleteFunc That's pretty much it. You might want to cache the results from that function. I didn't want to require a huge function signature repeating information that could be found elsewhere. You don't have to use the index parameter if you don't need it. You're getting the text anyway.
Author
Owner

@carpii commented on GitHub (Jan 1, 2023):

Understood. I just wanted to make sure I wasn't overlooking something obvious :-)

Bit more testing to do, but it's looking good so far. Any preference on how to receive your bounty (Paypal, github etc?)

<!-- gh-comment-id:1368536854 --> @carpii commented on GitHub (Jan 1, 2023): Understood. I just wanted to make sure I wasn't overlooking something obvious :-) Bit more testing to do, but it's looking good so far. Any preference on how to receive your bounty (Paypal, github etc?)
Author
Owner

@rivo commented on GitHub (Jan 1, 2023):

I think since we're here anyway, GitHub is fine. If that doesn't work for some reason, PayPal should do it.

Thank you! 🙏🏼

<!-- gh-comment-id:1368543292 --> @rivo commented on GitHub (Jan 1, 2023): I think since we're here anyway, GitHub is fine. If that doesn't work for some reason, [PayPal](https://www.paypal.com/paypalme/oliverrivo) should do it. Thank you! 🙏🏼
Author
Owner

@carpii commented on GitHub (Jan 1, 2023):

Bounty sent via Github. Thanks for accommodating my feature request, it's a nice enhancement to my project 👍

<!-- gh-comment-id:1368543870 --> @carpii commented on GitHub (Jan 1, 2023): Bounty sent via Github. Thanks for accommodating my feature request, it's a nice enhancement to my project :+1:
Author
Owner

@rivo commented on GitHub (Jan 4, 2023):

Bounty sent via Github.

Just to let you know that I haven't received anything yet. My GitHub dashboard also doesn't show any donations/donations made to me.

<!-- gh-comment-id:1370899065 --> @rivo commented on GitHub (Jan 4, 2023): > Bounty sent via Github. Just to let you know that I haven't received anything yet. My GitHub dashboard also doesn't show any donations/donations made to me.
Author
Owner

@carpii commented on GitHub (Jan 4, 2023):

Sorry about that. It looks like my card wasn't billed either

I'll try again now...

<!-- gh-comment-id:1370994562 --> @carpii commented on GitHub (Jan 4, 2023): Sorry about that. It looks like my card wasn't billed either I'll try again now...
Author
Owner

@carpii commented on GitHub (Jan 4, 2023):

As far as I can tell, instead of sending it instantly, github is adding it onto my next monthly invoice (on the 18th). Maybe it's because I am a monthly sponsor.

Unfortunately it's not giving me the option to cancel the $100 so I can send via Paypal instead.

I'll see what support has to say

<!-- gh-comment-id:1371026837 --> @carpii commented on GitHub (Jan 4, 2023): As far as I can tell, instead of sending it instantly, github is adding it onto my next monthly invoice (on the 18th). Maybe it's because I am a monthly sponsor. Unfortunately it's not giving me the option to cancel the $100 so I can send via Paypal instead. ![](https://i.imgur.com/sQqU3rt.png) I'll see what support has to say
Author
Owner

@carpii commented on GitHub (Jan 18, 2023):

Github support didn't respond and I wasn't billed on my invoice either

I think one-off github sponsorships are just buggy if you're already a monthly sponsor

I've now sent via Paypal instead, sorry it took a while

<!-- gh-comment-id:1387548885 --> @carpii commented on GitHub (Jan 18, 2023): Github support didn't respond and I wasn't billed on my invoice either I think one-off github sponsorships are just buggy if you're already a monthly sponsor I've now sent via Paypal instead, sorry it took a while
Author
Owner

@rivo commented on GitHub (Jan 19, 2023):

No problem at all! I appreciate your support, thank you!

<!-- gh-comment-id:1396496566 --> @rivo commented on GitHub (Jan 19, 2023): No problem at all! I appreciate your support, thank you!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#568
No description provided.