This commit is contained in:
Masashi Shibata 2021-03-06 02:19:18 +05:30 committed by GitHub
commit 1dc872f06f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 117 additions and 22 deletions

View File

@ -3,13 +3,94 @@
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"os/signal"
"syscall"
prompt "github.com/c-bata/go-prompt"
"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() {
if err := term.SetRaw(syscall.Stdin); err != nil {
fmt.Println(err)
@ -17,31 +98,45 @@ func main() {
}
defer term.Restore()
bufCh := make(chan []byte, 128)
go readBuffer(bufCh)
fmt.Print("> ")
p := NewParser()
sigquit := make(chan os.Signal, 1)
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 {
b := <-bufCh
if key := prompt.GetKey(b); key == prompt.NotDefined {
fmt.Printf("Key '%s' data:'%#v'\n", string(b), b)
} else {
if key == prompt.ControlC {
fmt.Println("exit.")
select {
case keypress := <-p.Out:
if keypress.Key == prompt.NotDefined {
fmt.Printf("Key '%s' data:'%#v'\n", string(keypress.Bytes), keypress.Bytes)
} else {
fmt.Printf("Key '%s' data:'%#v'\n", keypress.Key, keypress.Bytes)
if keypress.Key == prompt.ControlC {
return
}
}
if keypress.Key == prompt.ControlC {
return
}
fmt.Printf("Key '%s' data:'%#v'\n", key, b)
}
fmt.Print("> ")
}
}
func readBuffer(bufCh chan []byte) {
buf := make([]byte, 1024)
for {
if n, err := syscall.Read(syscall.Stdin, buf); err == nil {
bufCh <- buf[:n]
case <-sigquit:
close(p.Input)
return
}
}
}

View File

@ -96,7 +96,7 @@ var ASCIISequences = []*ASCIICode{
{Key: F3, ASCIICode: []byte{0x1b, 0x4f, 0x52}},
{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: F3, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x43}}, // Linux console
{Key: F4, ASCIICode: []byte{0x1b, 0x5b, 0x5b, 0x44}}, // Linux console