Preview filter while browsing an open dropdown; Esc closes only the list
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
+71
-1
@@ -11,16 +11,39 @@ import (
|
||||
// (and move between the buttons),
|
||||
//
|
||||
// Enter or Space still opens a dropdown list. While a list is open it gets all keys.
|
||||
func arrowNavigation(f *tview.Form) {
|
||||
//
|
||||
// With hooks, the highlighted entry of an open list is reported while the user
|
||||
// moves through it, before anything is selected.
|
||||
//
|
||||
// cancel is called on Esc, except when Esc only closes an open dropdown list
|
||||
// (tview would otherwise treat that as cancelling the whole form).
|
||||
func arrowNavigation(f *tview.Form, cancel func(), hooks *browseHooks) {
|
||||
var b browser
|
||||
var closingList bool
|
||||
f.SetCancelFunc(func() {
|
||||
if closingList {
|
||||
closingList = false
|
||||
return
|
||||
}
|
||||
if cancel != nil {
|
||||
cancel()
|
||||
}
|
||||
})
|
||||
f.SetInputCapture(func(ev *tcell.EventKey) *tcell.EventKey {
|
||||
closingList = false
|
||||
item, button := f.GetFocusedItemIndex()
|
||||
if item < 0 && button < 0 {
|
||||
return ev
|
||||
}
|
||||
dd, _ := focusedDropDown(f, item)
|
||||
if dd != nil && dd.IsOpen() {
|
||||
closingList = ev.Key() == tcell.KeyEscape
|
||||
if hooks != nil {
|
||||
b.track(dd, ev, hooks)
|
||||
}
|
||||
return ev
|
||||
}
|
||||
b.dd = nil
|
||||
total := f.GetFormItemCount() + f.GetButtonCount()
|
||||
pos := item
|
||||
if button >= 0 {
|
||||
@@ -90,3 +113,50 @@ func bindSearchNow(box *tview.Checkbox, searchable func() bool, blocked func())
|
||||
box.SetChecked(false)
|
||||
}
|
||||
}
|
||||
|
||||
// browseHooks lets a form follow the highlight of an open dropdown list.
|
||||
type browseHooks struct {
|
||||
browse func(dd *tview.DropDown, index int) // the highlight moved to entry index
|
||||
abort func() // the list was closed without selecting
|
||||
}
|
||||
|
||||
// browser mirrors the highlight of an open dropdown list, which tview does
|
||||
// not expose: it starts at the current option and follows the navigation keys.
|
||||
type browser struct {
|
||||
dd *tview.DropDown
|
||||
idx int
|
||||
known bool // false after keys that move the highlight in ways we do not track
|
||||
}
|
||||
|
||||
func (b *browser) track(dd *tview.DropDown, ev *tcell.EventKey, h *browseHooks) {
|
||||
n := dd.GetOptionCount()
|
||||
if b.dd != dd {
|
||||
cur, _ := dd.GetCurrentOption()
|
||||
b.dd, b.idx, b.known = dd, max(cur, 0), true
|
||||
}
|
||||
move := func(to int) {
|
||||
b.idx = to
|
||||
if b.known && h.browse != nil {
|
||||
h.browse(dd, b.idx)
|
||||
}
|
||||
}
|
||||
switch ev.Key() {
|
||||
case tcell.KeyDown:
|
||||
move((b.idx + 1) % n)
|
||||
case tcell.KeyUp:
|
||||
move((b.idx - 1 + n) % n)
|
||||
case tcell.KeyHome:
|
||||
move(0)
|
||||
case tcell.KeyEnd:
|
||||
move(n - 1)
|
||||
case tcell.KeyEscape:
|
||||
b.dd = nil
|
||||
if h.abort != nil {
|
||||
h.abort()
|
||||
}
|
||||
case tcell.KeyEnter:
|
||||
b.dd = nil // the selection is reported by the dropdown itself
|
||||
default:
|
||||
b.known = false // paging, typed prefixes
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user