-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
fix(task): suggest similar commands when mistyping a CLI subcommand #8286
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| #!/usr/bin/env bash | ||
| # Test that mistyped CLI commands suggest the correct command instead of | ||
| # showing a confusing "no tasks defined" error. | ||
| # See: https://github.com/jdx/mise/discussions/8278 | ||
|
|
||
| set -euo pipefail | ||
| export RUST_BACKTRACE=0 | ||
| export MISE_FRIENDLY_ERROR=1 | ||
|
|
||
| # Test: Typo of a known command should suggest the correct command | ||
| assert_fail "mise bin-path" "Did you mean" | ||
| assert_fail "mise bin-path" "bin-paths" | ||
|
|
||
| # Test: Another typo should suggest the correct command | ||
| assert_fail "mise instal" "install" | ||
|
|
||
| # Test: Should say "unknown command" not "no tasks defined" for command typos | ||
| assert_fail "mise bin-path" "unknown command" |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -61,9 +61,42 @@ fn validate_monorepo_setup(config: &Arc<Config>) -> Result<()> { | |||||
| Ok(()) | ||||||
| } | ||||||
|
|
||||||
| /// Check if a name is similar to any known CLI subcommands using fuzzy matching | ||||||
| fn suggest_similar_commands(name: &str) -> Vec<String> { | ||||||
| use clap::CommandFactory; | ||||||
| let cmd = crate::cli::Cli::command(); | ||||||
| let matcher = SkimMatcherV2::default().use_cache(true).smart_case(); | ||||||
| cmd.get_subcommands() | ||||||
| .flat_map(|s| std::iter::once(s.get_name()).chain(s.get_all_aliases())) | ||||||
|
Comment on lines
+66
to
+70
|
||||||
| .filter_map(|subcmd| { | ||||||
| matcher | ||||||
| .fuzzy_match(subcmd, name) | ||||||
| .filter(|&score| score > 0) | ||||||
| .map(|score| (score, subcmd.to_string())) | ||||||
| }) | ||||||
| .sorted_by_key(|(score, _)| -1 * *score) | ||||||
| .take(3) | ||||||
|
Comment on lines
+76
to
+78
|
||||||
| .map(|(_, subcmd)| subcmd) | ||||||
| .collect() | ||||||
| } | ||||||
|
|
||||||
| /// Show an error when a task is not found, with helpful suggestions | ||||||
| async fn err_no_task(config: &Config, name: &str) -> Result<()> { | ||||||
| // Check early if the name looks like a mistyped CLI subcommand | ||||||
| let similar_cmds = suggest_similar_commands(name); | ||||||
|
|
||||||
| if config.tasks().await.is_ok_and(|t| t.is_empty()) { | ||||||
| // If the name matches a CLI subcommand closely, suggest that instead of | ||||||
| // the confusing "no tasks defined" message | ||||||
| if !similar_cmds.is_empty() { | ||||||
| let mut err_msg = format!("unknown command: {}", style::ered(name)); | ||||||
| err_msg.push_str("\n\nDid you mean:"); | ||||||
|
||||||
| err_msg.push_str("\n\nDid you mean:"); | |
| err_msg.push_str("\n\nDid you mean?"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check for similar CLI commands currently takes precedence over the check for untrusted configuration files. If a user has tasks defined in an untrusted config but mistypes the task name (or if the name fuzzy-matches a CLI command), they will see an 'unknown command' error instead of being prompted to trust their config.
It is better to prioritize the untrusted config check, as this is a common reason why expected tasks are missing from the task list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot
AI
Feb 21, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This header says Did you mean the command: but multiple suggestions can be printed. Consider making this consistent with the earlier branch (and pluralizing if needed), e.g. use the same Did you mean… header in both places to avoid two different formats for the same kind of suggestion.
| err_msg.push_str("\n\nDid you mean the command:"); | |
| err_msg.push_str("\n\nDid you mean one of these?"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is recommended to filter out hidden subcommands from the suggestions. Internal or plumbing commands (such as
hook-env,completion, etc.) are typically not intended for direct use and can make the suggestions less relevant to the user's intent.