Skip to content

Commit ed400b8

Browse files
committed
Add command suggestions feature
1 parent 2a8f95f commit ed400b8

File tree

2 files changed

+33
-0
lines changed

2 files changed

+33
-0
lines changed

invoke/program.py

+32
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import difflib
12
import getpass
23
import inspect
34
import json
@@ -86,6 +87,12 @@ def core_args(self) -> List["Argument"]:
8687
default=False,
8788
help="Echo executed commands before running.",
8889
),
90+
Argument(
91+
names=("suggestions", "s"),
92+
kind=bool,
93+
default=True,
94+
help="Show possible commands suggestions.",
95+
),
8996
Argument(
9097
names=("help", "h"),
9198
optional=True,
@@ -403,6 +410,11 @@ def run(self, argv: Optional[List[str]] = None, exit: bool = True) -> None:
403410
# problems.
404411
if isinstance(e, ParseError):
405412
print(e, file=sys.stderr)
413+
if self.args.suggestions.value:
414+
unrecognised_cmd = str(e).replace("No idea what '", "")
415+
unrecognised_cmd = unrecognised_cmd.replace("' is!", "")
416+
msg = self._possible_commands_msg(unrecognised_cmd)
417+
print(msg, file=sys.stderr)
406418
if isinstance(e, Exit) and e.message:
407419
print(e.message, file=sys.stderr)
408420
if isinstance(e, UnexpectedExit) and e.result.hide:
@@ -985,3 +997,23 @@ def print_columns(
985997
else:
986998
print(spec.rstrip())
987999
print("")
1000+
1001+
def _possible_commands_msg(self, unknown_cmd: str) -> str:
1002+
try:
1003+
all_tasks = self.scoped_collection.task_names
1004+
except AttributeError:
1005+
all_tasks = {}
1006+
1007+
possible_cmds = list(all_tasks.keys())
1008+
suggestions = difflib.get_close_matches(
1009+
unknown_cmd, possible_cmds, n=3, cutoff=0.7
1010+
)
1011+
output_message = f"'{unknown_cmd}' is not an invoke command. "
1012+
output_message += "See 'invoke --list'.\n"
1013+
if suggestions:
1014+
output_message += "\nThe most similar command(s):\n"
1015+
for cmd in suggestions:
1016+
output_message += f" {cmd}\n"
1017+
else:
1018+
output_message += "\nNo suggestions was found.\n"
1019+
return output_message

tests/program.py

+1
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@ def core_help_option_prints_core_help(self):
599599
-r STRING, --search-root=STRING Change root directory used for finding
600600
task modules.
601601
-R, --dry Echo commands instead of running.
602+
-s, --suggestions Show possible commands suggestions.
602603
-T INT, --command-timeout=INT Specify a global command execution
603604
timeout, in seconds.
604605
-V, --version Show version and exit.

0 commit comments

Comments
 (0)