mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2024-11-14 09:24:03 +00:00
153 lines
3.3 KiB
Go
153 lines
3.3 KiB
Go
|
package fzf
|
||
|
|
||
|
import "strings"
|
||
|
|
||
|
/*
|
||
|
* String matching algorithms here do not use strings.ToLower to avoid
|
||
|
* performance penalty. And they assume pattern runes are given in lowercase
|
||
|
* letters when caseSensitive is false.
|
||
|
*
|
||
|
* In short: They try to do as little work as possible.
|
||
|
*/
|
||
|
|
||
|
func FuzzyMatch(caseSensitive bool, input *string, pattern []rune) (int, int) {
|
||
|
runes := []rune(*input)
|
||
|
|
||
|
// 0. (FIXME) How to find the shortest match?
|
||
|
// a_____b__c__abc
|
||
|
// ^^^^^^^^^^ ^^^
|
||
|
// 1. forward scan (abc)
|
||
|
// *-----*-----*>
|
||
|
// a_____b___abc__
|
||
|
// 2. reverse scan (cba)
|
||
|
// a_____b___abc__
|
||
|
// <***
|
||
|
pidx := 0
|
||
|
sidx := -1
|
||
|
eidx := -1
|
||
|
|
||
|
for index, char := range runes {
|
||
|
// This is considerably faster than blindly applying strings.ToLower to the
|
||
|
// whole string
|
||
|
if !caseSensitive && char >= 65 && char <= 90 {
|
||
|
char += 32
|
||
|
}
|
||
|
if char == pattern[pidx] {
|
||
|
if sidx < 0 {
|
||
|
sidx = index
|
||
|
}
|
||
|
if pidx += 1; pidx == len(pattern) {
|
||
|
eidx = index + 1
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if sidx >= 0 && eidx >= 0 {
|
||
|
pidx -= 1
|
||
|
for index := eidx - 1; index >= sidx; index-- {
|
||
|
char := runes[index]
|
||
|
if !caseSensitive && char >= 65 && char <= 90 {
|
||
|
char += 32
|
||
|
}
|
||
|
if char == pattern[pidx] {
|
||
|
if pidx -= 1; pidx < 0 {
|
||
|
sidx = index
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return sidx, eidx
|
||
|
}
|
||
|
return -1, -1
|
||
|
}
|
||
|
|
||
|
func ExactMatchStrings(caseSensitive bool, input *string, pattern []rune) (int, int) {
|
||
|
var str string
|
||
|
if caseSensitive {
|
||
|
str = *input
|
||
|
} else {
|
||
|
str = strings.ToLower(*input)
|
||
|
}
|
||
|
|
||
|
if idx := strings.Index(str, string(pattern)); idx >= 0 {
|
||
|
prefixRuneLen := len([]rune((*input)[:idx]))
|
||
|
return prefixRuneLen, prefixRuneLen + len(pattern)
|
||
|
}
|
||
|
return -1, -1
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* This is a basic string searching algorithm that handles case sensitivity.
|
||
|
* Although naive, it still performs better than the combination of
|
||
|
* strings.ToLower + strings.Index for typical fzf use cases where input
|
||
|
* strings and patterns are not very long.
|
||
|
*
|
||
|
* We might try to implement better algorithms in the future:
|
||
|
* http://en.wikipedia.org/wiki/String_searching_algorithm
|
||
|
*/
|
||
|
func ExactMatchNaive(caseSensitive bool, input *string, pattern []rune) (int, int) {
|
||
|
runes := []rune(*input)
|
||
|
numRunes := len(runes)
|
||
|
plen := len(pattern)
|
||
|
if len(runes) < plen {
|
||
|
return -1, -1
|
||
|
}
|
||
|
|
||
|
pidx := 0
|
||
|
for index := 0; index < numRunes; index++ {
|
||
|
char := runes[index]
|
||
|
if !caseSensitive && char >= 65 && char <= 90 {
|
||
|
char += 32
|
||
|
}
|
||
|
if pattern[pidx] == char {
|
||
|
pidx += 1
|
||
|
if pidx == plen {
|
||
|
return index - plen + 1, index + 1
|
||
|
}
|
||
|
} else {
|
||
|
index -= pidx
|
||
|
pidx = 0
|
||
|
}
|
||
|
}
|
||
|
return -1, -1
|
||
|
}
|
||
|
|
||
|
func PrefixMatch(caseSensitive bool, input *string, pattern []rune) (int, int) {
|
||
|
runes := []rune(*input)
|
||
|
if len(runes) < len(pattern) {
|
||
|
return -1, -1
|
||
|
}
|
||
|
|
||
|
for index, r := range pattern {
|
||
|
char := runes[index]
|
||
|
if !caseSensitive && char >= 65 && char <= 90 {
|
||
|
char += 32
|
||
|
}
|
||
|
if char != r {
|
||
|
return -1, -1
|
||
|
}
|
||
|
}
|
||
|
return 0, len(pattern)
|
||
|
}
|
||
|
|
||
|
func SuffixMatch(caseSensitive bool, input *string, pattern []rune) (int, int) {
|
||
|
runes := []rune(strings.TrimRight(*input, " "))
|
||
|
trimmedLen := len(runes)
|
||
|
diff := trimmedLen - len(pattern)
|
||
|
if diff < 0 {
|
||
|
return -1, -1
|
||
|
}
|
||
|
|
||
|
for index, r := range pattern {
|
||
|
char := runes[index+diff]
|
||
|
if !caseSensitive && char >= 65 && char <= 90 {
|
||
|
char += 32
|
||
|
}
|
||
|
if char != r {
|
||
|
return -1, -1
|
||
|
}
|
||
|
}
|
||
|
return trimmedLen - len(pattern), trimmedLen
|
||
|
}
|