diff --git a/cli/src/command_error.rs b/cli/src/command_error.rs index f947ca006f..988f27f9a3 100644 --- a/cli/src/command_error.rs +++ b/cli/src/command_error.rs @@ -543,15 +543,20 @@ fn print_error_sources(ui: &Ui, source: Option<&dyn error::Error>) -> io::Result let Some(err) = source else { return Ok(()); }; - if err.source().is_none() { - writeln!(ui.stderr(), "Caused by: {err}")?; - } else { - writeln!(ui.stderr(), "Caused by:")?; - for (i, err) in iter::successors(Some(err), |err| err.source()).enumerate() { - writeln!(ui.stderr(), "{n}: {err}", n = i + 1)?; - } - } - Ok(()) + ui.stderr_formatter() + .with_label("error_source", |formatter| { + if err.source().is_none() { + write!(formatter.labeled("heading"), "Caused by: ")?; + writeln!(formatter, "{err}")?; + } else { + writeln!(formatter.labeled("heading"), "Caused by:")?; + for (i, err) in iter::successors(Some(err), |err| err.source()).enumerate() { + write!(formatter.labeled("heading"), "{}: ", i + 1)?; + writeln!(formatter, "{err}")?; + } + } + Ok(()) + }) } fn handle_clap_error(ui: &mut Ui, err: &clap::Error, hints: &[String]) -> io::Result { diff --git a/cli/src/config/colors.toml b/cli/src/config/colors.toml index e2fa251ef2..79c748a4b8 100644 --- a/cli/src/config/colors.toml +++ b/cli/src/config/colors.toml @@ -1,8 +1,10 @@ [colors] "error" = { fg = "default", bold = true } +"error_source" = { fg = "default" } "warning" = { fg = "default", bold = true } "hint" = { fg = "default" } "error heading" = { fg = "red", bold = true } +"error_source heading" = { bold = true } "warning heading" = { fg = "yellow", bold = true } "hint heading" = { fg = "cyan", bold = true } diff --git a/cli/tests/test_global_opts.rs b/cli/tests/test_global_opts.rs index fa8ce5860d..6b005f5cec 100644 --- a/cli/tests/test_global_opts.rs +++ b/cli/tests/test_global_opts.rs @@ -400,6 +400,13 @@ fn test_color_ui_messages() { Error: There is no jj repo in "." "###); + // error source + let stderr = test_env.jj_cmd_failure(&repo_path, &["log", ".."]); + insta::assert_snapshot!(stderr, @r###" + Error: Path ".." is not in the repo "." + Caused by: Invalid component ".." in repo-relative path "../" + "###); + // warning let (_stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["log", "@"]); insta::assert_snapshot!(stderr, @r###" @@ -418,7 +425,7 @@ fn test_color_ui_messages() { ], ); insta::assert_snapshot!(stdout, @r###" - 8bb159bc30a9859930e567eb9238a7c43ee6744d + 167f90e7600a50f85c4f909b53eaf546faa82879 <Error: No commit available> (elided revisions) 0000000000000000000000000000000000000000 "###);