diff --git a/Cargo.lock b/Cargo.lock index d05080174..ccbdde82f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,11 +40,12 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "annotate-snippets" -version = "0.11.5" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4" +checksum = "7a851f39ec7e23bf1c30faf3844a496fee4db701f5f840f68d1f78f00e697892" dependencies = [ "anstyle", + "memchr", "unicode-width", ] diff --git a/Cargo.toml b/Cargo.toml index 30dfc6095..7fd04749b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ homepage = "https://github.com/rust-lang/cargo" repository = "https://github.com/rust-lang/cargo" [workspace.dependencies] -annotate-snippets = "0.11.5" +annotate-snippets = { version = "0.12.1", features = ["simd"] } anstream = "0.6.20" anstyle = "1.0.11" anyhow = "1.0.98" diff --git a/src/cargo/core/shell.rs b/src/cargo/core/shell.rs index 53b189645..918b59fbc 100644 --- a/src/cargo/core/shell.rs +++ b/src/cargo/core/shell.rs @@ -2,7 +2,7 @@ use std::fmt; use std::io::IsTerminal; use std::io::prelude::*; -use annotate_snippets::{Message, Renderer}; +use annotate_snippets::{Renderer, Report}; use anstream::AutoStream; use anstyle::Style; @@ -406,8 +406,8 @@ impl Shell { Ok(()) } - /// Prints the passed in [Message] to stderr - pub fn print_message(&mut self, message: Message<'_>) -> std::io::Result<()> { + /// Prints the passed in [`Report`] to stderr + pub fn print_report(&mut self, report: Report<'_>) -> std::io::Result<()> { let term_width = self .err_width() .diagnostic_terminal_width() @@ -415,7 +415,7 @@ impl Shell { writeln!( self.err(), "{}", - Renderer::styled().term_width(term_width).render(message) + Renderer::styled().term_width(term_width).render(report) ) } } diff --git a/src/cargo/util/lints.rs b/src/cargo/util/lints.rs index f6c25412b..06ea6f470 100644 --- a/src/cargo/util/lints.rs +++ b/src/cargo/util/lints.rs @@ -1,6 +1,6 @@ use crate::core::{Edition, Feature, Features, Manifest, Package}; use crate::{CargoResult, GlobalContext}; -use annotate_snippets::{Level, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Snippet}; use cargo_util_schemas::manifest::{TomlLintLevel, TomlToolLints}; use pathdiff::diff_paths; use std::fmt::Display; @@ -145,32 +145,33 @@ fn verify_feature_enabled( panic!("could not find `cargo::{lint_name}` in `[lints]`, or `[workspace.lints]` ") }; - let mut message = Level::Error - .title(&title) - .snippet( - Snippet::source(contents) - .origin(path) - .annotation(Level::Error.span(span.key).label(&label)) - .fold(true), - ) - .footer(Level::Help.title(&help)); + let mut report = Vec::new(); + report.push( + Group::with_title(Level::ERROR.primary_title(title)) + .element( + Snippet::source(contents) + .path(path) + .annotation(AnnotationKind::Primary.span(span.key).label(label)), + ) + .element(Level::HELP.message(help)), + ); if let Some(inherit_span) = get_key_value_span(manifest.document(), &["lints", "workspace"]) { - message = message.footer( - Level::Note.title(&second_title).snippet( + report.push( + Group::with_title(Level::NOTE.secondary_title(second_title)).element( Snippet::source(manifest.contents()) - .origin(&manifest_path) + .path(manifest_path) .annotation( - Level::Note.span(inherit_span.key.start..inherit_span.value.end), - ) - .fold(true), + AnnotationKind::Context + .span(inherit_span.key.start..inherit_span.value.end), + ), ), ); } *error_count += 1; - gctx.shell().print_message(message)?; + gctx.shell().print_report(&report)?; } Ok(()) } @@ -330,12 +331,12 @@ impl LintLevel { self == &LintLevel::Forbid || self == &LintLevel::Deny } - pub fn to_diagnostic_level(self) -> Level { + pub fn to_diagnostic_level(self) -> Level<'static> { match self { LintLevel::Allow => unreachable!("allow does not map to a diagnostic level"), - LintLevel::Warn => Level::Warning, - LintLevel::Deny => Level::Error, - LintLevel::Forbid => Level::Error, + LintLevel::Warn => Level::WARNING, + LintLevel::Deny => Level::ERROR, + LintLevel::Forbid => Level::ERROR, } } } @@ -450,17 +451,15 @@ pub fn check_im_a_teapot( let span = get_key_value_span(manifest.document(), &["package", "im-a-teapot"]).unwrap(); - let message = level - .title(IM_A_TEAPOT.desc) - .snippet( + let report = &[Group::with_title(level.primary_title(IM_A_TEAPOT.desc)) + .element( Snippet::source(manifest.contents()) - .origin(&manifest_path) - .annotation(level.span(span.key.start..span.value.end)) - .fold(true), + .path(&manifest_path) + .annotation(AnnotationKind::Primary.span(span.key.start..span.value.end)), ) - .footer(Level::Note.title(&emitted_reason)); + .element(Level::NOTE.message(&emitted_reason))]; - gctx.shell().print_message(message)?; + gctx.shell().print_report(report)?; } Ok(()) } @@ -540,37 +539,36 @@ fn output_unknown_lints( panic!("could not find `cargo::{lint_name}` in `[lints]`, or `[workspace.lints]` ") }; - let mut message = level.title(&title).snippet( + let mut report = Vec::new(); + let mut group = Group::with_title(level.clone().primary_title(title)).element( Snippet::source(contents) - .origin(path) - .annotation(Level::Error.span(span.key)) - .fold(true), + .path(path) + .annotation(AnnotationKind::Primary.span(span.key)), ); - if emitted_source.is_none() { emitted_source = Some(UNKNOWN_LINTS.emitted_source(lint_level, reason)); - message = message.footer(Level::Note.title(emitted_source.as_ref().unwrap())); + group = group.element(Level::NOTE.message(emitted_source.as_ref().unwrap())); } - if let Some(help) = help.as_ref() { - message = message.footer(Level::Help.title(help)); + group = group.element(Level::HELP.message(help)); } + report.push(group); if let Some(inherit_span) = get_key_value_span(manifest.document(), &["lints", "workspace"]) { - message = message.footer( - Level::Note.title(&second_title).snippet( + report.push( + Group::with_title(Level::NOTE.secondary_title(second_title)).element( Snippet::source(manifest.contents()) - .origin(&manifest_path) + .path(manifest_path) .annotation( - Level::Note.span(inherit_span.key.start..inherit_span.value.end), - ) - .fold(true), + AnnotationKind::Context + .span(inherit_span.key.start..inherit_span.value.end), + ), ), - ) + ); } - gctx.shell().print_message(message)?; + gctx.shell().print_report(&report)?; } Ok(()) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index d6b51ba62..70c7e7b91 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{Level, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Snippet}; use std::borrow::Cow; use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::ffi::OsStr; @@ -1879,12 +1879,11 @@ fn missing_dep_diagnostic( "`{}` is an unused optional dependency since no feature enables it", &dep_name ); - let message = Level::Error.title(&title); - let snippet = Snippet::source(&contents) - .origin(&manifest_path) - .fold(true) - .annotation(Level::Error.span(feature_span.value)); - let message = if missing_dep.weak_optional { + let group = Group::with_title(Level::ERROR.primary_title(&title)); + let snippet = Snippet::source(contents) + .path(manifest_path) + .annotation(AnnotationKind::Primary.span(feature_span.value)); + let group = if missing_dep.weak_optional { let mut orig_deps = vec![ ( orig_toml.dependencies.as_ref(), @@ -1920,17 +1919,20 @@ fn missing_dep_diagnostic( .collect::>(); let dep_span = get_key_value_span(&document, &toml_path).unwrap(); - message - .snippet(snippet.annotation(Level::Warning.span(dep_span.key).label(&info_label))) - .footer(Level::Help.title(&help)) + group + .element( + snippet + .annotation(AnnotationKind::Context.span(dep_span.key).label(info_label)), + ) + .element(Level::HELP.message(help)) } else { - message.snippet(snippet) + group.element(snippet) } } else { - message.snippet(snippet) + group.element(snippet) }; - if let Err(err) = gctx.shell().print_message(message) { + if let Err(err) = gctx.shell().print_report(&[group]) { return Err(err.into()); } Err(AlreadyPrintedError::new(anyhow!("").into()).into()) @@ -2792,13 +2794,13 @@ fn emit_diagnostic( .unwrap_or_else(|| manifest_file.to_path_buf()) .display() .to_string(); - let message = Level::Error.title(e.message()).snippet( + let group = Group::with_title(Level::ERROR.primary_title(e.message())).element( Snippet::source(contents) - .origin(&manifest_path) - .fold(true) - .annotation(Level::Error.span(span)), + .path(manifest_path) + .annotation(AnnotationKind::Primary.span(span)), ); - if let Err(err) = gctx.shell().print_message(message) { + + if let Err(err) = gctx.shell().print_report(&[group]) { return err.into(); } return AlreadyPrintedError::new(e.into()).into(); diff --git a/tests/testsuite/alt_registry.rs b/tests/testsuite/alt_registry.rs index 9099cdd12..7c49dfa5e 100644 --- a/tests/testsuite/alt_registry.rs +++ b/tests/testsuite/alt_registry.rs @@ -749,13 +749,12 @@ fn bad_registry_name() { .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid character ` ` in registry name: `bad name`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters) - - + + --> Cargo.toml:8:17 | 8 | [dependencies.bar] | ^^^^^^^^^^^^^^^^^^ - | "#]]) .run(); @@ -1976,13 +1975,12 @@ fn empty_dependency_registry() { .with_status(101) .with_stderr_data(str![[r#" [ERROR] registry name cannot be empty - - + + --> Cargo.toml:8:23 | 8 | bar = { version = "0.1.0", registry = "" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | "#]]) .run(); diff --git a/tests/testsuite/bad_config.rs b/tests/testsuite/bad_config.rs index 406f0b1b7..15869bbd4 100644 --- a/tests/testsuite/bad_config.rs +++ b/tests/testsuite/bad_config.rs @@ -455,11 +455,12 @@ fn malformed_override() { .with_status(101) .with_stderr_data(str![[r#" [ERROR] newlines are unsupported in inline tables, expected nothing - --> Cargo.toml:9:27 - | -9 | native = { - | ^ - | + --> Cargo.toml:9:27 + | + 9 | native = { + | ___________________________^ +10 | | foo: "bar" + | |_^ "#]]) .run(); @@ -2635,7 +2636,6 @@ fn bad_dependency() { | 9 | bar = 3 | ^ - | "#]]) .run(); @@ -2664,13 +2664,12 @@ fn bad_dependency_true_literal() { .with_status(101) .with_stderr_data(str![[r#" [ERROR] invalid type: boolean `true`, expected a version string like "0.9.8" or a detailed dependency like { version = "0.9.8" } -[NOTE] if you meant to use a workspace member, you can write - dep.workspace = true + [NOTE] if you meant to use a workspace member, you can write + dep.workspace = true --> Cargo.toml:9:23 | 9 | bar = true | ^^^^ - | "#]]) .run(); @@ -2703,7 +2702,6 @@ fn bad_debuginfo() { | 9 | debug = 'a' | ^^^ - | "#]]) .run(); @@ -2736,7 +2734,6 @@ fn bad_debuginfo2() { | 9 | debug = 3.6 | ^^^ - | "#]]) .run(); @@ -2767,7 +2764,6 @@ fn bad_opt_level() { | 7 | build = 3 | ^ - | "#]]) .run(); @@ -3067,7 +3063,6 @@ fn bad_trim_paths() { | 8 | trim-paths = "split-debuginfo" | ^^^^^^^^^^^^^^^^^ - | "#]]) .run(); diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index 4c44c8836..9e63e421a 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -423,7 +423,6 @@ fn cargo_compile_with_invalid_manifest2() { | 3 | foo = bar | ^^^ - | "#]]) .run(); @@ -441,7 +440,6 @@ fn cargo_compile_with_invalid_manifest3() { | 1 | a = bar | ^^^ - | "#]]) .run(); @@ -496,7 +494,6 @@ fn cargo_compile_with_invalid_version() { | 4 | version = "1.0" | ^^^^^ - | "#]]) .run(); @@ -516,7 +513,6 @@ fn cargo_compile_with_empty_package_name() { | 3 | name = "" | ^^ - | "#]]) .run(); @@ -536,7 +532,6 @@ fn cargo_compile_with_invalid_package_name() { | 3 | name = "foo@bar" | ^^^^^^^^^ - | "#]]) .run(); @@ -1317,7 +1312,6 @@ fn cargo_compile_with_invalid_dep_rename() { | 8 | "haha this isn't a valid name 🐛" = { package = "libc", version = "0.1" } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | "#]]) .run(); diff --git a/tests/testsuite/cargo_add/invalid_manifest/stderr.term.svg b/tests/testsuite/cargo_add/invalid_manifest/stderr.term.svg index f9c867bc7..611e12f42 100644 --- a/tests/testsuite/cargo_add/invalid_manifest/stderr.term.svg +++ b/tests/testsuite/cargo_add/invalid_manifest/stderr.term.svg @@ -1,4 +1,4 @@ - +