diff --git a/cli/src/command_error.rs b/cli/src/command_error.rs index 0083e2d06a..d0aa801ab5 100644 --- a/cli/src/command_error.rs +++ b/cli/src/command_error.rs @@ -30,6 +30,7 @@ use jj_lib::revset::{ RevsetEvaluationError, RevsetParseError, RevsetParseErrorKind, RevsetResolutionError, }; use jj_lib::signing::SignInitError; +use jj_lib::str_util::StringPatternParseError; use jj_lib::working_copy::{ResetError, SnapshotError, WorkingCopyStateError}; use jj_lib::workspace::WorkspaceInitError; use thiserror::Error; @@ -423,6 +424,9 @@ impl From for CommandError { name: _, candidates, } => format_similarity_hint(candidates), + RevsetParseErrorKind::InvalidFunctionArguments { .. } => { + find_source_parse_error_hint(bottom_err) + } _ => None, }; let mut cmd_err = @@ -470,6 +474,8 @@ impl From for CommandError { | TemplateParseErrorKind::NoSuchMethod { candidates, .. } => { format_similarity_hint(candidates) } + TemplateParseErrorKind::InvalidArguments { .. } + | TemplateParseErrorKind::Expression(_) => find_source_parse_error_hint(bottom_err), _ => None, }; let mut cmd_err = @@ -489,7 +495,10 @@ impl From for CommandError { impl From for CommandError { fn from(err: clap::Error) -> Self { - cli_error(err) + let hint = find_source_parse_error_hint(&err); + let mut cmd_err = cli_error(err); + cmd_err.extend_hints(hint); + cmd_err } } @@ -511,6 +520,24 @@ impl From for CommandError { } } +fn find_source_parse_error_hint(err: &dyn error::Error) -> Option { + let source = err.source()?; + if let Some(source) = source.downcast_ref() { + string_pattern_parse_error_hint(source) + } else { + None + } +} + +fn string_pattern_parse_error_hint(err: &StringPatternParseError) -> Option { + match err { + StringPatternParseError::InvalidKind(_) => { + Some("Try prefixing with one of `exact:`, `glob:` or `substring:`".into()) + } + StringPatternParseError::GlobPattern(_) => None, + } +} + const BROKEN_PIPE_EXIT_CODE: u8 = 3; pub(crate) fn handle_command_result(ui: &mut Ui, result: Result<(), CommandError>) -> ExitCode { diff --git a/cli/tests/test_branch_command.rs b/cli/tests/test_branch_command.rs index b31f390378..decf83f0d8 100644 --- a/cli/tests/test_branch_command.rs +++ b/cli/tests/test_branch_command.rs @@ -396,9 +396,10 @@ fn test_branch_delete_glob() { // Unknown pattern kind let stderr = test_env.jj_cmd_cli_error(&repo_path, &["branch", "forget", "whatever:branch"]); insta::assert_snapshot!(stderr, @r###" - error: invalid value 'whatever:branch' for '[NAMES]...': Invalid string pattern kind "whatever:", try prefixing with one of `exact:`, `glob:` or `substring:` + error: invalid value 'whatever:branch' for '[NAMES]...': Invalid string pattern kind "whatever:" For more information, try '--help'. + Hint: Try prefixing with one of `exact:`, `glob:` or `substring:` "###); } diff --git a/cli/tests/test_revset_output.rs b/cli/tests/test_revset_output.rs index 86a558cd07..2d3bdd5afb 100644 --- a/cli/tests/test_revset_output.rs +++ b/cli/tests/test_revset_output.rs @@ -175,7 +175,8 @@ fn test_bad_function_call() { | ^---------^ | = Function "branches": Invalid string pattern - 2: Invalid string pattern kind "bad:", try prefixing with one of `exact:`, `glob:` or `substring:` + 2: Invalid string pattern kind "bad:" + Hint: Try prefixing with one of `exact:`, `glob:` or `substring:` "###); let stderr = test_env.jj_cmd_failure(&repo_path, &["log", "-r", "root()::whatever()"]); diff --git a/lib/src/str_util.rs b/lib/src/str_util.rs index 1df3fdf2fc..2cef8bae9b 100644 --- a/lib/src/str_util.rs +++ b/lib/src/str_util.rs @@ -25,7 +25,7 @@ use thiserror::Error; #[derive(Debug, Error)] pub enum StringPatternParseError { /// Unknown pattern kind is specified. - #[error(r#"Invalid string pattern kind "{0}:", try prefixing with one of `exact:`, `glob:` or `substring:`"#)] + #[error(r#"Invalid string pattern kind "{0}:""#)] InvalidKind(String), /// Failed to parse glob pattern. #[error(transparent)]