From 03060245d816a53a33209e6b7e1c3c42948e9962 Mon Sep 17 00:00:00 2001 From: Nahor Date: Thu, 15 Feb 2024 18:14:04 -0800 Subject: [PATCH] feat(collection): add support for collection of labels (#341) Fixes: https://github.com/zkat/miette/issues/315 Allow errors to have a number of labels determined at runtime. An example of this is when the rust compiler labels all the arms of a `match` expression when one of them has an incompatible type To allow customization of the text for each label in a collection, add support for using LabeledSpan in collections instead of just regular spans --- README.md | 52 ++++++ miette-derive/src/label.rs | 211 +++++++++++++++------- src/macro_helpers.rs | 23 +++ src/protocol.rs | 5 + tests/test_derive_collection.rs | 306 ++++++++++++++++++++++++++++++++ 5 files changed, 534 insertions(+), 63 deletions(-) create mode 100644 tests/test_derive_collection.rs diff --git a/README.md b/README.md index 0e936b3a..302e0b5e 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ libraries and such might not want. - [... handler options](#-handler-options) - [... dynamic diagnostics](#-dynamic-diagnostics) - [... syntax highlighting](#-syntax-highlighting) + - [... collection of labels](#-collection-of-labels) - [Acknowledgements](#acknowledgements) - [License](#license) @@ -671,6 +672,57 @@ trait to [`MietteHandlerOpts`] by calling the [`with_syntax_highlighting`](MietteHandlerOpts::with_syntax_highlighting) method. See the [`highlighters`] module docs for more details. +#### ... collection of labels + +When the number of labels is unknown, you can use a collection of `SourceSpan` +(or any type convertible into `SourceSpan`). For this, add the `collection` +parameter to `label` and use any type than can be iterated over for the field. + +```rust +#[derive(Debug, Diagnostic, Error)] +#[error("oops!")] +struct MyError { + #[label("main issue")] + primary_span: SourceSpan, + + #[label(collection, "related to this")] + other_spans: Vec>, +} + +let report: miette::Report = MyError { + primary_span: (6, 9).into(), + other_spans: vec![19..26, 30..41], +}.into(); + +println!("{:?}", report.with_source_code("About something or another or yet another ...".to_string())); +``` + +A collection can also be of `LabeledSpan` if you want to have different text +for different labels. Labels with no text will use the one from the `label` +attribute + +```rust +#[derive(Debug, Diagnostic, Error)] +#[error("oops!")] +struct MyError { + #[label("main issue")] + primary_span: SourceSpan, + + #[label(collection, "related to this")] + other_spans: Vec, // LabeledSpan +} + +let report: miette::Report = MyError { + primary_span: (6, 9).into(), + other_spans: vec![ + LabeledSpan::new(None, 19, 7), // Use default text `related to this` + LabeledSpan::new(Some("and also this".to_string()), 30, 11), // Use specific text + ], +}.into(); + +println!("{:?}", report.with_source_code("About something or another or yet another ...".to_string())); +``` + ### MSRV This crate requires rustc 1.70.0 or later. diff --git a/miette-derive/src/label.rs b/miette-derive/src/label.rs index dd5ec693..cd6994ab 100644 --- a/miette-derive/src/label.rs +++ b/miette-derive/src/label.rs @@ -16,16 +16,23 @@ use crate::{ pub struct Labels(Vec