mirror of https://github.com/chzyer/readline.git
Bugfix/datarace prompt (#81)
* fix data race in PromptLen * add lock for all operation in RuneBuffer * add race test * update travis
This commit is contained in:
parent
820d6f2766
commit
283f5429f7
|
@ -1,10 +1,9 @@
|
|||
language: go
|
||||
go:
|
||||
- 1.5
|
||||
before_install:
|
||||
- go get golang.org/x/crypto/ssh/terminal
|
||||
- 1.7
|
||||
script:
|
||||
- GOOS=windows go install github.com/chzyer/readline/example/...
|
||||
- GOOS=linux go install github.com/chzyer/readline/example/...
|
||||
- GOOS=darwin go install github.com/chzyer/readline/example/...
|
||||
- go test -v
|
||||
- go test -race -v
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package readline
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRace(t *testing.T) {
|
||||
rl, err := NewEx(&Config{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
for range time.Tick(time.Millisecond) {
|
||||
rl.SetPrompt("hello")
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
rl.Close()
|
||||
}()
|
||||
|
||||
rl.Readline()
|
||||
}
|
39
runebuf.go
39
runebuf.go
|
@ -33,11 +33,15 @@ type RuneBuffer struct {
|
|||
}
|
||||
|
||||
func (r *RuneBuffer) OnWidthChange(newWidth int) {
|
||||
r.Lock()
|
||||
r.width = newWidth
|
||||
r.Unlock()
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) Backup() {
|
||||
r.Lock()
|
||||
r.bck = &runeBufferBck{r.buf, r.idx}
|
||||
r.Unlock()
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) Restore() {
|
||||
|
@ -62,15 +66,21 @@ func NewRuneBuffer(w io.Writer, prompt string, cfg *Config, width int) *RuneBuff
|
|||
}
|
||||
|
||||
func (r *RuneBuffer) SetConfig(cfg *Config) {
|
||||
r.Lock()
|
||||
r.cfg = cfg
|
||||
r.interactive = cfg.useInteractive()
|
||||
r.Unlock()
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) SetMask(m rune) {
|
||||
r.Lock()
|
||||
r.cfg.MaskRune = m
|
||||
r.Unlock()
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) CurrentWidth(x int) int {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
return runes.WidthAll(r.buf[:x])
|
||||
}
|
||||
|
||||
|
@ -86,6 +96,9 @@ func (r *RuneBuffer) promptLen() int {
|
|||
}
|
||||
|
||||
func (r *RuneBuffer) RuneSlice(i int) []rune {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if i > 0 {
|
||||
rs := make([]rune, i)
|
||||
copy(rs, r.buf[r.idx:r.idx+i])
|
||||
|
@ -97,16 +110,22 @@ func (r *RuneBuffer) RuneSlice(i int) []rune {
|
|||
}
|
||||
|
||||
func (r *RuneBuffer) Runes() []rune {
|
||||
r.Lock()
|
||||
newr := make([]rune, len(r.buf))
|
||||
copy(newr, r.buf)
|
||||
r.Unlock()
|
||||
return newr
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) Pos() int {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
return r.idx
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) Len() int {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
return len(r.buf)
|
||||
}
|
||||
|
||||
|
@ -154,6 +173,8 @@ func (r *RuneBuffer) MoveForward() {
|
|||
}
|
||||
|
||||
func (r *RuneBuffer) IsCursorInEnd() bool {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
return r.idx == len(r.buf)
|
||||
}
|
||||
|
||||
|
@ -382,6 +403,12 @@ func (r *RuneBuffer) getSplitByLine(rs []rune) []string {
|
|||
}
|
||||
|
||||
func (r *RuneBuffer) IdxLine(width int) int {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
return r.idxLine(width)
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) idxLine(width int) int {
|
||||
if width == 0 {
|
||||
return 0
|
||||
}
|
||||
|
@ -404,7 +431,7 @@ func (r *RuneBuffer) Refresh(f func()) {
|
|||
return
|
||||
}
|
||||
|
||||
r.Clean()
|
||||
r.clean()
|
||||
if f != nil {
|
||||
f()
|
||||
}
|
||||
|
@ -527,10 +554,16 @@ func (r *RuneBuffer) cleanOutput(w io.Writer, idxLine int) {
|
|||
}
|
||||
|
||||
func (r *RuneBuffer) Clean() {
|
||||
r.clean(r.IdxLine(r.width))
|
||||
r.Lock()
|
||||
r.clean()
|
||||
r.Unlock()
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) clean(idxLine int) {
|
||||
func (r *RuneBuffer) clean() {
|
||||
r.cleanWithIdxLine(r.idxLine(r.width))
|
||||
}
|
||||
|
||||
func (r *RuneBuffer) cleanWithIdxLine(idxLine int) {
|
||||
if r.hadClean || !r.interactive {
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue