mirror of https://github.com/chzyer/readline.git
fix runebuffer refresh
This commit is contained in:
parent
e878807b59
commit
9c65cb7ccf
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
15
history.go
15
history.go
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
35
runebuf.go
35
runebuf.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
6
utils.go
6
utils.go
|
@ -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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue