diff --git a/example/main.go b/example/main.go index 1860740..715dbba 100644 --- a/example/main.go +++ b/example/main.go @@ -9,8 +9,15 @@ import ( "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() { - l, err := readline.New("> ") + l, err := readline.New("home -> ") if err != nil { panic(err) } @@ -24,7 +31,7 @@ func main() { } switch line { case "help": - io.WriteString(l.Stderr(), "sayhello: start to display oneline log per second\nbye: quit\n") + usage(l.Stderr()) case "sayhello": go func() { for _ = range time.Tick(time.Second) { @@ -33,6 +40,7 @@ func main() { }() case "bye": goto exit + case "": default: log.Println("you said:", strconv.Quote(line)) } diff --git a/history.go b/history.go index 9dac917..e5b488a 100644 --- a/history.go +++ b/history.go @@ -47,10 +47,21 @@ func (o *Operation) NextHistory() ([]rune, bool) { func (o *Operation) NewHistory(current []rune) { // if just use last command without modify // just clean lastest history - if o.current == o.history.Back().Prev() { - use := o.current.Value.(*HisItem) - if equalRunes(use.Tmp, use.Source) { - o.current = o.history.Back() + if back := o.history.Back(); back != nil { + prev := back.Prev() + if prev != nil { + use := o.current.Value.(*HisItem) + if equalRunes(use.Tmp, prev.Value.(*HisItem).Source) { + o.current = o.history.Back() + o.current.Value.(*HisItem).Clean() + o.historyVer++ + return + } + } + } + if len(current) == 0 { + o.current = o.history.Back() + if o.current != nil { o.current.Value.(*HisItem).Clean() o.historyVer++ return diff --git a/operation.go b/operation.go index e0ca9b4..d9dc4c6 100644 --- a/operation.go +++ b/operation.go @@ -81,7 +81,6 @@ func (l *Operation) ioloop() { data = data[:len(data)-1] // trim \n l.outchan <- data l.NewHistory(data) - debugList(l.history) case CharBackward: l.buf.MoveBackward() case CharForward: diff --git a/runebuf.go b/runebuf.go index 6bbb96d..9d75a59 100644 --- a/runebuf.go +++ b/runebuf.go @@ -10,15 +10,14 @@ type RuneBuffer struct { idx int prompt []byte w io.Writer + hasPrompt bool lastWritten int - printPrompt bool } func NewRuneBuffer(w io.Writer, prompt string) *RuneBuffer { rb := &RuneBuffer{ - prompt: []byte(prompt), - w: w, - printPrompt: true, + prompt: []byte(prompt), + w: w, } return rb } @@ -161,18 +160,24 @@ func (r *RuneBuffer) MoveToLineEnd() { } 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) } 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.Write(bytes.Repeat([]byte{'\b'}, originIdx+len(r.prompt))) - buf.Write(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) + } + r.hasPrompt = prompt buf.Write([]byte(string(r.buf))) if 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() { moveToFirst := r.idx - moveToFirst += len(r.prompt) + if r.hasPrompt { + moveToFirst += len(r.prompt) + } 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{'\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 { ret := r.buf r.buf = r.buf[:0] r.idx = 0 - r.printPrompt = true - r.Refresh(-len(ret), r.SetIdx(0)) + r.hasPrompt = false return ret } diff --git a/terminal.go b/terminal.go index e961d47..c895081 100644 --- a/terminal.go +++ b/terminal.go @@ -72,7 +72,6 @@ func (t *Terminal) ioloop() { isEscapeEx := false for { r, _, err := buf.ReadRune() - Debug(r, isEscape, isEscapeEx) if err != nil { break } @@ -87,7 +86,6 @@ func (t *Terminal) ioloop() { } else if isEscapeEx { isEscapeEx = false r = escapeExKey(r) - Debug("r:", r) } if IsPrintable(r) || r < 0 { diff --git a/utils.go b/utils.go index 4cf9592..e159682 100644 --- a/utils.go +++ b/utils.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "syscall" + "time" "unsafe" "golang.org/x/crypto/ssh/terminal" @@ -103,3 +104,8 @@ func equalRunes(a, b []rune) bool { } return true } + +func sleep(n int) { + Debug(n) + time.Sleep(2000 * time.Millisecond) +}