285 lines
7.4 KiB
Go
285 lines
7.4 KiB
Go
|
package config
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/gdamore/tcell"
|
||
|
)
|
||
|
|
||
|
type KeyStroke struct {
|
||
|
Key tcell.Key
|
||
|
Rune rune
|
||
|
}
|
||
|
|
||
|
type Binding struct {
|
||
|
Output []KeyStroke
|
||
|
Input []KeyStroke
|
||
|
}
|
||
|
|
||
|
type KeyBindings []*Binding
|
||
|
|
||
|
const (
|
||
|
BINDING_FOUND = iota
|
||
|
BINDING_INCOMPLETE
|
||
|
BINDING_NOT_FOUND
|
||
|
)
|
||
|
|
||
|
type BindingSearchResult int
|
||
|
|
||
|
func NewKeyBindings() *KeyBindings {
|
||
|
return &KeyBindings{}
|
||
|
}
|
||
|
|
||
|
func (bindings *KeyBindings) Add(binding *Binding) {
|
||
|
// TODO: Search for conflicts?
|
||
|
*bindings = append(*bindings, binding)
|
||
|
}
|
||
|
|
||
|
func (bindings *KeyBindings) GetBinding(
|
||
|
input []KeyStroke) (BindingSearchResult, []KeyStroke) {
|
||
|
|
||
|
incomplete := false
|
||
|
// TODO: This could probably be a sorted list to speed things up
|
||
|
// TODO: Deal with bindings that share a prefix
|
||
|
for _, binding := range *bindings {
|
||
|
if len(binding.Input) < len(input) {
|
||
|
continue
|
||
|
}
|
||
|
for i, stroke := range input {
|
||
|
if stroke != binding.Input[i] {
|
||
|
goto next
|
||
|
}
|
||
|
}
|
||
|
if len(binding.Input) != len(input) {
|
||
|
incomplete = true
|
||
|
} else {
|
||
|
return BINDING_FOUND, binding.Output
|
||
|
}
|
||
|
next:
|
||
|
}
|
||
|
if incomplete {
|
||
|
return BINDING_INCOMPLETE, nil
|
||
|
}
|
||
|
return BINDING_NOT_FOUND, nil
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
keyNames map[string]tcell.Key
|
||
|
)
|
||
|
|
||
|
func ParseKeyStrokes(keystrokes string) ([]KeyStroke, error) {
|
||
|
var strokes []KeyStroke
|
||
|
buf := bytes.NewBufferString(keystrokes)
|
||
|
for {
|
||
|
tok, _, err := buf.ReadRune()
|
||
|
if err == io.EOF {
|
||
|
break
|
||
|
} else if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
// TODO: make it possible to bind to < or > themselves (and default to
|
||
|
// switching accounts)
|
||
|
switch tok {
|
||
|
case '<':
|
||
|
name, err := buf.ReadString(byte('>'))
|
||
|
if err == io.EOF {
|
||
|
return nil, errors.New("Expecting '>'")
|
||
|
} else if err != nil {
|
||
|
return nil, err
|
||
|
} else if name == ">" {
|
||
|
return nil, errors.New("Expected a key name")
|
||
|
}
|
||
|
name = name[:len(name)-1]
|
||
|
if key, ok := keyNames[strings.ToLower(name)]; ok {
|
||
|
strokes = append(strokes, KeyStroke{
|
||
|
Key: key,
|
||
|
})
|
||
|
} else {
|
||
|
return nil, errors.New(fmt.Sprintf("Unknown key '%s'", name))
|
||
|
}
|
||
|
case '>':
|
||
|
return nil, errors.New("Found '>' without '<'")
|
||
|
default:
|
||
|
strokes = append(strokes, KeyStroke{
|
||
|
Key: tcell.KeyRune,
|
||
|
Rune: tok,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
return strokes, nil
|
||
|
}
|
||
|
|
||
|
func ParseBinding(input, output string) (*Binding, error) {
|
||
|
in, err := ParseKeyStrokes(input)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
out, err := ParseKeyStrokes(output)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &Binding{
|
||
|
Input: in,
|
||
|
Output: out,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func init() {
|
||
|
keyNames = make(map[string]tcell.Key)
|
||
|
keyNames["up"] = tcell.KeyUp
|
||
|
keyNames["down"] = tcell.KeyDown
|
||
|
keyNames["right"] = tcell.KeyRight
|
||
|
keyNames["left"] = tcell.KeyLeft
|
||
|
keyNames["upleft"] = tcell.KeyUpLeft
|
||
|
keyNames["upright"] = tcell.KeyUpRight
|
||
|
keyNames["downleft"] = tcell.KeyDownLeft
|
||
|
keyNames["downright"] = tcell.KeyDownRight
|
||
|
keyNames["center"] = tcell.KeyCenter
|
||
|
keyNames["pgup"] = tcell.KeyPgUp
|
||
|
keyNames["pgdn"] = tcell.KeyPgDn
|
||
|
keyNames["home"] = tcell.KeyHome
|
||
|
keyNames["end"] = tcell.KeyEnd
|
||
|
keyNames["insert"] = tcell.KeyInsert
|
||
|
keyNames["delete"] = tcell.KeyDelete
|
||
|
keyNames["help"] = tcell.KeyHelp
|
||
|
keyNames["exit"] = tcell.KeyExit
|
||
|
keyNames["clear"] = tcell.KeyClear
|
||
|
keyNames["cancel"] = tcell.KeyCancel
|
||
|
keyNames["print"] = tcell.KeyPrint
|
||
|
keyNames["pause"] = tcell.KeyPause
|
||
|
keyNames["backtab"] = tcell.KeyBacktab
|
||
|
keyNames["f1"] = tcell.KeyF1
|
||
|
keyNames["f2"] = tcell.KeyF2
|
||
|
keyNames["f3"] = tcell.KeyF3
|
||
|
keyNames["f4"] = tcell.KeyF4
|
||
|
keyNames["f5"] = tcell.KeyF5
|
||
|
keyNames["f6"] = tcell.KeyF6
|
||
|
keyNames["f7"] = tcell.KeyF7
|
||
|
keyNames["f8"] = tcell.KeyF8
|
||
|
keyNames["f9"] = tcell.KeyF9
|
||
|
keyNames["f10"] = tcell.KeyF10
|
||
|
keyNames["f11"] = tcell.KeyF11
|
||
|
keyNames["f12"] = tcell.KeyF12
|
||
|
keyNames["f13"] = tcell.KeyF13
|
||
|
keyNames["f14"] = tcell.KeyF14
|
||
|
keyNames["f15"] = tcell.KeyF15
|
||
|
keyNames["f16"] = tcell.KeyF16
|
||
|
keyNames["f17"] = tcell.KeyF17
|
||
|
keyNames["f18"] = tcell.KeyF18
|
||
|
keyNames["f19"] = tcell.KeyF19
|
||
|
keyNames["f20"] = tcell.KeyF20
|
||
|
keyNames["f21"] = tcell.KeyF21
|
||
|
keyNames["f22"] = tcell.KeyF22
|
||
|
keyNames["f23"] = tcell.KeyF23
|
||
|
keyNames["f24"] = tcell.KeyF24
|
||
|
keyNames["f25"] = tcell.KeyF25
|
||
|
keyNames["f26"] = tcell.KeyF26
|
||
|
keyNames["f27"] = tcell.KeyF27
|
||
|
keyNames["f28"] = tcell.KeyF28
|
||
|
keyNames["f29"] = tcell.KeyF29
|
||
|
keyNames["f30"] = tcell.KeyF30
|
||
|
keyNames["f31"] = tcell.KeyF31
|
||
|
keyNames["f32"] = tcell.KeyF32
|
||
|
keyNames["f33"] = tcell.KeyF33
|
||
|
keyNames["f34"] = tcell.KeyF34
|
||
|
keyNames["f35"] = tcell.KeyF35
|
||
|
keyNames["f36"] = tcell.KeyF36
|
||
|
keyNames["f37"] = tcell.KeyF37
|
||
|
keyNames["f38"] = tcell.KeyF38
|
||
|
keyNames["f39"] = tcell.KeyF39
|
||
|
keyNames["f40"] = tcell.KeyF40
|
||
|
keyNames["f41"] = tcell.KeyF41
|
||
|
keyNames["f42"] = tcell.KeyF42
|
||
|
keyNames["f43"] = tcell.KeyF43
|
||
|
keyNames["f44"] = tcell.KeyF44
|
||
|
keyNames["f45"] = tcell.KeyF45
|
||
|
keyNames["f46"] = tcell.KeyF46
|
||
|
keyNames["f47"] = tcell.KeyF47
|
||
|
keyNames["f48"] = tcell.KeyF48
|
||
|
keyNames["f49"] = tcell.KeyF49
|
||
|
keyNames["f50"] = tcell.KeyF50
|
||
|
keyNames["f51"] = tcell.KeyF51
|
||
|
keyNames["f52"] = tcell.KeyF52
|
||
|
keyNames["f53"] = tcell.KeyF53
|
||
|
keyNames["f54"] = tcell.KeyF54
|
||
|
keyNames["f55"] = tcell.KeyF55
|
||
|
keyNames["f56"] = tcell.KeyF56
|
||
|
keyNames["f57"] = tcell.KeyF57
|
||
|
keyNames["f58"] = tcell.KeyF58
|
||
|
keyNames["f59"] = tcell.KeyF59
|
||
|
keyNames["f60"] = tcell.KeyF60
|
||
|
keyNames["f61"] = tcell.KeyF61
|
||
|
keyNames["f62"] = tcell.KeyF62
|
||
|
keyNames["f63"] = tcell.KeyF63
|
||
|
keyNames["f64"] = tcell.KeyF64
|
||
|
keyNames["c-space"] = tcell.KeyCtrlSpace
|
||
|
keyNames["c-a"] = tcell.KeyCtrlA
|
||
|
keyNames["c-b"] = tcell.KeyCtrlB
|
||
|
keyNames["c-c"] = tcell.KeyCtrlC
|
||
|
keyNames["c-d"] = tcell.KeyCtrlD
|
||
|
keyNames["c-e"] = tcell.KeyCtrlE
|
||
|
keyNames["c-f"] = tcell.KeyCtrlF
|
||
|
keyNames["c-g"] = tcell.KeyCtrlG
|
||
|
keyNames["c-h"] = tcell.KeyCtrlH
|
||
|
keyNames["c-i"] = tcell.KeyCtrlI
|
||
|
keyNames["c-j"] = tcell.KeyCtrlJ
|
||
|
keyNames["c-k"] = tcell.KeyCtrlK
|
||
|
keyNames["c-l"] = tcell.KeyCtrlL
|
||
|
keyNames["c-m"] = tcell.KeyCtrlM
|
||
|
keyNames["c-n"] = tcell.KeyCtrlN
|
||
|
keyNames["c-o"] = tcell.KeyCtrlO
|
||
|
keyNames["c-p"] = tcell.KeyCtrlP
|
||
|
keyNames["c-q"] = tcell.KeyCtrlQ
|
||
|
keyNames["c-r"] = tcell.KeyCtrlR
|
||
|
keyNames["c-s"] = tcell.KeyCtrlS
|
||
|
keyNames["c-t"] = tcell.KeyCtrlT
|
||
|
keyNames["c-u"] = tcell.KeyCtrlU
|
||
|
keyNames["c-v"] = tcell.KeyCtrlV
|
||
|
keyNames["c-w"] = tcell.KeyCtrlW
|
||
|
keyNames["c-x"] = tcell.KeyCtrlX
|
||
|
keyNames["c-y"] = tcell.KeyCtrlY
|
||
|
keyNames["c-z"] = tcell.KeyCtrlZ
|
||
|
keyNames["c-]"] = tcell.KeyCtrlLeftSq
|
||
|
keyNames["c-\\"] = tcell.KeyCtrlBackslash
|
||
|
keyNames["c-["] = tcell.KeyCtrlRightSq
|
||
|
keyNames["c-^"] = tcell.KeyCtrlCarat
|
||
|
keyNames["c-_"] = tcell.KeyCtrlUnderscore
|
||
|
keyNames["NUL"] = tcell.KeyNUL
|
||
|
keyNames["SOH"] = tcell.KeySOH
|
||
|
keyNames["STX"] = tcell.KeySTX
|
||
|
keyNames["ETX"] = tcell.KeyETX
|
||
|
keyNames["EOT"] = tcell.KeyEOT
|
||
|
keyNames["ENQ"] = tcell.KeyENQ
|
||
|
keyNames["ACK"] = tcell.KeyACK
|
||
|
keyNames["BEL"] = tcell.KeyBEL
|
||
|
keyNames["BS"] = tcell.KeyBS
|
||
|
keyNames["TAB"] = tcell.KeyTAB
|
||
|
keyNames["LF"] = tcell.KeyLF
|
||
|
keyNames["VT"] = tcell.KeyVT
|
||
|
keyNames["FF"] = tcell.KeyFF
|
||
|
keyNames["CR"] = tcell.KeyCR
|
||
|
keyNames["SO"] = tcell.KeySO
|
||
|
keyNames["SI"] = tcell.KeySI
|
||
|
keyNames["DLE"] = tcell.KeyDLE
|
||
|
keyNames["DC1"] = tcell.KeyDC1
|
||
|
keyNames["DC2"] = tcell.KeyDC2
|
||
|
keyNames["DC3"] = tcell.KeyDC3
|
||
|
keyNames["DC4"] = tcell.KeyDC4
|
||
|
keyNames["NAK"] = tcell.KeyNAK
|
||
|
keyNames["SYN"] = tcell.KeySYN
|
||
|
keyNames["ETB"] = tcell.KeyETB
|
||
|
keyNames["CAN"] = tcell.KeyCAN
|
||
|
keyNames["EM"] = tcell.KeyEM
|
||
|
keyNames["SUB"] = tcell.KeySUB
|
||
|
keyNames["ESC"] = tcell.KeyESC
|
||
|
keyNames["FS"] = tcell.KeyFS
|
||
|
keyNames["GS"] = tcell.KeyGS
|
||
|
keyNames["RS"] = tcell.KeyRS
|
||
|
keyNames["US"] = tcell.KeyUS
|
||
|
keyNames["DEL"] = tcell.KeyDEL
|
||
|
}
|