github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/cmds/elvish/edit/completion/matcher.go (about) 1 package completion 2 3 import ( 4 "errors" 5 "strings" 6 7 "github.com/u-root/u-root/cmds/elvish/eval" 8 "github.com/u-root/u-root/cmds/elvish/eval/vals" 9 "github.com/u-root/u-root/cmds/elvish/util" 10 "github.com/u-root/u-root/cmds/elvish/hashmap" 11 ) 12 13 var ( 14 errIncorrectNumOfResults = errors.New("matcher must return a bool for each candidate") 15 errMatcherMustBeFn = errors.New("matcher must be a function") 16 errMatcherInputMustBeString = errors.New("matcher input must be string") 17 ) 18 19 var ( 20 matchPrefix = eval.NewBuiltinFn( 21 "edit:match-prefix", wrapMatcher(strings.HasPrefix)) 22 matchSubstr = eval.NewBuiltinFn( 23 "edit:match-substr", wrapMatcher(strings.Contains)) 24 matchSubseq = eval.NewBuiltinFn( 25 "edit:match-subseq", wrapMatcher(util.HasSubseq)) 26 ) 27 28 func lookupMatcher(m hashmap.Map, name string) (eval.Callable, bool) { 29 key := name 30 if !hashmap.HasKey(m, key) { 31 // Use fallback matcher 32 if !hashmap.HasKey(m, "") { 33 return nil, false 34 } 35 key = "" 36 } 37 value, _ := m.Index(key) 38 matcher, ok := value.(eval.Callable) 39 return matcher, ok 40 } 41 42 func wrapMatcher(matcher func(s, p string) bool) interface{} { 43 return func(fm *eval.Frame, 44 opts eval.RawOptions, pattern string, inputs eval.Inputs) { 45 46 var options struct { 47 IgnoreCase bool 48 SmartCase bool 49 } 50 opts.Scan(&options) 51 switch { 52 case options.IgnoreCase && options.SmartCase: 53 throwf("-ignore-case and -smart-case cannot be used together") 54 case options.IgnoreCase: 55 innerMatcher := matcher 56 matcher = func(s, p string) bool { 57 return innerMatcher(strings.ToLower(s), strings.ToLower(p)) 58 } 59 case options.SmartCase: 60 innerMatcher := matcher 61 matcher = func(s, p string) bool { 62 if p == strings.ToLower(p) { 63 // Ignore case is pattern is all lower case. 64 return innerMatcher(strings.ToLower(s), p) 65 } else { 66 return innerMatcher(s, p) 67 } 68 } 69 } 70 71 out := fm.OutputChan() 72 inputs(func(v interface{}) { 73 s, ok := v.(string) 74 if !ok { 75 throw(errMatcherInputMustBeString) 76 } 77 out <- vals.Bool(matcher(s, pattern)) 78 }) 79 } 80 }