2017-05-22 07:33:38 +08:00
|
|
|
package ui
|
2013-09-27 20:45:45 +08:00
|
|
|
|
2016-02-12 20:31:24 +08:00
|
|
|
import (
|
2016-09-15 20:54:43 +08:00
|
|
|
"bytes"
|
2016-02-12 20:31:24 +08:00
|
|
|
"fmt"
|
|
|
|
"strings"
|
2016-09-15 20:54:43 +08:00
|
|
|
|
2019-12-24 04:00:59 +08:00
|
|
|
"github.com/elves/elvish/pkg/parse"
|
2017-08-31 07:52:10 +08:00
|
|
|
"github.com/xiaq/persistent/hash"
|
2016-02-12 20:31:24 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// Key represents a single keyboard input, typically assembled from a escape
|
|
|
|
// sequence.
|
|
|
|
type Key struct {
|
|
|
|
Rune rune
|
|
|
|
Mod Mod
|
|
|
|
}
|
|
|
|
|
2019-03-11 00:51:46 +08:00
|
|
|
// K constructs a new Key.
|
|
|
|
func K(r rune, mods ...Mod) Key {
|
|
|
|
var mod Mod
|
|
|
|
for _, m := range mods {
|
|
|
|
mod |= m
|
|
|
|
}
|
|
|
|
return Key{r, mod}
|
|
|
|
}
|
|
|
|
|
2016-09-15 20:54:43 +08:00
|
|
|
// Default is used in the key binding table to indicate default binding.
|
|
|
|
var Default = Key{DefaultBindingRune, 0}
|
2016-02-12 10:44:08 +08:00
|
|
|
|
2015-02-25 05:56:38 +08:00
|
|
|
// Mod represents a modifier key.
|
2013-09-27 20:56:18 +08:00
|
|
|
type Mod byte
|
|
|
|
|
2015-02-25 05:56:38 +08:00
|
|
|
// Values for Mod.
|
2013-09-27 20:56:18 +08:00
|
|
|
const (
|
2015-02-25 05:56:38 +08:00
|
|
|
// Shift is the shift modifier. It is only applied to special keys (e.g.
|
|
|
|
// Shift-F1). For instance 'A' and '@' which are typically entered with the
|
|
|
|
// shift key pressed, are not considered to be shift-modified.
|
2013-09-27 20:56:18 +08:00
|
|
|
Shift Mod = 1 << iota
|
2015-02-25 05:56:38 +08:00
|
|
|
// Alt is the alt modifier, traditionally known as the meta modifier.
|
2013-09-27 20:56:18 +08:00
|
|
|
Alt
|
|
|
|
Ctrl
|
|
|
|
)
|
|
|
|
|
2018-01-03 14:17:07 +08:00
|
|
|
const functionKeyOffset = 1000
|
|
|
|
|
2016-09-15 20:54:43 +08:00
|
|
|
// Special negative runes to represent function keys, used in the Rune field of
|
|
|
|
// the Key struct.
|
|
|
|
const (
|
2018-01-03 14:17:07 +08:00
|
|
|
// DefaultBindingRune is a special value to represent default binding.
|
|
|
|
DefaultBindingRune rune = iota - functionKeyOffset
|
|
|
|
|
|
|
|
F1
|
2016-09-15 20:54:43 +08:00
|
|
|
F2
|
|
|
|
F3
|
|
|
|
F4
|
|
|
|
F5
|
|
|
|
F6
|
|
|
|
F7
|
|
|
|
F8
|
|
|
|
F9
|
|
|
|
F10
|
|
|
|
F11
|
|
|
|
F12
|
|
|
|
|
|
|
|
Up
|
|
|
|
Down
|
|
|
|
Right
|
|
|
|
Left
|
|
|
|
|
|
|
|
Home
|
|
|
|
Insert
|
|
|
|
Delete
|
|
|
|
End
|
|
|
|
PageUp
|
|
|
|
PageDown
|
|
|
|
|
|
|
|
// Some function key names are just aliases for their ASCII representation
|
|
|
|
|
|
|
|
Tab = '\t'
|
|
|
|
Enter = '\n'
|
|
|
|
Backspace = 0x7f
|
|
|
|
)
|
|
|
|
|
2018-01-03 14:17:07 +08:00
|
|
|
// functionKey stores the names of function keys, in the same order they appeared above.
|
2016-09-15 20:54:43 +08:00
|
|
|
var functionKeyNames = [...]string{
|
2018-01-03 14:17:07 +08:00
|
|
|
"Default",
|
2016-09-15 20:54:43 +08:00
|
|
|
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
|
|
|
|
"Up", "Down", "Right", "Left",
|
2018-01-03 14:17:07 +08:00
|
|
|
"Home", "Insert", "Delete", "End", "PageUp", "PageDown",
|
2016-09-15 20:54:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// keyNames stores the name of function keys with a positive rune.
|
|
|
|
var keyNames = map[rune]string{
|
|
|
|
Tab: "Tab", Enter: "Enter", Backspace: "Backspace",
|
|
|
|
}
|
|
|
|
|
2017-08-31 07:52:10 +08:00
|
|
|
func (k Key) Kind() string {
|
2020-03-31 12:55:49 +08:00
|
|
|
return "edit:key"
|
2017-08-31 07:52:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (k Key) Equal(other interface{}) bool {
|
2017-08-31 08:51:33 +08:00
|
|
|
return k == other
|
2017-08-31 07:52:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (k Key) Hash() uint32 {
|
2020-03-31 12:55:49 +08:00
|
|
|
return hash.DJB(uint32(k.Rune), uint32(k.Mod))
|
2017-08-31 07:52:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (k Key) Repr(int) string {
|
|
|
|
return "(edit:key " + parse.Quote(k.String()) + ")"
|
|
|
|
}
|
|
|
|
|
2016-09-15 20:54:43 +08:00
|
|
|
func (k Key) String() string {
|
|
|
|
var b bytes.Buffer
|
2014-01-16 09:24:14 +08:00
|
|
|
if k.Mod&Ctrl != 0 {
|
2016-09-15 20:54:43 +08:00
|
|
|
b.WriteString("Ctrl-")
|
2013-09-27 20:45:45 +08:00
|
|
|
}
|
2014-01-16 09:24:14 +08:00
|
|
|
if k.Mod&Alt != 0 {
|
2016-09-15 20:54:43 +08:00
|
|
|
b.WriteString("Alt-")
|
2013-09-27 20:45:45 +08:00
|
|
|
}
|
2014-03-10 00:12:12 +08:00
|
|
|
if k.Mod&Shift != 0 {
|
2016-09-15 20:54:43 +08:00
|
|
|
b.WriteString("Shift-")
|
2014-03-10 00:12:12 +08:00
|
|
|
}
|
2014-03-10 19:06:22 +08:00
|
|
|
if k.Rune > 0 {
|
2015-02-25 05:56:38 +08:00
|
|
|
if name, ok := keyNames[k.Rune]; ok {
|
2016-09-15 20:54:43 +08:00
|
|
|
b.WriteString(name)
|
2013-09-27 21:26:17 +08:00
|
|
|
} else {
|
2016-09-15 20:54:43 +08:00
|
|
|
b.WriteRune(k.Rune)
|
2013-09-27 21:26:17 +08:00
|
|
|
}
|
2013-09-27 20:45:45 +08:00
|
|
|
} else {
|
2018-01-03 14:17:07 +08:00
|
|
|
i := int(k.Rune + functionKeyOffset)
|
2020-04-01 05:58:17 +08:00
|
|
|
if i < 0 || i >= len(functionKeyNames) {
|
2018-01-03 14:17:07 +08:00
|
|
|
fmt.Fprintf(&b, "(bad function key %d)", k.Rune)
|
2016-02-12 10:44:08 +08:00
|
|
|
} else {
|
2018-01-03 14:17:07 +08:00
|
|
|
b.WriteString(functionKeyNames[i])
|
2016-02-12 10:44:08 +08:00
|
|
|
}
|
2013-09-27 20:45:45 +08:00
|
|
|
}
|
2016-09-15 20:54:43 +08:00
|
|
|
return b.String()
|
2013-09-27 20:45:45 +08:00
|
|
|
}
|
|
|
|
|
2016-02-12 20:31:24 +08:00
|
|
|
// modifierByName maps a name to an modifier. It is used for parsing keys where
|
|
|
|
// the modifier string is first turned to lower case, so that all of C, c,
|
|
|
|
// CTRL, Ctrl and ctrl can represent the Ctrl modifier.
|
|
|
|
var modifierByName = map[string]Mod{
|
|
|
|
"s": Shift, "shift": Shift,
|
|
|
|
"a": Alt, "alt": Alt,
|
|
|
|
"m": Alt, "meta": Alt,
|
|
|
|
"c": Ctrl, "ctrl": Ctrl,
|
|
|
|
}
|
|
|
|
|
2020-04-01 06:05:41 +08:00
|
|
|
// ParseKey parses a key. The syntax is:
|
2016-02-12 20:31:24 +08:00
|
|
|
//
|
|
|
|
// Key = { Mod ('+' | '-') } BareKey
|
|
|
|
//
|
|
|
|
// BareKey = FunctionKeyName | SingleRune
|
2020-04-01 06:05:41 +08:00
|
|
|
func ParseKey(s string) (Key, error) {
|
2016-02-12 20:31:24 +08:00
|
|
|
var k Key
|
|
|
|
// parse modifiers
|
|
|
|
for {
|
|
|
|
i := strings.IndexAny(s, "+-")
|
|
|
|
if i == -1 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
modname := strings.ToLower(s[:i])
|
|
|
|
mod, ok := modifierByName[modname]
|
|
|
|
if !ok {
|
2020-04-01 05:58:17 +08:00
|
|
|
return Key{}, fmt.Errorf("bad modifier: %s", parse.Quote(modname))
|
2016-02-12 20:31:24 +08:00
|
|
|
}
|
|
|
|
k.Mod |= mod
|
|
|
|
s = s[i+1:]
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(s) == 1 {
|
|
|
|
k.Rune = rune(s[0])
|
2016-09-16 22:01:22 +08:00
|
|
|
// XXX The following assumptions about keys with Ctrl are not checked
|
|
|
|
// with all terminals.
|
|
|
|
if k.Mod&Ctrl != 0 {
|
|
|
|
// Keys with Ctrl as one of the modifiers and a single ASCII letter
|
|
|
|
// as the base rune do not distinguish between cases. So we
|
|
|
|
// normalize the base rune to upper case.
|
|
|
|
if 'a' <= k.Rune && k.Rune <= 'z' {
|
|
|
|
k.Rune += 'A' - 'a'
|
|
|
|
}
|
|
|
|
// Tab is equivalent to Ctrl-I and Ctrl-J is equivalent to Enter.
|
|
|
|
// Normalize Ctrl-I to Tab and Ctrl-J to Enter.
|
|
|
|
if k.Rune == 'I' {
|
|
|
|
k.Mod &= ^Ctrl
|
|
|
|
k.Rune = Tab
|
|
|
|
} else if k.Rune == 'J' {
|
|
|
|
k.Mod &= ^Ctrl
|
|
|
|
k.Rune = Enter
|
|
|
|
}
|
|
|
|
}
|
2016-02-12 20:31:24 +08:00
|
|
|
return k, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for r, name := range keyNames {
|
|
|
|
if s == name {
|
|
|
|
k.Rune = r
|
|
|
|
return k, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-03 14:17:07 +08:00
|
|
|
for i, name := range functionKeyNames {
|
2016-02-12 20:31:24 +08:00
|
|
|
if s == name {
|
2018-01-03 14:17:07 +08:00
|
|
|
k.Rune = rune(i - functionKeyOffset)
|
2016-02-12 20:31:24 +08:00
|
|
|
return k, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-01 05:58:17 +08:00
|
|
|
return Key{}, fmt.Errorf("bad key: %s", parse.Quote(s))
|
2016-02-12 20:31:24 +08:00
|
|
|
}
|
|
|
|
|
2018-01-03 14:06:45 +08:00
|
|
|
// Keys implements sort.Interface.
|
|
|
|
type Keys []Key
|
|
|
|
|
|
|
|
func (ks Keys) Len() int { return len(ks) }
|
|
|
|
func (ks Keys) Swap(i, j int) { ks[i], ks[j] = ks[j], ks[i] }
|
|
|
|
func (ks Keys) Less(i, j int) bool {
|
|
|
|
return ks[i].Mod < ks[j].Mod ||
|
|
|
|
(ks[i].Mod == ks[j].Mod && ks[i].Rune < ks[j].Rune)
|
|
|
|
}
|