fix fwd/bck search

This commit is contained in:
Cheney 2015-09-23 11:10:36 +08:00
parent 3b1cf6b8fb
commit a7f498f047
5 changed files with 108 additions and 17 deletions

View File

@ -58,9 +58,19 @@ func (o *opHistory) Close() {
}
}
func (o *opHistory) FindHistoryBck(rs []rune) (int, *list.Element) {
func (o *opHistory) FindHistoryBck(isNewSearch bool, rs []rune, start int) (int, *list.Element) {
for elem := o.current; elem != nil; elem = elem.Prev() {
idx := RunesIndex(o.showItem(elem.Value), rs)
item := o.showItem(elem.Value)
if isNewSearch {
start += len(rs)
}
if elem == o.current {
if len(item) < start {
continue
}
item = item[:start]
}
idx := RunesIndexBck(item, rs)
if idx < 0 {
continue
}
@ -69,12 +79,25 @@ func (o *opHistory) FindHistoryBck(rs []rune) (int, *list.Element) {
return -1, nil
}
func (o *opHistory) FindHistoryFwd(rs []rune) (int, *list.Element) {
func (o *opHistory) FindHistoryFwd(isNewSearch bool, rs []rune, start int) (int, *list.Element) {
for elem := o.current; elem != nil; elem = elem.Next() {
idx := RunesIndex(o.showItem(elem.Value), rs)
item := o.showItem(elem.Value)
if isNewSearch {
start -= len(rs)
}
if elem == o.current {
if len(item)-1 < start {
continue
}
item = item[start:]
}
idx := RunesIndex(item, rs)
if idx < 0 {
continue
}
if elem == o.current {
idx += start
}
return idx, elem
}
return -1, nil
@ -119,8 +142,8 @@ func (o *opHistory) NewHistory(current []rune) {
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) {
use := o.showItem(o.current.Value.(*HisItem))
if equalRunes(use, prev.Value.(*HisItem).Source) {
o.current = o.history.Back()
o.current.Value.(*HisItem).Clean()
o.historyVer++

View File

@ -96,6 +96,9 @@ func (l *Operation) ioloop() {
case MetaBackspace:
l.buf.BackEscapeWord()
case CharEnter, CharEnter2:
if l.IsSearchMode() {
l.ExitSearchMode(false)
}
l.buf.MoveToLineEnd()
l.buf.WriteRune('\n')
data := l.buf.Reset()
@ -136,7 +139,9 @@ func (l *Operation) ioloop() {
l.ExitSearchMode(false)
l.buf.Refresh()
}
l.UpdateHistory(l.buf.Runes(), false)
if !l.IsSearchMode() {
l.UpdateHistory(l.buf.Runes(), false)
}
}
}

View File

@ -198,7 +198,9 @@ func (r *RuneBuffer) Output() []byte {
buf.Write(r.CleanOutput())
buf.Write(r.prompt)
buf.Write([]byte(string(r.buf)))
buf.Write(bytes.Repeat([]byte{'\b'}, len(r.buf)-r.idx))
if len(r.buf) > r.idx {
buf.Write(bytes.Repeat([]byte{'\b'}, len(r.buf)-r.idx))
}
return buf.Bytes()
}
@ -224,6 +226,31 @@ func (r *RuneBuffer) Reset() []rune {
return ret
}
func (r *RuneBuffer) SetStyle(start, end int, style string) {
idx := r.idx
if end < start {
panic("end < start")
}
// goto start
move := start - idx
if move > 0 {
r.w.Write([]byte(string(r.buf[r.idx : r.idx+move])))
} else {
r.w.Write(bytes.Repeat([]byte("\b"), -move))
}
r.w.Write([]byte("\033[" + style))
r.w.Write([]byte(string(r.buf[start:end])))
r.w.Write([]byte("\033[0m"))
if move > 0 {
r.w.Write(bytes.Repeat([]byte("\b"), -move+(end-start)))
} else if -move < end-start {
r.w.Write(bytes.Repeat([]byte("\b"), -move))
} else {
r.w.Write([]byte(string(r.buf[end:r.idx])))
}
}
func (r *RuneBuffer) SetWithIdx(idx int, buf []rune) {
r.buf = buf
r.idx = idx

View File

@ -43,39 +43,59 @@ func (o *opSearch) IsSearchMode() bool {
func (o *opSearch) SearchBackspace() {
if len(o.data) > 0 {
o.data = o.data[:len(o.data)-1]
o.search()
o.search(true)
}
}
func (o *opSearch) findHistoryBy() (int, *list.Element) {
func (o *opSearch) findHistoryBy(isNewSearch bool) (int, *list.Element) {
if o.dir == S_DIR_BCK {
return o.history.FindHistoryBck(o.data)
return o.history.FindHistoryBck(isNewSearch, o.data, o.buf.idx)
}
return o.history.FindHistoryFwd(o.data)
return o.history.FindHistoryFwd(isNewSearch, o.data, o.buf.idx)
}
func (o *opSearch) search() bool {
idx, elem := o.findHistoryBy()
func (o *opSearch) search(isChange bool) bool {
if len(o.data) == 0 {
o.state = S_STATE_FOUND
o.SearchRefresh(-1)
return true
}
idx, elem := o.findHistoryBy(isChange)
if elem == nil {
o.SearchRefresh(-2)
return false
}
o.history.current = elem
o.buf.SetWithIdx(idx, o.history.showItem(o.history.current.Value))
item := o.history.showItem(o.history.current.Value)
start, end := 0, 0
if o.dir == S_DIR_BCK {
start, end = idx, idx+len(o.data)
} else {
start, end = idx, idx+len(o.data)
idx += len(o.data)
}
o.buf.SetWithIdx(idx, item)
o.buf.SetStyle(start, end, "4m")
o.SearchRefresh(idx)
return true
}
func (o *opSearch) SearchChar(r rune) {
o.data = append(o.data, r)
o.search()
o.search(true)
}
func (o *opSearch) SearchMode(dir int) {
alreadyInMode := o.inMode
o.inMode = true
o.dir = dir
o.source = o.history.current
o.SearchRefresh(-1)
if alreadyInMode {
o.search(false)
} else {
o.SearchRefresh(-1)
}
}
func (o *opSearch) ExitSearchMode(revert bool) {

View File

@ -131,6 +131,22 @@ func RunesWidth(r []rune) (length int) {
return
}
func RunesIndexBck(r, sub []rune) int {
for i := len(r) - len(sub); i >= 0; i-- {
found := true
for j := 0; j < len(sub); j++ {
if r[i+j] != sub[j] {
found = false
break
}
}
if found {
return i
}
}
return -1
}
func RunesIndex(r, sub []rune) int {
for i := 0; i < len(r); i++ {
found := true