diff --git a/complete.go b/complete.go index 423cbec..a48d39c 100644 --- a/complete.go +++ b/complete.go @@ -45,13 +45,35 @@ func (c *Complete) Run() bool { return c.Complete() } +type completeArgs struct { + prefixMatcher func(str, prefix string) bool +} + +//CompleteArg is a config argument for Complete.Complete +type CompleteArg func(*completeArgs) + +//WithMatcher causes Complete to use the given matcher function when filtering completion options +func WithMatcher(matcher func(str, prefix string) bool) CompleteArg { + return func(configs *completeArgs) { + configs.prefixMatcher = matcher + } +} + // Complete a command from completion line in environment variable, // and print out the complete options. // returns success if the completion ran or if the cli matched // any of the given flags, false otherwise // For installation: it assumes that flags were added and parsed before // it was called. -func (c *Complete) Complete() bool { +func (c *Complete) Complete(configSetters ...CompleteArg) bool { + cfg := &completeArgs{ + prefixMatcher: strings.HasPrefix, + } + + for _, configSetter := range configSetters { + configSetter(cfg) + } + line, point, ok := getEnv() if !ok { // make sure flags parsed, @@ -72,7 +94,7 @@ func (c *Complete) Complete() bool { // filter only options that match the last argument matches := []string{} for _, option := range options { - if strings.HasPrefix(option, a.Last) { + if cfg.prefixMatcher(option, a.Last) { matches = append(matches, option) } } diff --git a/complete_test.go b/complete_test.go index 45fa304..0776497 100644 --- a/complete_test.go +++ b/complete_test.go @@ -13,6 +13,14 @@ import ( func TestCompleter_Complete(t *testing.T) { initTests() + buildCompleteArgs := func(args ...CompleteArg) []CompleteArg { + return args + } + + permissiveMatcher := func(str, prefix string) bool { + return true + } + c := Command{ Sub: Commands{ "sub1": { @@ -40,14 +48,16 @@ func TestCompleter_Complete(t *testing.T) { cmp := New("cmd", c) tests := []struct { - line string - point int // -1 indicates len(line) - want []string + line string + point int // -1 indicates len(line) + want []string + completeArgs []CompleteArg }{ { - line: "cmd ", - point: -1, - want: []string{"sub1", "sub2"}, + line: "cmd ", + point: -1, + want: []string{"sub1", "sub2"}, + completeArgs: buildCompleteArgs(WithMatcher(permissiveMatcher)), }, { line: "cmd -", @@ -69,6 +79,17 @@ func TestCompleter_Complete(t *testing.T) { point: -1, want: []string{"sub1", "sub2"}, }, + { + line: "cmd SuB", + point: -1, + want: []string{}, + }, + { + line: "cmd SuB", + point: -1, + want: []string{"sub1", "sub2"}, + completeArgs: buildCompleteArgs(WithMatcher(permissiveMatcher)), + }, { line: "cmd sub1", point: -1, @@ -262,7 +283,7 @@ func TestCompleter_Complete(t *testing.T) { for _, tt := range tests { t.Run(fmt.Sprintf("%s@%d", tt.line, tt.point), func(t *testing.T) { - got := runComplete(cmp, tt.line, tt.point) + got := runComplete(cmp, tt.line, tt.point, tt.completeArgs) sort.Strings(tt.want) sort.Strings(got) @@ -349,7 +370,7 @@ func TestCompleter_Complete_SharedPrefix(t *testing.T) { for _, tt := range tests { t.Run(tt.line, func(t *testing.T) { - got := runComplete(cmp, tt.line, tt.point) + got := runComplete(cmp, tt.line, tt.point, nil) sort.Strings(tt.want) sort.Strings(got) @@ -364,7 +385,7 @@ func TestCompleter_Complete_SharedPrefix(t *testing.T) { // runComplete runs the complete login for test purposes // it gets the complete struct and command line arguments and returns // the complete options -func runComplete(c *Complete, line string, point int) (completions []string) { +func runComplete(c *Complete, line string, point int, completeArgs []CompleteArg) (completions []string) { if point == -1 { point = len(line) } @@ -372,7 +393,7 @@ func runComplete(c *Complete, line string, point int) (completions []string) { os.Setenv(envPoint, strconv.Itoa(point)) b := bytes.NewBuffer(nil) c.Out = b - c.Complete() + c.Complete(completeArgs...) completions = parseOutput(b.String()) return }