Skip to content

Commit 5e8a9eb

Browse files
YuviGoldumarcor
authored andcommitted
Support subcommands checking for suggestions (spf13#1500)
Till now, only the root command is looked for suggestions. Now `findSuggestions` works for nested commands as well. For example ``` Error: unknown command "rewin" for "root times" Did you mean this? rewind Run 'root times --help' for usage. ``` Signed-off-by: Yuval Goldberg <yuvigoldi@gmail.com>
1 parent f235efa commit 5e8a9eb

File tree

2 files changed

+101
-29
lines changed

2 files changed

+101
-29
lines changed

‎args.go‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@ func validateArgs(cmd *Command, args []string) error {
2727
}
2828

2929
// Legacy arg validation has the following behaviour:
30-
// - root commands with no subcommands can take arbitrary arguments
31-
// - root commands with subcommands will do subcommand validity checking
30+
// - commands with no subcommands can take arbitrary arguments
31+
// - commands with subcommands will do subcommand validity checking
3232
// - subcommands will always accept arbitrary arguments
3333
func legacyArgs(cmd *Command, args []string) error {
3434
// no subcommand, always take args
3535
if !cmd.HasSubCommands() {
3636
return nil
3737
}
3838

39-
// root command with subcommands, do subcommand checking.
40-
if !cmd.HasParent() && len(args) > 0 {
39+
// do subcommand checking
40+
if len(args) > 0 {
4141
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
4242
}
4343
return nil

‎command_test.go‎

Lines changed: 97 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,39 +1194,111 @@ func TestSuggestions(t *testing.T) {
11941194
SuggestFor: []string{"counts"},
11951195
Run: emptyRun,
11961196
}
1197+
rewindCmd := &Command{
1198+
Use: "rewind",
1199+
SuggestFor: []string{"dejavu"},
1200+
Run: emptyRun,
1201+
}
1202+
timesCmd.AddCommand(rewindCmd)
11971203
rootCmd.AddCommand(timesCmd)
11981204

1199-
templateWithSuggestions := "Error: unknown command \"%s\" for \"root\"\n\nDid you mean this?\n\t%s\n\nRun 'root --help' for usage.\n"
1200-
templateWithoutSuggestions := "Error: unknown command \"%s\" for \"root\"\nRun 'root --help' for usage.\n"
1201-
1202-
tests := map[string]string{
1203-
"time": "times",
1204-
"tiems": "times",
1205-
"tims": "times",
1206-
"timeS": "times",
1207-
"rimes": "times",
1208-
"ti": "times",
1209-
"t": "times",
1210-
"timely": "times",
1211-
"ri": "",
1212-
"timezone": "",
1213-
"foo": "",
1214-
"counts": "times",
1215-
}
1216-
1217-
for typo, suggestion := range tests {
1205+
templateSuggestions := "\nDid you mean this?\n\t%s\n\n"
1206+
1207+
templatePrefix := "Error: unknown command \"%s\" for \"%s\"\n"
1208+
templateSuffix := "Run '%s --help' for usage.\n"
1209+
1210+
tests := []struct {
1211+
input string
1212+
targetCommand string
1213+
expectedSuggestion string
1214+
}{
1215+
{
1216+
input: "time",
1217+
expectedSuggestion: "times",
1218+
},
1219+
{
1220+
input: "tiems",
1221+
expectedSuggestion: "times",
1222+
},
1223+
{
1224+
input: "tims",
1225+
expectedSuggestion: "times",
1226+
},
1227+
{
1228+
input: "timeS",
1229+
expectedSuggestion: "times",
1230+
},
1231+
{
1232+
input: "rimes",
1233+
expectedSuggestion: "times",
1234+
},
1235+
{
1236+
input: "ti",
1237+
expectedSuggestion: "times",
1238+
},
1239+
{
1240+
input: "t",
1241+
expectedSuggestion: "times",
1242+
},
1243+
{
1244+
input: "timely",
1245+
expectedSuggestion: "times",
1246+
},
1247+
{
1248+
input: "ri",
1249+
expectedSuggestion: "",
1250+
},
1251+
{
1252+
input: "timezone",
1253+
expectedSuggestion: "",
1254+
},
1255+
{
1256+
input: "foo",
1257+
expectedSuggestion: "",
1258+
},
1259+
{
1260+
input: "counts",
1261+
expectedSuggestion: "times",
1262+
},
1263+
{
1264+
input: "foo rewind",
1265+
expectedSuggestion: "",
1266+
},
1267+
{
1268+
input: "times rewin",
1269+
targetCommand: "root times",
1270+
expectedSuggestion: "rewind",
1271+
},
1272+
{
1273+
input: "times dejavu",
1274+
targetCommand: "root times",
1275+
expectedSuggestion: "rewind",
1276+
},
1277+
}
1278+
1279+
for index := range tests {
12181280
for _, suggestionsDisabled := range []bool{true, false} {
1281+
test := tests[index]
1282+
1283+
timesCmd.DisableSuggestions = suggestionsDisabled
12191284
rootCmd.DisableSuggestions = suggestionsDisabled
12201285

1221-
var expected string
1222-
output, _ := executeCommand(rootCmd, typo)
1286+
args := strings.Split(test.input, " ")
1287+
output, _ := executeCommand(rootCmd, args...)
12231288

1224-
if suggestion == "" || suggestionsDisabled {
1225-
expected = fmt.Sprintf(templateWithoutSuggestions, typo)
1226-
} else {
1227-
expected = fmt.Sprintf(templateWithSuggestions, typo, suggestion)
1289+
unknownArg := args[len(args)-1]
1290+
if test.targetCommand == "" {
1291+
test.targetCommand = rootCmd.Use
1292+
unknownArg = args[0]
12281293
}
12291294

1295+
expected := fmt.Sprintf(templatePrefix, unknownArg, test.targetCommand)
1296+
if test.expectedSuggestion != "" && !suggestionsDisabled {
1297+
expected += fmt.Sprintf(templateSuggestions, test.expectedSuggestion)
1298+
}
1299+
1300+
expected += fmt.Sprintf(templateSuffix, test.targetCommand)
1301+
12301302
if output != expected {
12311303
t.Errorf("Unexpected response.\nExpected:\n %q\nGot:\n %q\n", expected, output)
12321304
}

0 commit comments

Comments
 (0)