From 9d836514cfa67979351a641b34006a287352830a Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Tue, 15 Apr 2025 16:29:14 +0200 Subject: [PATCH 1/2] fix(key): accept both key.Text and key.String for key matches This commit fixes the key matching logic to accept both the key.Text and key.String representations of keys. This allows for more flexible key matching, especially when dealing with different keyboard layouts or input methods. Fixes: https://github.com/charmbracelet/bubbletea/issues/1390 --- key/key.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/key/key.go b/key/key.go index 0c79a7a2e..9cb688221 100644 --- a/key/key.go +++ b/key/key.go @@ -36,7 +36,11 @@ // to render help text for keystrokes in your views. package key -import "fmt" +import ( + "fmt" + + tea "github.com/charmbracelet/bubbletea/v2" +) // Binding describes a set of keybindings and, optionally, their associated // help text. @@ -128,10 +132,15 @@ type Help struct { // Matches checks if the given key matches the given bindings. func Matches[Key fmt.Stringer](k Key, b ...Binding) bool { + var txt string + switch v := any(k).(type) { + case tea.KeyMsg: + txt = v.Key().Text + } keys := k.String() for _, binding := range b { for _, v := range binding.keys { - if keys == v && binding.Enabled() { + if binding.Enabled() && (v == keys || (txt != "" && v == txt)) { return true } } From 8b901d55ffb8342a62209c0a91395b501f85c6d9 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Thu, 17 Apr 2025 16:45:08 +0200 Subject: [PATCH 2/2] chore(key): add Matches test --- key/key_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/key/key_test.go b/key/key_test.go index 359a4c265..aea0ef3b4 100644 --- a/key/key_test.go +++ b/key/key_test.go @@ -2,6 +2,8 @@ package key import ( "testing" + + tea "github.com/charmbracelet/bubbletea/v2" ) func TestBinding_Enabled(t *testing.T) { @@ -24,3 +26,44 @@ func TestBinding_Enabled(t *testing.T) { t.Errorf("expected key not to be Enabled") } } + +func TestMatches(t *testing.T) { + cases := []struct { + key tea.KeyMsg + bindings []Binding + }{ + { + key: tea.KeyPressMsg{Code: 'k', Text: "k"}, + bindings: []Binding{ + NewBinding( + WithKeys("k", "up"), + WithHelp("↑/k", "move up"), + ), + }, + }, + { + key: tea.KeyPressMsg{Code: '/', Mod: tea.ModShift, Text: "?"}, + bindings: []Binding{ + NewBinding( + WithKeys("?"), + WithHelp("?", "search"), + ), + }, + }, + { + key: tea.KeyPressMsg{Code: 'a', Mod: tea.ModCtrl}, + bindings: []Binding{ + NewBinding( + WithKeys("ctrl+a"), + WithHelp("ctrl+a", "select all"), + ), + }, + }, + } + + for i, c := range cases { + if !Matches(c.key, c.bindings...) { + t.Errorf("case %d: expected key (%q) to match binding(s)", i+1, c.key.String()) + } + } +}