Merge ae591692bbb5be93aaa102145ea3611ca29681b7 into 82a912274504477990ecf7c852eebb7c85291772
This commit is contained in:
commit
1dc872f06f
@ -3,13 +3,94 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
prompt "github.com/c-bata/go-prompt"
|
prompt "github.com/c-bata/go-prompt"
|
||||||
"github.com/c-bata/go-prompt/internal/term"
|
"github.com/c-bata/go-prompt/internal/term"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type KeyPress struct {
|
||||||
|
Key prompt.Key
|
||||||
|
Bytes []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parser struct {
|
||||||
|
Input chan rune
|
||||||
|
Out chan KeyPress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) Feed(r rune) {
|
||||||
|
p.Input <- r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) Start() {
|
||||||
|
prefix := bytes.NewBuffer(nil)
|
||||||
|
retry := false
|
||||||
|
for {
|
||||||
|
if retry {
|
||||||
|
retry = false
|
||||||
|
} else {
|
||||||
|
in, ok := <-p.Input
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
prefix.WriteRune(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
if prefix.Len() > 0 {
|
||||||
|
isPrefixOfLongerMatch := false
|
||||||
|
for _, s := range prompt.ASCIISequences {
|
||||||
|
if bytes.HasPrefix(s.ASCIICode, prefix.Bytes()) && bytes.Compare(s.ASCIICode, prefix.Bytes()) != 0 {
|
||||||
|
isPrefixOfLongerMatch = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match := prompt.GetKey(prefix.Bytes())
|
||||||
|
if !isPrefixOfLongerMatch && match != prompt.NotDefined {
|
||||||
|
p.Out <- KeyPress{Key: match, Bytes: prefix.Bytes()}
|
||||||
|
prefix.Reset()
|
||||||
|
} else if !isPrefixOfLongerMatch && match == prompt.NotDefined {
|
||||||
|
found := false
|
||||||
|
retry = true
|
||||||
|
|
||||||
|
prefixRunes := []rune(prefix.String())
|
||||||
|
for i := len(prefixRunes); i > 0; i-- {
|
||||||
|
prefixBytes := []byte(string(prefixRunes[:i]))
|
||||||
|
match = prompt.GetKey(prefixBytes)
|
||||||
|
if match != prompt.NotDefined {
|
||||||
|
p.Out <- KeyPress{Key: match, Bytes: prefixBytes}
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
_, _, _ = prefix.ReadRune()
|
||||||
|
}
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
r, _, err := prefix.ReadRune()
|
||||||
|
if err == io.EOF {
|
||||||
|
continue // don't reach here.
|
||||||
|
}
|
||||||
|
p.Out <- KeyPress{Key: match, Bytes: []byte(string(r))}
|
||||||
|
_, _, _ = prefix.ReadRune()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewParser() *Parser {
|
||||||
|
return &Parser{
|
||||||
|
Input: make(chan rune, 1),
|
||||||
|
Out: make(chan KeyPress, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := term.SetRaw(syscall.Stdin); err != nil {
|
if err := term.SetRaw(syscall.Stdin); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@ -17,31 +98,45 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer term.Restore()
|
defer term.Restore()
|
||||||
|
|
||||||
bufCh := make(chan []byte, 128)
|
p := NewParser()
|
||||||
go readBuffer(bufCh)
|
sigquit := make(chan os.Signal, 1)
|
||||||
fmt.Print("> ")
|
signal.Notify(sigquit, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
go p.Start()
|
||||||
|
|
||||||
|
r := bufio.NewReader(os.Stdin)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
c, _, err := r.ReadRune()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.Feed(c)
|
||||||
|
}
|
||||||
|
close(p.Input)
|
||||||
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
b := <-bufCh
|
select {
|
||||||
if key := prompt.GetKey(b); key == prompt.NotDefined {
|
case keypress := <-p.Out:
|
||||||
fmt.Printf("Key '%s' data:'%#v'\n", string(b), b)
|
if keypress.Key == prompt.NotDefined {
|
||||||
} else {
|
fmt.Printf("Key '%s' data:'%#v'\n", string(keypress.Bytes), keypress.Bytes)
|
||||||
if key == prompt.ControlC {
|
} else {
|
||||||
fmt.Println("exit.")
|
fmt.Printf("Key '%s' data:'%#v'\n", keypress.Key, keypress.Bytes)
|
||||||
|
if keypress.Key == prompt.ControlC {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if keypress.Key == prompt.ControlC {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Printf("Key '%s' data:'%#v'\n", key, b)
|
case <-sigquit:
|
||||||
}
|
close(p.Input)
|
||||||
fmt.Print("> ")
|
return
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func readBuffer(bufCh chan []byte) {
|
|
||||||
buf := make([]byte, 1024)
|
|
||||||
|
|
||||||
for {
|
|
||||||
if n, err := syscall.Read(syscall.Stdin, buf); err == nil {
|
|
||||||
bufCh <- buf[:n]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
input.go
2
input.go
@ -96,7 +96,7 @@ var ASCIISequences = []*ASCIICode{
|
|||||||
{Key: F3, ASCIICode: []byte{0x1b, 0x4f, 0x52}},
|
{Key: F3, ASCIICode: []byte{0x1b, 0x4f, 0x52}},
|
||||||
{Key: F4, ASCIICode: []byte{0x1b, 0x4f, 0x53}},
|
{Key: F4, ASCIICode: []byte{0x1b, 0x4f, 0x53}},
|
||||||
|
|
||||||
{Key: F1, ASCIICode: []byte{0x1b, 0x4f, 0x50, 0x41}}, // Linux console
|
{Key: F1, ASCIICode: []byte{0x1b, 0x4f, 0x5b, 0x41}}, // Linux console
|
||||||
{Key: F2, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x42}}, // Linux console
|
{Key: F2, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x42}}, // Linux console
|
||||||
{Key: F3, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x43}}, // Linux console
|
{Key: F3, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x43}}, // Linux console
|
||||||
{Key: F4, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x44}}, // Linux console
|
{Key: F4, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x44}}, // Linux console
|
||||||
|
Loading…
Reference in New Issue
Block a user