add HistorySearchFold (#86)

* add HistorySearchFold

* [history] fix test
This commit is contained in:
chzyer 2016-10-03 14:51:04 +08:00 committed by GitHub
parent bc5e387904
commit 94eaec69a7
4 changed files with 63 additions and 7 deletions

View File

@ -68,6 +68,8 @@ func main() {
AutoComplete: completer, AutoComplete: completer,
InterruptPrompt: "^C", InterruptPrompt: "^C",
EOFPrompt: "exit", EOFPrompt: "exit",
HistorySearchFold: true,
}) })
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -153,7 +153,7 @@ func (o *opHistory) FindBck(isNewSearch bool, rs []rune, start int) (int, *list.
item = item[:start] item = item[:start]
} }
} }
idx := runes.IndexAllBck(item, rs) idx := runes.IndexAllBckEx(item, rs, o.cfg.HistorySearchFold)
if idx < 0 { if idx < 0 {
continue continue
} }
@ -178,7 +178,7 @@ func (o *opHistory) FindFwd(isNewSearch bool, rs []rune, start int) (int, *list.
continue continue
} }
} }
idx := runes.IndexAll(item, rs) idx := runes.IndexAllEx(item, rs, o.cfg.HistorySearchFold)
if idx < 0 { if idx < 0 {
continue continue
} }

View File

@ -34,6 +34,8 @@ type Config struct {
// specify the max length of historys, it's 500 by default, set it to -1 to disable history // specify the max length of historys, it's 500 by default, set it to -1 to disable history
HistoryLimit int HistoryLimit int
DisableAutoSaveHistory bool DisableAutoSaveHistory bool
// enable case-insensitive history searching
HistorySearchFold bool
// AutoCompleter will called once user press TAB // AutoCompleter will called once user press TAB
AutoComplete AutoCompleter AutoComplete AutoCompleter

View File

@ -3,6 +3,7 @@ package readline
import ( import (
"bytes" "bytes"
"unicode" "unicode"
"unicode/utf8"
) )
var runes = Runes{} var runes = Runes{}
@ -10,6 +11,42 @@ var TabWidth = 4
type Runes struct{} type Runes struct{}
func (Runes) EqualRune(a, b rune, fold bool) bool {
if a == b {
return true
}
if !fold {
return false
}
if a > b {
a, b = b, a
}
if b < utf8.RuneSelf && 'A' <= a && a <= 'Z' {
if b == a+'a'-'A' {
return true
}
}
return false
}
func (r Runes) EqualRuneFold(a, b rune) bool {
return r.EqualRune(a, b, true)
}
func (r Runes) EqualFold(a, b []rune) bool {
if len(a) != len(b) {
return false
}
for i := 0; i < len(a); i++ {
if r.EqualRuneFold(a[i], b[i]) {
continue
}
return false
}
return true
}
func (Runes) Equal(a, b []rune) bool { func (Runes) Equal(a, b []rune) bool {
if len(a) != len(b) { if len(a) != len(b) {
return false return false
@ -22,12 +59,11 @@ func (Runes) Equal(a, b []rune) bool {
return true return true
} }
// Search in runes from end to front func (rs Runes) IndexAllBckEx(r, sub []rune, fold bool) int {
func (Runes) IndexAllBck(r, sub []rune) int {
for i := len(r) - len(sub); i >= 0; i-- { for i := len(r) - len(sub); i >= 0; i-- {
found := true found := true
for j := 0; j < len(sub); j++ { for j := 0; j < len(sub); j++ {
if r[i+j] != sub[j] { if !rs.EqualRune(r[i+j], sub[j], fold) {
found = false found = false
break break
} }
@ -39,15 +75,24 @@ func (Runes) IndexAllBck(r, sub []rune) int {
return -1 return -1
} }
// Search in runes from end to front
func (rs Runes) IndexAllBck(r, sub []rune) int {
return rs.IndexAllBckEx(r, sub, false)
}
// Search in runes from front to end // Search in runes from front to end
func (Runes) IndexAll(r, sub []rune) int { func (rs Runes) IndexAll(r, sub []rune) int {
return rs.IndexAllEx(r, sub, false)
}
func (rs Runes) IndexAllEx(r, sub []rune, fold bool) int {
for i := 0; i < len(r); i++ { for i := 0; i < len(r); i++ {
found := true found := true
if len(r[i:]) < len(sub) { if len(r[i:]) < len(sub) {
return -1 return -1
} }
for j := 0; j < len(sub); j++ { for j := 0; j < len(sub); j++ {
if r[i+j] != sub[j] { if !rs.EqualRune(r[i+j], sub[j], fold) {
found = false found = false
break break
} }
@ -128,6 +173,13 @@ func (Runes) Copy(r []rune) []rune {
return n return n
} }
func (Runes) HasPrefixFold(r, prefix []rune) bool {
if len(r) < len(prefix) {
return false
}
return runes.EqualFold(r[:len(prefix)], prefix)
}
func (Runes) HasPrefix(r, prefix []rune) bool { func (Runes) HasPrefix(r, prefix []rune) bool {
if len(r) < len(prefix) { if len(r) < len(prefix) {
return false return false