elvish/edit/reader.go
2013-09-23 18:06:52 +08:00

127 lines
1.7 KiB
Go

package edit
import (
"time"
"../async"
)
var EscTimeout = time.Millisecond * 10
type Key struct {
rune
Ctrl bool
Alt bool
}
var ZeroKey = Key{}
func PlainKey(r rune) Key {
return Key{rune: r}
}
func CtrlKey(r rune) Key {
return Key{rune: r, Ctrl: true}
}
func AltKey(r rune) Key {
return Key{rune: r, Alt: true}
}
func (k Key) String() (s string) {
if k.Ctrl {
s += "Ctrl-"
}
if k.Alt {
s += "Alt-"
}
s += string(k.rune)
return
}
const (
F1 rune = -1-iota
F2
F3
F4
F5
F6
F7
F8
F9
F10
F11
F12
Escape // ^[
Backspace // ^?
Up // ^[OA
Down // ^[OB
Right // ^[OC
Left // ^[OD
Home // ^[[1~
Insert // ^[[2~
Delete // ^[[3~
End // ^[[4~
PageUp // ^[[5~
PageDown // ^[[6~
)
// reader is the part of an Editor responsible for reading and decoding
// terminal key sequences.
type reader struct {
runeReader *async.RuneReader
readAhead []Key
}
func newReader(rr *async.RuneReader) *reader {
return &reader{
rr,
make([]Key, 0),
}
}
// type readerState func(rune) (bool, readerState)
func (rd *reader) readKey() (k Key, err error) {
if n := len(rd.readAhead); n > 0 {
k = rd.readAhead[0]
rd.readAhead = rd.readAhead[1:]
return
}
r, _, err := rd.runeReader.ReadRune()
if err != nil {
return
}
switch r {
case 0x0:
k = CtrlKey('`')
case 0x1d:
k = CtrlKey('6')
case 0x1f:
k = CtrlKey('/')
case 0x7f:
k = PlainKey(Backspace)
case 0x1b:
// ^[, or Escape
r, _, e := rd.runeReader.ReadRuneTimeout(EscTimeout)
if e == async.Timeout {
return CtrlKey('['), nil
} else if e != nil {
return ZeroKey, e
}
return AltKey(r), nil
default:
if 0x1 <= r && r <= 0x1d {
k = CtrlKey(r+0x40)
} else {
k = PlainKey(r)
}
}
return
}