fix runebuffer refresh

This commit is contained in:
Cheney 2015-09-21 22:27:40 +08:00
parent e878807b59
commit 9c65cb7ccf
6 changed files with 59 additions and 24 deletions

View File

@ -9,8 +9,15 @@ import (
"github.com/chzyer/readline" "github.com/chzyer/readline"
) )
func usage(w io.Writer) {
io.WriteString(w, `
sayhello: start to display oneline log per second
bye: quit
`[1:])
}
func main() { func main() {
l, err := readline.New("> ") l, err := readline.New("home -> ")
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -24,7 +31,7 @@ func main() {
} }
switch line { switch line {
case "help": case "help":
io.WriteString(l.Stderr(), "sayhello: start to display oneline log per second\nbye: quit\n") usage(l.Stderr())
case "sayhello": case "sayhello":
go func() { go func() {
for _ = range time.Tick(time.Second) { for _ = range time.Tick(time.Second) {
@ -33,6 +40,7 @@ func main() {
}() }()
case "bye": case "bye":
goto exit goto exit
case "":
default: default:
log.Println("you said:", strconv.Quote(line)) log.Println("you said:", strconv.Quote(line))
} }

View File

@ -47,15 +47,26 @@ func (o *Operation) NextHistory() ([]rune, bool) {
func (o *Operation) NewHistory(current []rune) { func (o *Operation) NewHistory(current []rune) {
// if just use last command without modify // if just use last command without modify
// just clean lastest history // just clean lastest history
if o.current == o.history.Back().Prev() { if back := o.history.Back(); back != nil {
prev := back.Prev()
if prev != nil {
use := o.current.Value.(*HisItem) use := o.current.Value.(*HisItem)
if equalRunes(use.Tmp, use.Source) { if equalRunes(use.Tmp, prev.Value.(*HisItem).Source) {
o.current = o.history.Back() o.current = o.history.Back()
o.current.Value.(*HisItem).Clean() o.current.Value.(*HisItem).Clean()
o.historyVer++ o.historyVer++
return return
} }
} }
}
if len(current) == 0 {
o.current = o.history.Back()
if o.current != nil {
o.current.Value.(*HisItem).Clean()
o.historyVer++
return
}
}
if o.current != o.history.Back() { if o.current != o.history.Back() {
// move history item to current command // move history item to current command

View File

@ -81,7 +81,6 @@ func (l *Operation) ioloop() {
data = data[:len(data)-1] // trim \n data = data[:len(data)-1] // trim \n
l.outchan <- data l.outchan <- data
l.NewHistory(data) l.NewHistory(data)
debugList(l.history)
case CharBackward: case CharBackward:
l.buf.MoveBackward() l.buf.MoveBackward()
case CharForward: case CharForward:

View File

@ -10,15 +10,14 @@ type RuneBuffer struct {
idx int idx int
prompt []byte prompt []byte
w io.Writer w io.Writer
hasPrompt bool
lastWritten int lastWritten int
printPrompt bool
} }
func NewRuneBuffer(w io.Writer, prompt string) *RuneBuffer { func NewRuneBuffer(w io.Writer, prompt string) *RuneBuffer {
rb := &RuneBuffer{ rb := &RuneBuffer{
prompt: []byte(prompt), prompt: []byte(prompt),
w: w, w: w,
printPrompt: true,
} }
return rb return rb
} }
@ -161,18 +160,24 @@ func (r *RuneBuffer) MoveToLineEnd() {
} }
func (r *RuneBuffer) Refresh(chlen, chidx int) { func (r *RuneBuffer) Refresh(chlen, chidx int) {
s := r.Output(len(r.buf)-chlen, r.idx-chidx) s := r.Output(len(r.buf)-chlen, r.idx-chidx, true)
r.w.Write(s) r.w.Write(s)
} }
func (r *RuneBuffer) RefreshSet(originLength, originIdx int) { func (r *RuneBuffer) RefreshSet(originLength, originIdx int) {
r.w.Write(r.Output(originLength, originIdx)) r.w.Write(r.Output(originLength, originIdx, true))
} }
func (r *RuneBuffer) Output(originLength, originIdx int) []byte { func (r *RuneBuffer) Output(originLength, originIdx int, prompt bool) []byte {
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
buf.Write(bytes.Repeat([]byte{'\b'}, originIdx+len(r.prompt))) buf.Write(bytes.Repeat([]byte{'\b'}, originIdx))
if prompt {
if r.hasPrompt {
buf.Write(bytes.Repeat([]byte{'\b'}, len(r.prompt)))
}
buf.Write(r.prompt) buf.Write(r.prompt)
}
r.hasPrompt = prompt
buf.Write([]byte(string(r.buf))) buf.Write([]byte(string(r.buf)))
if originLength > len(r.buf) { if originLength > len(r.buf) {
buf.Write(bytes.Repeat([]byte{' '}, originLength-len(r.buf))) buf.Write(bytes.Repeat([]byte{' '}, originLength-len(r.buf)))
@ -184,21 +189,29 @@ func (r *RuneBuffer) Output(originLength, originIdx int) []byte {
func (r *RuneBuffer) Clean() { func (r *RuneBuffer) Clean() {
moveToFirst := r.idx moveToFirst := r.idx
if r.hasPrompt {
moveToFirst += len(r.prompt) moveToFirst += len(r.prompt)
}
r.w.Write(bytes.Repeat([]byte{'\b'}, moveToFirst)) r.w.Write(bytes.Repeat([]byte{'\b'}, moveToFirst))
length := len(r.buf) + len(r.prompt) length := len(r.buf)
if r.hasPrompt {
length += len(r.prompt)
}
r.w.Write(bytes.Repeat([]byte{' '}, length)) r.w.Write(bytes.Repeat([]byte{' '}, length))
r.w.Write(bytes.Repeat([]byte{'\b'}, length)) r.w.Write(bytes.Repeat([]byte{'\b'}, length))
r.printPrompt = true r.hasPrompt = false
}
func (r *RuneBuffer) ResetScreen() {
r.w.Write(r.Output(0, 0, false))
} }
func (r *RuneBuffer) Reset() []rune { func (r *RuneBuffer) Reset() []rune {
ret := r.buf ret := r.buf
r.buf = r.buf[:0] r.buf = r.buf[:0]
r.idx = 0 r.idx = 0
r.printPrompt = true r.hasPrompt = false
r.Refresh(-len(ret), r.SetIdx(0))
return ret return ret
} }

View File

@ -72,7 +72,6 @@ func (t *Terminal) ioloop() {
isEscapeEx := false isEscapeEx := false
for { for {
r, _, err := buf.ReadRune() r, _, err := buf.ReadRune()
Debug(r, isEscape, isEscapeEx)
if err != nil { if err != nil {
break break
} }
@ -87,7 +86,6 @@ func (t *Terminal) ioloop() {
} else if isEscapeEx { } else if isEscapeEx {
isEscapeEx = false isEscapeEx = false
r = escapeExKey(r) r = escapeExKey(r)
Debug("r:", r)
} }
if IsPrintable(r) || r < 0 { if IsPrintable(r) || r < 0 {

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"os" "os"
"syscall" "syscall"
"time"
"unsafe" "unsafe"
"golang.org/x/crypto/ssh/terminal" "golang.org/x/crypto/ssh/terminal"
@ -103,3 +104,8 @@ func equalRunes(a, b []rune) bool {
} }
return true return true
} }
func sleep(n int) {
Debug(n)
time.Sleep(2000 * time.Millisecond)
}