github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/utils/readline/find.go (about)

     1  package readline
     2  
     3  import (
     4  	"path"
     5  	"regexp"
     6  	"strings"
     7  )
     8  
     9  var (
    10  	rFindSearchPart = []rune("partial word match: ")
    11  	rFindCancelPart = []rune("Cancelled partial word match")
    12  
    13  	rFindSearchGlob = []rune("globbing match: ")
    14  	rFindCancelGlob = []rune("Cancelled globbing match")
    15  
    16  	rFindSearchRegex = []rune("regexp match: ")
    17  	rFindCancelRegex = []rune("Cancelled regexp match")
    18  )
    19  
    20  type findT interface {
    21  	MatchString(string) bool
    22  }
    23  
    24  type fuzzyFindT struct {
    25  	mode   int
    26  	tokens []string
    27  }
    28  
    29  const (
    30  	ffMatchAll  = 0
    31  	ffMatchSome = iota + 1
    32  	ffMatchNone
    33  	ffMatchRegexp
    34  	ffMatchGlob
    35  )
    36  
    37  func (ff *fuzzyFindT) MatchString(item string) bool {
    38  	switch ff.mode {
    39  
    40  	case ffMatchSome:
    41  		return ff.matchSome(item)
    42  
    43  	case ffMatchNone:
    44  		return ff.matchNone(item)
    45  
    46  	default:
    47  		return ff.matchAll(item)
    48  	}
    49  }
    50  
    51  func (ff *fuzzyFindT) matchAll(item string) bool {
    52  	if len(ff.tokens) == 0 {
    53  		return true
    54  	}
    55  
    56  	for i := range ff.tokens {
    57  		if !strings.Contains(strings.ToLower(item), ff.tokens[i]) {
    58  			return false
    59  		}
    60  	}
    61  
    62  	return true
    63  }
    64  
    65  func (ff *fuzzyFindT) matchSome(item string) bool {
    66  	if len(ff.tokens) == 0 {
    67  		return true
    68  	}
    69  
    70  	for i := range ff.tokens {
    71  		if strings.Contains(strings.ToLower(item), ff.tokens[i]) {
    72  			return true
    73  		}
    74  	}
    75  
    76  	return false
    77  }
    78  
    79  func (ff *fuzzyFindT) matchNone(item string) bool {
    80  	if len(ff.tokens) == 0 {
    81  		return false
    82  	}
    83  
    84  	for i := range ff.tokens {
    85  		if strings.Contains(strings.ToLower(item), ff.tokens[i]) {
    86  			return false
    87  		}
    88  	}
    89  
    90  	return true
    91  }
    92  
    93  type globFindT struct{ pattern string }
    94  
    95  func (gf *globFindT) MatchString(item string) bool {
    96  	found, _ := path.Match(gf.pattern, item)
    97  	return found
    98  }
    99  
   100  func newGlobFind(pattern string) (*globFindT, error) {
   101  	gf := new(globFindT)
   102  	gf.pattern = pattern
   103  	return gf, nil
   104  }
   105  
   106  func newFuzzyFind(pattern string) (findT, []rune, []rune, error) {
   107  	pattern = strings.ToLower(pattern)
   108  	ff := new(fuzzyFindT)
   109  
   110  	ff.tokens = strings.Split(pattern, " ")
   111  
   112  	for {
   113  		if len(ff.tokens) == 0 {
   114  			return ff, rFindSearchPart, rFindCancelPart, nil
   115  		}
   116  
   117  		if ff.tokens[len(ff.tokens)-1] == "" {
   118  			ff.tokens = ff.tokens[:len(ff.tokens)-1]
   119  		} else {
   120  			break
   121  		}
   122  	}
   123  
   124  	switch ff.tokens[0] {
   125  	case "or":
   126  		ff.mode = ffMatchSome
   127  		ff.tokens = ff.tokens[1:]
   128  
   129  	case "!":
   130  		ff.mode = ffMatchNone
   131  		ff.tokens = ff.tokens[1:]
   132  
   133  	case "rx":
   134  		ff.mode = ffMatchRegexp
   135  		pattern = strings.Join(ff.tokens[1:], " ")
   136  		find, err := regexp.Compile("(?i)" + pattern)
   137  		return find, rFindSearchRegex, rFindCancelRegex, err
   138  
   139  	case "g":
   140  		ff.mode = ffMatchGlob
   141  		pattern = strings.Join(ff.tokens[1:], " ")
   142  		find, err := newGlobFind(pattern)
   143  		return find, rFindSearchGlob, rFindCancelGlob, err
   144  
   145  	default:
   146  		if strings.Contains(pattern, "*") {
   147  			ff.mode = ffMatchGlob
   148  			find, err := newGlobFind(pattern)
   149  			return find, rFindSearchGlob, rFindCancelGlob, err
   150  		}
   151  	}
   152  
   153  	return ff, rFindSearchPart, rFindCancelPart, nil
   154  }