This commit is contained in:
c-bata 2017-07-14 10:51:19 +09:00
parent b9fa638633
commit d8e4a92790
7 changed files with 192 additions and 55 deletions

20
erasing.go Normal file
View File

@ -0,0 +1,20 @@
package main
import "github.com/c-bata/go-prompt-toolkit/prompt"
func main() {
l := 20
out := prompt.NewVT100Writer()
for i := 0; i < l; i++ {
out.CursorGoTo(i, 0)
out.WriteStr("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
}
out.CursorGoTo(5, 10)
out.EraseLine()
out.CursorGoTo(l, 0)
out.Flush()
return
}

106
main.go
View File

@ -3,18 +3,18 @@ package main
import (
"fmt"
"syscall"
"os"
"os/signal"
"github.com/c-bata/go-prompt-toolkit/prompt"
)
func enterAlternateScreen(fd int) {
syscall.Write(fd, []byte{0x1b, 0x5b, 0x3f, 0x01, 0x00, 0x04, 0x09, 0x68, 0x1b, 0x5b, 0x48})
}
func scroll(out *prompt.VT100Writer, lines int) {
for i := 0; i < lines; i++ {
out.ScrollDown()
defer out.ScrollUp()
}
for i := 0; i < lines; i++ {
out.ScrollUp()
}
return
}
@ -23,8 +23,14 @@ func main() {
in := prompt.NewVT100Parser()
in.Setup()
defer in.TearDown()
defer fmt.Println("\nexited!")
defer fmt.Println("\nGoodbye!")
out := prompt.NewVT100Writer()
renderer := prompt.Render{
Prefix: ">>> ",
Out: out,
}
out.SetTitle("はろー")
scroll(out, 7)
out.Flush()
@ -32,68 +38,27 @@ func main() {
bufCh := make(chan []byte, 128)
go readBuffer(bufCh)
winSizeCh := make(chan *prompt.WinSize, 128)
go updateWindowSize(in, winSizeCh)
buffer := prompt.NewBuffer()
for {
b := <-bufCh
if ac := in.GetASCIICode(b); ac == nil {
out.EraseDown()
out.WriteRaw(b)
ac := in.GetASCIICode(b)
if ac == nil {
buffer.InsertText(string(b), false, true)
} else if ac.Key == prompt.Enter || ac.Key == prompt.ControlJ {
out.EraseDown()
out.WriteStr(buffer.Document().TextAfterCursor())
out.WriteStr("\n>>> Your input: '")
out.WriteStr(buffer.Text())
out.WriteStr("' <<<\n")
buffer = prompt.NewBuffer()
} else if ac.Key == prompt.Left {
l := buffer.CursorLeft(1)
if l == 0 {
continue
}
out.EraseLine()
out.EraseDown()
after := buffer.Document().CurrentLine()
out.WriteStr(after)
out.CursorBackward(len(after) - buffer.CursorPosition)
} else if ac.Key == prompt.Right {
l := buffer.CursorRight(1)
if l == 0 {
continue
}
out.CursorForward(l)
out.WriteRaw(b)
out.EraseDown()
after := buffer.Document().TextAfterCursor()
out.WriteStr(after)
} else if ac.Key == prompt.Backspace {
deleted := buffer.DeleteBeforeCursor(1)
if deleted == "" {
continue
}
out.CursorBackward(1)
out.EraseDown()
after := buffer.Document().TextAfterCursor()
out.WriteStr(after)
} else if ac.Key == prompt.Tab || ac.Key == prompt.ControlI {
} else if ac.Key == prompt.BackTab {
} else if ac.Key == prompt.Right {
buffer.CursorRight(1)
} else if ac.Key == prompt.ControlT {
enterAlternateScreen(syscall.Stdout)
} else if ac.Key == prompt.ControlC {
out.EraseDown()
out.ClearTitle()
out.Flush()
return
} else if ac.Key == prompt.Up || ac.Key == prompt.Down {
} else {
out.WriteRaw(b)
//buffer.InsertText(ac.Key.String(), false, true)
prompt.InputHandler(ac, buffer, out)
}
// Display completions
@ -132,6 +97,8 @@ func main() {
out.SetColor("default", "default")
}
completions := []string{"select", "insert", "update", "where"}
renderer.Render(buffer, completions)
scroll(out, 4)
out.Flush()
}
@ -146,3 +113,36 @@ func readBuffer(bufCh chan []byte) {
}
}
}
func updateWindowSize(in *prompt.VT100Parser, winSizeCh chan *prompt.WinSize) {
sigCh := make(chan os.Signal, 1)
signal.Notify(
sigCh,
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT,
syscall.SIGWINCH,
)
for {
s := <-sigCh
switch s {
// kill -SIGHUP XXXX
case syscall.SIGHUP:
// kill -SIGINT XXXX or Ctrl+c
case syscall.SIGINT:
// kill -SIGTERM XXXX
case syscall.SIGTERM:
// kill -SIGQUIT XXXX
case syscall.SIGQUIT:
case syscall.SIGWINCH:
winSizeCh <- in.GetWinSize()
default:
}
}
}

24
prompt/completions.go Normal file
View File

@ -0,0 +1,24 @@
package prompt
type Completion struct {
// The new string that will be inserted into document.
text string
// Position relative to the cursor position where the new text will start.
startPosition int
}
func (c *Completion) NewCompletionFromPosition(position int) *Completion {
if position < c.startPosition {
panic("position argument must be smaller than start position.")
}
return &Completion{
text: c.text[position - c.startPosition:],
}
}
func NewCompletion(text string) *Completion {
return &Completion{
text: text,
}
}

6
prompt/input.go Normal file
View File

@ -0,0 +1,6 @@
package prompt
type WinSize struct {
Row uint16
Col uint16
}

63
prompt/key_binding.go Normal file
View File

@ -0,0 +1,63 @@
package prompt
var InputHandler = defaultHandler
func defaultHandler(ac *ASCIICode, buffer *Buffer, out *VT100Writer) {
switch ac.Key {
case ControlJ: // this is equivalent with Enter Key.
fallthrough
case Enter:
out.EraseDown()
out.WriteStr(buffer.Document().TextAfterCursor())
out.WriteStr("\n>>> Your input: '")
out.WriteStr(buffer.Text())
out.WriteStr("' <<<\n")
buffer = NewBuffer()
case Left:
l := buffer.CursorLeft(1)
if l == 0 {
return
}
out.EraseLine()
out.EraseDown()
after := buffer.Document().CurrentLine()
out.WriteStr(after)
out.CursorBackward(len(after) - buffer.CursorPosition)
case Right:
l := buffer.CursorRight(1)
if l == 0 {
return
}
out.CursorForward(l)
out.WriteRaw(ac.ASCIICode)
out.EraseDown()
after := buffer.Document().TextAfterCursor()
out.WriteStr(after)
case Backspace:
deleted := buffer.DeleteBeforeCursor(1)
if deleted == "" {
return
}
out.CursorBackward(1)
out.EraseDown()
after := buffer.Document().TextAfterCursor()
out.WriteStr(after)
case ControlI: // this is equivalent with TabKey.
fallthrough
case Tab:
break
case ControlT:
break
return
case Up:
break
case Down:
break
default:
break
}
return
}

21
prompt/render.go Normal file
View File

@ -0,0 +1,21 @@
package prompt
type Render struct {
Prefix string
Out *VT100Writer
row uint16
col uint16 // sigwinchで送られてくる列数を常に見ながら、prefixのlengthとbufferのcursor positionを比べて、completionの表示位置をずらす
}
func (r *Render) UpdateWinSize(ws WinSize) {
r.row = ws.Row
r.col = ws.Col
return
}
func (r *Render) renderCompletion(words []string) {
return
}
func (r *Render) Render(buffer *Buffer, completions []string) {
}

View File

@ -53,7 +53,7 @@ func (t *VT100Parser) GetASCIICode(b []byte) *ASCIICode {
}
// GetWinSize returns winsize struct which is the response of ioctl(2).
func (t *VT100Parser) GetWinSize() (row, col uint16) {
func (t *VT100Parser) GetWinSize() *WinSize {
ws := &ioctlWinsize{}
retCode, _, errno := syscall.Syscall(
syscall.SYS_IOCTL,
@ -64,7 +64,10 @@ func (t *VT100Parser) GetWinSize() (row, col uint16) {
if int(retCode) == -1 {
panic(errno)
}
return ws.Row, ws.Col
return &WinSize{
Row: ws.Row,
Col: ws.Col,
}
}
var asciiSequences []*ASCIICode = []*ASCIICode{