update
This commit is contained in:
parent
b9fa638633
commit
d8e4a92790
20
erasing.go
Normal file
20
erasing.go
Normal 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
106
main.go
@ -3,18 +3,18 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
"github.com/c-bata/go-prompt-toolkit/prompt"
|
"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) {
|
func scroll(out *prompt.VT100Writer, lines int) {
|
||||||
for i := 0; i < lines; i++ {
|
for i := 0; i < lines; i++ {
|
||||||
out.ScrollDown()
|
out.ScrollDown()
|
||||||
defer out.ScrollUp()
|
}
|
||||||
|
for i := 0; i < lines; i++ {
|
||||||
|
out.ScrollUp()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -23,8 +23,14 @@ func main() {
|
|||||||
in := prompt.NewVT100Parser()
|
in := prompt.NewVT100Parser()
|
||||||
in.Setup()
|
in.Setup()
|
||||||
defer in.TearDown()
|
defer in.TearDown()
|
||||||
defer fmt.Println("\nexited!")
|
defer fmt.Println("\nGoodbye!")
|
||||||
out := prompt.NewVT100Writer()
|
out := prompt.NewVT100Writer()
|
||||||
|
|
||||||
|
renderer := prompt.Render{
|
||||||
|
Prefix: ">>> ",
|
||||||
|
Out: out,
|
||||||
|
}
|
||||||
|
|
||||||
out.SetTitle("はろー")
|
out.SetTitle("はろー")
|
||||||
scroll(out, 7)
|
scroll(out, 7)
|
||||||
out.Flush()
|
out.Flush()
|
||||||
@ -32,68 +38,27 @@ func main() {
|
|||||||
bufCh := make(chan []byte, 128)
|
bufCh := make(chan []byte, 128)
|
||||||
go readBuffer(bufCh)
|
go readBuffer(bufCh)
|
||||||
|
|
||||||
|
winSizeCh := make(chan *prompt.WinSize, 128)
|
||||||
|
go updateWindowSize(in, winSizeCh)
|
||||||
|
|
||||||
buffer := prompt.NewBuffer()
|
buffer := prompt.NewBuffer()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
b := <-bufCh
|
b := <-bufCh
|
||||||
if ac := in.GetASCIICode(b); ac == nil {
|
ac := in.GetASCIICode(b)
|
||||||
out.EraseDown()
|
if ac == nil {
|
||||||
out.WriteRaw(b)
|
|
||||||
buffer.InsertText(string(b), false, true)
|
buffer.InsertText(string(b), false, true)
|
||||||
} else if ac.Key == prompt.Enter || ac.Key == prompt.ControlJ {
|
|
||||||
out.EraseDown()
|
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.WriteRaw(b)
|
||||||
out.EraseDown()
|
|
||||||
after := buffer.Document().TextAfterCursor()
|
after := buffer.Document().TextAfterCursor()
|
||||||
out.WriteStr(after)
|
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 {
|
} else if ac.Key == prompt.ControlC {
|
||||||
out.EraseDown()
|
out.EraseDown()
|
||||||
out.ClearTitle()
|
out.ClearTitle()
|
||||||
out.Flush()
|
out.Flush()
|
||||||
return
|
return
|
||||||
} else if ac.Key == prompt.Up || ac.Key == prompt.Down {
|
|
||||||
} else {
|
} else {
|
||||||
out.WriteRaw(b)
|
prompt.InputHandler(ac, buffer, out)
|
||||||
//buffer.InsertText(ac.Key.String(), false, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display completions
|
// Display completions
|
||||||
@ -132,6 +97,8 @@ func main() {
|
|||||||
out.SetColor("default", "default")
|
out.SetColor("default", "default")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
completions := []string{"select", "insert", "update", "where"}
|
||||||
|
renderer.Render(buffer, completions)
|
||||||
scroll(out, 4)
|
scroll(out, 4)
|
||||||
out.Flush()
|
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
24
prompt/completions.go
Normal 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
6
prompt/input.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package prompt
|
||||||
|
|
||||||
|
type WinSize struct {
|
||||||
|
Row uint16
|
||||||
|
Col uint16
|
||||||
|
}
|
63
prompt/key_binding.go
Normal file
63
prompt/key_binding.go
Normal 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
21
prompt/render.go
Normal 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) {
|
||||||
|
}
|
@ -53,7 +53,7 @@ func (t *VT100Parser) GetASCIICode(b []byte) *ASCIICode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetWinSize returns winsize struct which is the response of ioctl(2).
|
// 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{}
|
ws := &ioctlWinsize{}
|
||||||
retCode, _, errno := syscall.Syscall(
|
retCode, _, errno := syscall.Syscall(
|
||||||
syscall.SYS_IOCTL,
|
syscall.SYS_IOCTL,
|
||||||
@ -64,7 +64,10 @@ func (t *VT100Parser) GetWinSize() (row, col uint16) {
|
|||||||
if int(retCode) == -1 {
|
if int(retCode) == -1 {
|
||||||
panic(errno)
|
panic(errno)
|
||||||
}
|
}
|
||||||
return ws.Row, ws.Col
|
return &WinSize{
|
||||||
|
Row: ws.Row,
|
||||||
|
Col: ws.Col,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var asciiSequences []*ASCIICode = []*ASCIICode{
|
var asciiSequences []*ASCIICode = []*ASCIICode{
|
||||||
|
Loading…
Reference in New Issue
Block a user