diff --git a/action.go b/action.go index 2c2f159..7ff5dc3 100644 --- a/action.go +++ b/action.go @@ -1,6 +1,7 @@ package peco import ( + "encoding/json" "unicode" "github.com/nsf/termbox-go" @@ -24,7 +25,7 @@ type ActionFunc func(*Input, termbox.Event) var nameToActions map[string]Action // This is the default keybinding used by NewKeymap() -var defaultKeyBinding map[termbox.Key]Action +var defaultKeyBinding map[string]Action // Execute fulfills the Action interface for AfterFunc func (a ActionFunc) Execute(i *Input, e termbox.Event) { @@ -37,18 +38,22 @@ func (a ActionFunc) Execute(i *Input, e termbox.Event) { func (a ActionFunc) Register(name string, defaultKeys ...termbox.Key) { nameToActions["peco."+name] = a for _, k := range defaultKeys { - Keyseq.Add(keyseq.KeyList{keyseq.NewKeyFromKey(k)}, a) + a.RegisterKeySequence(keyseq.KeyList{keyseq.NewKeyFromKey(k)}) } } func (a ActionFunc) RegisterKeySequence(k keyseq.KeyList) { - Keyseq.Add(k, a) + b, err := json.Marshal(k) + if err != nil { + panic(err) + } + defaultKeyBinding[string(b)] = a } func init() { // Build the global maps nameToActions = map[string]Action{} - defaultKeyBinding = map[termbox.Key]Action{} + defaultKeyBinding = map[string]Action{} ActionFunc(doBeginningOfLine).Register("BeginningOfLine", termbox.KeyCtrlA) ActionFunc(doBackwardChar).Register("BackwardChar", termbox.KeyCtrlB) @@ -109,21 +114,19 @@ func init() { ActionFunc(doKonamiCommand).RegisterKeySequence( keyseq.KeyList{ - keyseq.Key{0,termbox.KeyCtrlX,0}, - keyseq.Key{0,termbox.KeyArrowUp,0}, - keyseq.Key{0,termbox.KeyArrowUp,0}, - keyseq.Key{0,termbox.KeyArrowDown,0}, - keyseq.Key{0,termbox.KeyArrowDown,0}, - keyseq.Key{0,termbox.KeyArrowLeft,0}, - keyseq.Key{0,termbox.KeyArrowRight,0}, - keyseq.Key{0,termbox.KeyArrowLeft,0}, - keyseq.Key{0,termbox.KeyArrowRight,0}, - keyseq.Key{0,0,'b'}, - keyseq.Key{0,0,'a'}, + keyseq.Key{0, termbox.KeyCtrlX, 0}, + keyseq.Key{0, termbox.KeyArrowUp, 0}, + keyseq.Key{0, termbox.KeyArrowUp, 0}, + keyseq.Key{0, termbox.KeyArrowDown, 0}, + keyseq.Key{0, termbox.KeyArrowDown, 0}, + keyseq.Key{0, termbox.KeyArrowLeft, 0}, + keyseq.Key{0, termbox.KeyArrowRight, 0}, + keyseq.Key{0, termbox.KeyArrowLeft, 0}, + keyseq.Key{0, termbox.KeyArrowRight, 0}, + keyseq.Key{0, 0, 'b'}, + keyseq.Key{0, 0, 'a'}, }, ) - - Keyseq.Compile() } // This is a noop action @@ -224,8 +227,8 @@ func doFinish(i *Input, _ termbox.Event) { } func doCancel(i *Input, ev termbox.Event) { - if Keyseq.InMiddleOfChain() { - Keyseq.CancelChain() + if i.currentKeymap.Keyseq.InMiddleOfChain() { + i.currentKeymap.Keyseq.CancelChain() return } diff --git a/ctx.go b/ctx.go index 4420574..985525a 100644 --- a/ctx.go +++ b/ctx.go @@ -245,7 +245,7 @@ func (c *Ctx) NewInput() *Input { // Create a new keymap object k := NewKeymap() k.ApplyConfig(c.config.Keymap) - return &Input{c, &sync.Mutex{}, nil, k, false} + return &Input{c, &sync.Mutex{}, nil, k} } func (c *Ctx) Stop() { diff --git a/input.go b/input.go index 922dde8..a97c41c 100644 --- a/input.go +++ b/input.go @@ -12,7 +12,6 @@ type Input struct { mutex *sync.Mutex // Currently only used for protecting Alt/Esc workaround mod *time.Timer currentKeymap Keymap - chained bool } func (i *Input) Loop() { @@ -84,7 +83,7 @@ func (i *Input) handleInputEvent(ev termbox.Event) { } func (i *Input) handleKeyEvent(ev termbox.Event) { - if h := i.currentKeymap.Handler(ev, i.chained); h != nil { + if h := i.currentKeymap.Handler(ev); h != nil { h.Execute(i, ev) return } diff --git a/keymap.go b/keymap.go index 3afaba8..7b2061a 100644 --- a/keymap.go +++ b/keymap.go @@ -1,6 +1,7 @@ package peco import ( + "encoding/json" "fmt" "os" "strings" @@ -16,13 +17,9 @@ const ( ModMax ) -// Keyseq does successive matches against key events. -var Keyseq = keyseq.New() - -type Keymap [ModMax]RawKeymap - -// RawKeymap contains the actual mapping from termbox.Key to Action -type RawKeymap map[termbox.Key]Action +type Keymap struct { + Keyseq *keyseq.Keyseq +} type KeymapStringKey string @@ -153,24 +150,26 @@ func (ksk KeymapStringKey) ToKey() (k termbox.Key, modifier int, ch rune, err er } func NewKeymap() Keymap { - def := RawKeymap{} - for k, v := range defaultKeyBinding { - def[k] = v - } - return Keymap{ - def, - {}, + k := keyseq.New() + for s, a := range defaultKeyBinding { + kl := keyseq.KeyList{} + if err := json.Unmarshal([]byte(s), &kl); err != nil { + panic(err) + } + k.Add(kl, a) } + k.Compile() + return Keymap{k} } -func (km Keymap) Handler(ev termbox.Event, chained bool) Action { +func (km Keymap) Handler(ev termbox.Event) Action { modifier := ModNone if (ev.Mod & termbox.ModAlt) != 0 { modifier = ModAlt } key := keyseq.Key{modifier, ev.Key, ev.Ch} - action, err := Keyseq.AcceptKey(key) + action, err := km.Keyseq.AcceptKey(key) switch err { case nil: @@ -204,11 +203,11 @@ func (km Keymap) ApplyConfig(c map[string]string) { continue } - Keyseq.Add(list, v) + km.Keyseq.Add(list, v) } } // TODO: this needs to be fixed. func (km Keymap) hasModifierMaps() bool { - return len(km[ModAlt]) > 0 + return false } diff --git a/keymap_test.go b/keymap_test.go index cee9b52..5c31af3 100644 --- a/keymap_test.go +++ b/keymap_test.go @@ -39,26 +39,31 @@ func TestKeymapStrToKeyValue(t *testing.T) { } func TestKeymapStrToKeyValueWithAlt(t *testing.T) { - expected := map[string]termbox.Key{ - "M-v": termbox.Key('v'), - "M-C-v": termbox.KeyCtrlV, - "M-Space": termbox.KeySpace, - "M-MouseLeft": termbox.MouseLeft, + expected := map[string]struct{ + key termbox.Key + ch rune + } { + "M-v": {0, 'v'}, + "M-C-v": {termbox.KeyCtrlV,rune(0)}, + "M-Space": {termbox.KeySpace, rune(0)}, + "M-MouseLeft": {termbox.MouseLeft, rune(0)}, } t.Logf("Checking Alt prefixed key name mapping...") for n, v := range expected { t.Logf(" checking %s...", n) - // TODO ch isn't being checked - k, modifier, _, err := KeymapStringKey(n).ToKey() + k, modifier, ch, err := KeymapStringKey(n).ToKey() if err != nil { t.Errorf("Failed ToKey: Key name %s", n) } if modifier != 1 { t.Errorf("Key name %s has Alt prefix", n) } - if k != v { - t.Errorf("Expected '%s' to be '%d', but got '%d'", n, v, stringToKey[n]) + if k != v.key { + t.Errorf("Expected '%s' to be '%d', but got '%d'", n, v.key, k) + } + if ch != v.ch { + t.Errorf("Expected '%s' to be '%c', but got '%c'", n, v.ch, ch) } } }