Keep the application's focus in step with arrow-key moves in forms

Form.SetFocus moves between items without telling the application, which
kept the item that was left. Opening the help from the Config view then
blurred only that one: the field in use kept drawing its cursor through
the help window, the form still had the focus and took the help's keys
(no scrolling), and closing the help returned to the wrong field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019reK4DUGYqDUjniWYJvwUW
This commit is contained in:
2026-10-21 12:23:00 +02:00
co-authored by Claude Opus 5.5
parent 8ce7bdaaa7
commit c3eca0b68c
4 changed files with 52 additions and 2 deletions
+17 -2
View File
@@ -18,6 +18,18 @@ import (
// 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) {
// Form.SetFocus moves the focus between its items without telling the
// application, which then still holds the item that was left. Opening a
// dialog would only blur that one: the item actually in use kept its
// cursor on screen and, because the form still had the focus, took the
// dialog's keys, and closing the dialog returned to the wrong item. So the
// application is told after every move.
move := func(index int) {
f.SetFocus(index)
if syncFocus != nil {
syncFocus(f) // the form hands the focus on to the item at index
}
}
var b browser
var closingList bool
f.SetCancelFunc(func() {
@@ -65,7 +77,7 @@ func arrowNavigation(f *tview.Form, cancel func(), hooks *browseHooks) {
}
return nil
}
f.SetFocus(next)
move(next)
case tcell.KeyTab, tcell.KeyBacktab:
dir := 1
if ev.Key() == tcell.KeyBacktab {
@@ -86,7 +98,7 @@ func arrowNavigation(f *tview.Form, cancel func(), hooks *browseHooks) {
cur, _ := dd.GetCurrentOption()
dd.SetCurrentOption((cur + step + n) % n)
case button >= 0:
f.SetFocus(min(max(pos+step, f.GetFormItemCount()), total-1))
move(min(max(pos+step, f.GetFormItemCount()), total-1))
default:
return ev
}
@@ -97,6 +109,9 @@ func arrowNavigation(f *tview.Form, cancel func(), hooks *browseHooks) {
})
}
// syncFocus gives a primitive the application's focus; New sets it.
var syncFocus func(p tview.Primitive)
func focusedDropDown(f *tview.Form, item int) (*tview.DropDown, bool) {
if item < 0 {
return nil, false