mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-18 14:34:52 +02:00
Refactor ShortcutTracker.Match() to respect AllowFallback priority order
Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com> Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/85fbf706-4688-4901-9a23-907cebc91da3
This commit is contained in:
committed by
GitHub
parent
9ea5441a2f
commit
6a0efbfdba
@@ -292,20 +292,44 @@ func isNonASCIIKey(key string) bool {
|
||||
}
|
||||
|
||||
func (self *KeyEvent) MatchesParsedShortcutWithFallback(ps *ParsedShortcut, event_type KeyEventType, allowFallback string) bool {
|
||||
return self.MatchesParsedShortcutPriorityWithFallback(ps, event_type, allowFallback) >= 0
|
||||
}
|
||||
|
||||
// MatchesParsedShortcutPriorityWithFallback returns the match priority for the given shortcut:
|
||||
// - returns -1 if the event does not match
|
||||
// - returns 0 for a direct match (no fallback needed)
|
||||
// - returns the 1-based position of the matching fallback type in allowFallback for a fallback match
|
||||
// (e.g., "shifted" at position 0 in "shifted,ascii" returns 1; "ascii" at position 1 returns 2)
|
||||
//
|
||||
// Lower values indicate higher priority, so callers should prefer matches with smaller return values.
|
||||
func (self *KeyEvent) MatchesParsedShortcutPriorityWithFallback(ps *ParsedShortcut, event_type KeyEventType, allowFallback string) int {
|
||||
if self.Type&event_type == 0 {
|
||||
return false
|
||||
return -1
|
||||
}
|
||||
mods := self.Mods.WithoutLocks()
|
||||
if mods == ps.Mods && self.Key == ps.KeyName {
|
||||
return true
|
||||
return 0
|
||||
}
|
||||
if strings.Contains(allowFallback, "shifted") && self.ShiftedKey != "" && mods&SHIFT != 0 && (mods & ^SHIFT) == ps.Mods && self.ShiftedKey == ps.KeyName {
|
||||
return true
|
||||
canShifted := self.ShiftedKey != "" && mods&SHIFT != 0 && (mods & ^SHIFT) == ps.Mods && self.ShiftedKey == ps.KeyName
|
||||
canASCII := self.AlternateKey != "" && isNonASCIIKey(self.Key) && mods == ps.Mods && self.AlternateKey == ps.KeyName
|
||||
for i, part := range strings.Split(allowFallback, ",") {
|
||||
switch strings.TrimSpace(part) {
|
||||
case "shifted":
|
||||
if canShifted {
|
||||
return i + 1
|
||||
}
|
||||
case "ascii":
|
||||
if canASCII {
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.Contains(allowFallback, "ascii") && self.AlternateKey != "" && isNonASCIIKey(self.Key) && mods == ps.Mods && self.AlternateKey == ps.KeyName {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return -1
|
||||
}
|
||||
|
||||
// MatchesPressOrRepeatPriorityWithFallback returns the match priority (see MatchesParsedShortcutPriorityWithFallback).
|
||||
func (self *KeyEvent) MatchesPressOrRepeatPriorityWithFallback(spec string, allowFallback string) int {
|
||||
return self.MatchesParsedShortcutPriorityWithFallback(ParseShortcut(spec), PRESS|REPEAT, allowFallback)
|
||||
}
|
||||
|
||||
func (self *KeyEvent) MatchesParsedShortcut(ps *ParsedShortcut, event_type KeyEventType) bool {
|
||||
|
||||
@@ -108,6 +108,60 @@ func TestMatchesParsedShortcutWithFallback(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchesParsedShortcutPriorityWithFallback(t *testing.T) {
|
||||
psA := ParseShortcut("a")
|
||||
psCtrlC := ParseShortcut("ctrl+c")
|
||||
|
||||
// Direct match: priority 0
|
||||
evDirect := &KeyEvent{Type: PRESS, Key: "a"}
|
||||
if p := evDirect.MatchesParsedShortcutPriorityWithFallback(psA, PRESS, ""); p != 0 {
|
||||
t.Fatalf("direct match should have priority 0, got %d", p)
|
||||
}
|
||||
|
||||
// No match: priority -1
|
||||
evNoMatch := &KeyEvent{Type: PRESS, Key: "b"}
|
||||
if p := evNoMatch.MatchesParsedShortcutPriorityWithFallback(psA, PRESS, "shifted,ascii"); p != -1 {
|
||||
t.Fatalf("no match should have priority -1, got %d", p)
|
||||
}
|
||||
|
||||
// Shifted fallback at position 0 in "shifted,ascii": priority 1
|
||||
evShifted := &KeyEvent{Type: PRESS, Mods: SHIFT, Key: "A", ShiftedKey: "a"}
|
||||
if p := evShifted.MatchesParsedShortcutPriorityWithFallback(psA, PRESS, "shifted,ascii"); p != 1 {
|
||||
t.Fatalf("shifted fallback first in 'shifted,ascii' should have priority 1, got %d", p)
|
||||
}
|
||||
|
||||
// Shifted fallback at position 1 in "ascii,shifted": priority 2
|
||||
if p := evShifted.MatchesParsedShortcutPriorityWithFallback(psA, PRESS, "ascii,shifted"); p != 2 {
|
||||
t.Fatalf("shifted fallback second in 'ascii,shifted' should have priority 2, got %d", p)
|
||||
}
|
||||
|
||||
// Shifted fallback only in "shifted": priority 1 (same as first position)
|
||||
if p := evShifted.MatchesParsedShortcutPriorityWithFallback(psA, PRESS, "shifted"); p != 1 {
|
||||
t.Fatalf("shifted fallback only in 'shifted' should have priority 1, got %d", p)
|
||||
}
|
||||
|
||||
// Shifted fallback not allowed: priority -1
|
||||
if p := evShifted.MatchesParsedShortcutPriorityWithFallback(psA, PRESS, "ascii"); p != -1 {
|
||||
t.Fatalf("shifted fallback not in 'ascii' should have priority -1, got %d", p)
|
||||
}
|
||||
|
||||
// ASCII (alternate key) fallback at position 1 in "shifted,ascii": priority 2
|
||||
evASCII := &KeyEvent{Type: PRESS, Mods: CTRL, Key: "с", AlternateKey: "c"}
|
||||
if p := evASCII.MatchesParsedShortcutPriorityWithFallback(psCtrlC, PRESS, "shifted,ascii"); p != 2 {
|
||||
t.Fatalf("ascii fallback second in 'shifted,ascii' should have priority 2, got %d", p)
|
||||
}
|
||||
|
||||
// ASCII fallback at position 0 in "ascii,shifted": priority 1
|
||||
if p := evASCII.MatchesParsedShortcutPriorityWithFallback(psCtrlC, PRESS, "ascii,shifted"); p != 1 {
|
||||
t.Fatalf("ascii fallback first in 'ascii,shifted' should have priority 1, got %d", p)
|
||||
}
|
||||
|
||||
// ASCII fallback only in "ascii": priority 1
|
||||
if p := evASCII.MatchesParsedShortcutPriorityWithFallback(psCtrlC, PRESS, "ascii"); p != 1 {
|
||||
t.Fatalf("ascii fallback only in 'ascii' should have priority 1, got %d", p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchesParsedShortcutUnconditionalAlternateKey(t *testing.T) {
|
||||
// Unconditional match via MatchesPressOrRepeat (hardcoded shortcuts)
|
||||
ev := &KeyEvent{Type: PRESS, Mods: CTRL, Key: "с", AlternateKey: "c"}
|
||||
|
||||
Reference in New Issue
Block a user