135 lines
4.3 KiB
Go
135 lines
4.3 KiB
Go
package keymap
|
|
|
|
import (
|
|
"testing"
|
|
|
|
uv "github.com/charmbracelet/ultraviolet"
|
|
)
|
|
|
|
func TestParseEvents(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
want uv.KeyPressEvent
|
|
}{
|
|
{"Enter", uv.KeyPressEvent{Code: uv.KeyEnter}},
|
|
{"enter", uv.KeyPressEvent{Code: uv.KeyEnter}},
|
|
{"Escape", uv.KeyPressEvent{Code: uv.KeyEscape}},
|
|
{"Esc", uv.KeyPressEvent{Code: uv.KeyEscape}},
|
|
{"Tab", uv.KeyPressEvent{Code: uv.KeyTab}},
|
|
{"BTab", uv.KeyPressEvent{Code: uv.KeyTab, Mod: uv.ModShift}},
|
|
{"S-Tab", uv.KeyPressEvent{Code: uv.KeyTab, Mod: uv.ModShift}},
|
|
{"Backspace", uv.KeyPressEvent{Code: uv.KeyBackspace}},
|
|
{"Space", uv.KeyPressEvent{Code: ' '}},
|
|
{"Up", uv.KeyPressEvent{Code: uv.KeyUp}},
|
|
{"Down", uv.KeyPressEvent{Code: uv.KeyDown}},
|
|
{"Left", uv.KeyPressEvent{Code: uv.KeyLeft}},
|
|
{"Right", uv.KeyPressEvent{Code: uv.KeyRight}},
|
|
{"Home", uv.KeyPressEvent{Code: uv.KeyHome}},
|
|
{"End", uv.KeyPressEvent{Code: uv.KeyEnd}},
|
|
{"PgUp", uv.KeyPressEvent{Code: uv.KeyPgUp}},
|
|
{"PageDown", uv.KeyPressEvent{Code: uv.KeyPgDown}},
|
|
{"Insert", uv.KeyPressEvent{Code: uv.KeyInsert}},
|
|
{"Delete", uv.KeyPressEvent{Code: uv.KeyDelete}},
|
|
{"F1", uv.KeyPressEvent{Code: uv.KeyF1}},
|
|
{"F12", uv.KeyPressEvent{Code: uv.KeyF12}},
|
|
{"a", uv.KeyPressEvent{Code: 'a'}},
|
|
{"Z", uv.KeyPressEvent{Code: 'Z'}},
|
|
{"%", uv.KeyPressEvent{Code: '%'}},
|
|
{"C-c", uv.KeyPressEvent{Code: 'c', Mod: uv.ModCtrl}},
|
|
{"C-C", uv.KeyPressEvent{Code: 'c', Mod: uv.ModCtrl}}, // normalized to lowercase
|
|
{"C-Space", uv.KeyPressEvent{Code: ' ', Mod: uv.ModCtrl}},
|
|
{"C-[", uv.KeyPressEvent{Code: '[', Mod: uv.ModCtrl}},
|
|
{"C-]", uv.KeyPressEvent{Code: ']', Mod: uv.ModCtrl}},
|
|
{"C-_", uv.KeyPressEvent{Code: '_', Mod: uv.ModCtrl}},
|
|
{"M-x", uv.KeyPressEvent{Code: 'x', Mod: uv.ModAlt}},
|
|
{"M-Enter", uv.KeyPressEvent{Code: uv.KeyEnter, Mod: uv.ModAlt}},
|
|
{"M-Escape", uv.KeyPressEvent{Code: uv.KeyEscape, Mod: uv.ModAlt}},
|
|
{"C-M-x", uv.KeyPressEvent{Code: 'x', Mod: uv.ModCtrl | uv.ModAlt}},
|
|
{"M-C-x", uv.KeyPressEvent{Code: 'x', Mod: uv.ModCtrl | uv.ModAlt}},
|
|
{"S-a", uv.KeyPressEvent{Code: 'A'}},
|
|
{"C-S-a", uv.KeyPressEvent{Code: 'a', Mod: uv.ModCtrl}}, // shift folds into the letter, ctrl re-lowers
|
|
{"-", uv.KeyPressEvent{Code: '-'}},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
k, err := Parse(tc.name)
|
|
if err != nil {
|
|
t.Fatalf("Parse(%q): %v", tc.name, err)
|
|
}
|
|
ev, ok := k.Event()
|
|
if !ok {
|
|
raw, _ := k.Raw()
|
|
t.Fatalf("Parse(%q) produced raw bytes %q, want event", tc.name, raw)
|
|
}
|
|
if ev != tc.want {
|
|
t.Errorf("Parse(%q) = %+v, want %+v", tc.name, ev, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Modified special keys have no vt-encoder support and must come out as
|
|
// pre-encoded xterm sequences: CSI 1;m<ch> and CSI n;m~ with
|
|
// m = 1 + Shift(1) + Alt(2) + Ctrl(4).
|
|
func TestParseModifiedSpecials(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
want string
|
|
}{
|
|
{"C-Up", "\x1b[1;5A"},
|
|
{"S-Up", "\x1b[1;2A"},
|
|
{"M-Up", "\x1b[1;3A"},
|
|
{"C-S-Up", "\x1b[1;6A"},
|
|
{"C-M-Up", "\x1b[1;7A"},
|
|
{"C-M-S-Up", "\x1b[1;8A"},
|
|
{"C-Down", "\x1b[1;5B"},
|
|
{"C-Right", "\x1b[1;5C"},
|
|
{"C-Left", "\x1b[1;5D"},
|
|
{"C-Home", "\x1b[1;5H"},
|
|
{"S-End", "\x1b[1;2F"},
|
|
{"C-F1", "\x1b[1;5P"},
|
|
{"S-F4", "\x1b[1;2S"},
|
|
{"C-Delete", "\x1b[3;5~"},
|
|
{"S-Insert", "\x1b[2;2~"},
|
|
{"M-PgUp", "\x1b[5;3~"},
|
|
{"C-PgDn", "\x1b[6;5~"},
|
|
{"C-F5", "\x1b[15;5~"},
|
|
{"S-F12", "\x1b[24;2~"},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
k, err := Parse(tc.name)
|
|
if err != nil {
|
|
t.Fatalf("Parse(%q): %v", tc.name, err)
|
|
}
|
|
raw, ok := k.Raw()
|
|
if !ok {
|
|
ev, _ := k.Event()
|
|
t.Fatalf("Parse(%q) produced event %+v, want raw bytes", tc.name, ev)
|
|
}
|
|
if string(raw) != tc.want {
|
|
t.Errorf("Parse(%q) = %q, want %q", tc.name, raw, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseErrors(t *testing.T) {
|
|
for _, name := range []string{
|
|
"", // empty
|
|
"NoSuch", // unknown named key
|
|
"C-", // dangling modifier
|
|
"X-a", // bad modifier letter
|
|
"C-1", // no control character for digits
|
|
"C--", // no control character for dash
|
|
"S-5", // shift is only meaningful on letters
|
|
"C-Enter", // no escape sequence exists
|
|
"ab", // multi-rune non-name
|
|
} {
|
|
t.Run("bad:"+name, func(t *testing.T) {
|
|
if k, err := Parse(name); err == nil {
|
|
t.Errorf("Parse(%q) succeeded (%+v), want error", name, k)
|
|
}
|
|
})
|
|
}
|
|
}
|