Skip to content

Commit 20ee15c

Browse files
committed
feat: suggests commands on abbreviation match failure
1 parent 21d2752 commit 20ee15c

File tree

3 files changed

+28
-18
lines changed

3 files changed

+28
-18
lines changed

application.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,11 @@ func (a *Application) Run(arguments []string) (err error) {
117117
args := context.Args()
118118
if args.Present() {
119119
name := args.first()
120-
context.Command = a.BestCommand(name)
120+
context.Command, err = a.BestCommand(name)
121+
if err != nil {
122+
HandleExitCoder(err)
123+
return err
124+
}
121125
}
122126

123127
if a.Before != nil {
@@ -175,10 +179,10 @@ func (a *Application) Command(name string) *Command {
175179
// BestCommand returns the named command on App or a command fuzzy matching if
176180
// there is only one. Returns nil if the command does not exist of if the fuzzy
177181
// matching find more than one.
178-
func (a *Application) BestCommand(name string) *Command {
182+
func (a *Application) BestCommand(name string) (*Command, error) {
179183
name = strings.ToLower(name)
180184
if c := a.Command(name); c != nil {
181-
return c
185+
return c, nil
182186
}
183187

184188
// fuzzy match?
@@ -190,9 +194,15 @@ func (a *Application) BestCommand(name string) *Command {
190194
}
191195
if len(matches) == 1 {
192196
matches[0].UserName = name
193-
return matches[0]
197+
return matches[0], nil
198+
} else if len(matches) > 1 {
199+
suggestions := ""
200+
for _, m := range matches {
201+
suggestions += fmt.Sprintf("\n %s", m.FullName())
202+
}
203+
return nil, fmt.Errorf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s", name, suggestions)
194204
}
195-
return nil
205+
return nil, nil
196206
}
197207

198208
// Category returns the named CommandCategory on App. Returns nil if the category does not exist

command_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,22 +124,22 @@ func TestCaseInsensitiveCommandNames(t *testing.T) {
124124

125125
app.setup()
126126

127-
if c := app.BestCommand("project:list"); c != projectList {
127+
if c, _ := app.BestCommand("project:list"); c != projectList {
128128
t.Fatalf("expected project:list, got %v", c)
129129
}
130-
if c := app.BestCommand("Project:lISt"); c != projectList {
130+
if c, _ := app.BestCommand("Project:lISt"); c != projectList {
131131
t.Fatalf("expected project:list, got %v", c)
132132
}
133-
if c := app.BestCommand("project:link"); c != projectLink {
133+
if c, _ := app.BestCommand("project:link"); c != projectLink {
134134
t.Fatalf("expected project:link, got %v", c)
135135
}
136-
if c := app.BestCommand("project:Link"); c != projectLink {
136+
if c, _ := app.BestCommand("project:Link"); c != projectLink {
137137
t.Fatalf("expected project:link, got %v", c)
138138
}
139-
if c := app.BestCommand("foo"); c != projectList {
139+
if c, _ := app.BestCommand("foo"); c != projectList {
140140
t.Fatalf("expected project:link, got %v", c)
141141
}
142-
if c := app.BestCommand("FoO"); c != projectList {
142+
if c, _ := app.BestCommand("FoO"); c != projectList {
143143
t.Fatalf("expected project:link, got %v", c)
144144
}
145145
}
@@ -154,27 +154,27 @@ func TestFuzzyCommandNames(t *testing.T) {
154154
projectLink,
155155
}
156156

157-
c := app.BestCommand("project:list")
157+
c, _ := app.BestCommand("project:list")
158158
if c != projectList {
159159
t.Fatalf("expected project:list, got %v", c)
160160
}
161-
c = app.BestCommand("project:link")
161+
c, _ = app.BestCommand("project:link")
162162
if c != projectLink {
163163
t.Fatalf("expected project:link, got %v", c)
164164
}
165-
c = app.BestCommand("pro:list")
165+
c, _ = app.BestCommand("pro:list")
166166
if c != projectList {
167167
t.Fatalf("expected project:list, got %v", c)
168168
}
169-
c = app.BestCommand("pro:lis")
169+
c, _ = app.BestCommand("pro:lis")
170170
if c != projectList {
171171
t.Fatalf("expected project:list, got %v", c)
172172
}
173-
c = app.BestCommand("p:lis")
173+
c, _ = app.BestCommand("p:lis")
174174
if c != projectList {
175175
t.Fatalf("expected project:list, got %v", c)
176176
}
177-
c = app.BestCommand("p:li")
177+
c, _ = app.BestCommand("p:li")
178178
if c != nil {
179179
t.Fatalf("expected no matches, got %v", c)
180180
}

help.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ func ShowAppHelp(c *Context) error {
147147

148148
// ShowCommandHelp prints help for the given command
149149
func ShowCommandHelp(ctx *Context, command string) error {
150-
if c := ctx.App.BestCommand(command); c != nil {
150+
if c, _ := ctx.App.BestCommand(command); c != nil {
151151
if c.DescriptionFunc != nil {
152152
c.Description = c.DescriptionFunc(c, ctx.App)
153153
}

0 commit comments

Comments
 (0)