mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Let an editable view opt into receiving printable keys as keybindings
Printable keys are withheld from keybindings while the user is typing in a field, so that they end up as text. Decide that from the field that has the focus rather than from the view a binding happens to be registered for: a field can be embedded in another view, and that view's keys must be withheld too, or its bindings would swallow the characters. That makes it worth honouring KeybindOnEdit, which has been documented but ignored ever since it was introduced. A field that sets it sees printable keys offered to the keybindings first, and still gets them if no binding handles them, which is what lets a view keep its keys until the field has something to type into. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
28c5f5748c
commit
9e98b3d2f3
|
|
@ -2091,13 +2091,15 @@ func (g *Gui) isSuspended() bool {
|
|||
return g.suspended
|
||||
}
|
||||
|
||||
// matchView returns if the keybinding matches the current view (and the view's context)
|
||||
// matchView returns if the keybinding matches the given view (and the view's context)
|
||||
func (g *Gui) matchView(v *View, kb *keybinding) bool {
|
||||
// if the user is typing in a field, ignore char keys
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
if v.Editable && kb.key.IsPrintable() {
|
||||
// If the user is typing in a field, printable keys are theirs to type, so no
|
||||
// keybinding gets a look at them: not the field's own, and not those of the
|
||||
// view it is embedded in either.
|
||||
if field := g.currentView; field != nil && field.Editable && !field.KeybindOnEdit && kb.key.IsPrintable() {
|
||||
return false
|
||||
}
|
||||
if kb.viewName != v.name {
|
||||
|
|
|
|||
|
|
@ -56,6 +56,52 @@ func TestFirstMatchingKeybindingOfParentViewWins(t *testing.T) {
|
|||
assert.Equal(t, []string{"first"}, pressed)
|
||||
}
|
||||
|
||||
func TestPrintableKeysGoToTheFieldBeingTypedIn(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
keybindOnEdit bool
|
||||
declineKeybinding bool
|
||||
expectedPresses int
|
||||
expectedEdits int
|
||||
}{
|
||||
{name: "the field gets the key", expectedEdits: 1},
|
||||
{name: "the parent view gets the key", keybindOnEdit: true, expectedPresses: 1},
|
||||
{
|
||||
name: "the field gets the key the parent view declined",
|
||||
keybindOnEdit: true,
|
||||
declineKeybinding: true,
|
||||
expectedPresses: 1,
|
||||
expectedEdits: 1,
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
g := newTestGui(t)
|
||||
parent, child := setupParentAndChildView(t, g)
|
||||
child.Editable = true
|
||||
child.KeybindOnEdit = test.keybindOnEdit
|
||||
|
||||
edits := 0
|
||||
child.Editor = EditorFunc(func(*View, Key) bool {
|
||||
edits++
|
||||
return true
|
||||
})
|
||||
presses := 0
|
||||
g.SetKeybinding(parent.Name(), NewKeyRune('j'), func(*Gui, *View) error {
|
||||
presses++
|
||||
if test.declineKeybinding {
|
||||
return ErrKeybindingNotHandled
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
assert.NoError(t, g.onKey(&GocuiEvent{Type: eventKey, Key: NewKeyRune('j')}))
|
||||
|
||||
assert.Equal(t, test.expectedPresses, presses)
|
||||
assert.Equal(t, test.expectedEdits, edits)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnhandledKeybindingOfParentViewFallsThroughToEditor(t *testing.T) {
|
||||
g := newTestGui(t)
|
||||
parent, child := setupParentAndChildView(t, g)
|
||||
|
|
|
|||
Loading…
Reference in a new issue