Skip to content

Commit

Permalink
add HistorySearchFold (chzyer#86)
Browse files Browse the repository at this point in the history
* add HistorySearchFold

* [history] fix test
  • Loading branch information
chzyer authored Oct 3, 2016
1 parent bc5e387 commit 94eaec6
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 7 deletions.
2 changes: 2 additions & 0 deletions example/readline-demo/readline-demo.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ func main() {
AutoComplete: completer,
InterruptPrompt: "^C",
EOFPrompt: "exit",

HistorySearchFold: true,
})
if err != nil {
panic(err)
Expand Down
4 changes: 2 additions & 2 deletions history.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (o *opHistory) FindBck(isNewSearch bool, rs []rune, start int) (int, *list.
item = item[:start]
}
}
idx := runes.IndexAllBck(item, rs)
idx := runes.IndexAllBckEx(item, rs, o.cfg.HistorySearchFold)
if idx < 0 {
continue
}
Expand All @@ -178,7 +178,7 @@ func (o *opHistory) FindFwd(isNewSearch bool, rs []rune, start int) (int, *list.
continue
}
}
idx := runes.IndexAll(item, rs)
idx := runes.IndexAllEx(item, rs, o.cfg.HistorySearchFold)
if idx < 0 {
continue
}
Expand Down
2 changes: 2 additions & 0 deletions readline.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
HistoryLimit int
DisableAutoSaveHistory bool
// enable case-insensitive history searching
HistorySearchFold bool

// AutoCompleter will called once user press TAB
AutoComplete AutoCompleter
Expand Down
62 changes: 57 additions & 5 deletions runes.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,50 @@ package readline
import (
"bytes"
"unicode"
"unicode/utf8"
)

var runes = Runes{}
var TabWidth = 4

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 {
if len(a) != len(b) {
return false
Expand All @@ -22,12 +59,11 @@ func (Runes) Equal(a, b []rune) bool {
return true
}

// Search in runes from end to front
func (Runes) IndexAllBck(r, sub []rune) int {
func (rs Runes) IndexAllBckEx(r, sub []rune, fold bool) 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] {
if !rs.EqualRune(r[i+j], sub[j], fold) {
found = false
break
}
Expand All @@ -39,15 +75,24 @@ func (Runes) IndexAllBck(r, sub []rune) int {
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
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++ {
found := true
if len(r[i:]) < len(sub) {
return -1
}
for j := 0; j < len(sub); j++ {
if r[i+j] != sub[j] {
if !rs.EqualRune(r[i+j], sub[j], fold) {
found = false
break
}
Expand Down Expand Up @@ -128,6 +173,13 @@ func (Runes) Copy(r []rune) []rune {
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 {
if len(r) < len(prefix) {
return false
Expand Down

0 comments on commit 94eaec6

Please sign in to comment.