Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow user to set the "hasPrefix" function in Complete() #99

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions complete.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
}
}
Expand Down
41 changes: 31 additions & 10 deletions complete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down Expand Up @@ -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 -",
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -364,15 +385,15 @@ 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)
}
os.Setenv(envLine, line)
os.Setenv(envPoint, strconv.Itoa(point))
b := bytes.NewBuffer(nil)
c.Out = b
c.Complete()
c.Complete(completeArgs...)
completions = parseOutput(b.String())
return
}
Expand Down