From 97b0cb27c0e7a9e33b8344153bae27eed59b6d81 Mon Sep 17 00:00:00 2001 From: Gabriel Levcovitz Date: Wed, 19 Feb 2025 14:02:32 -0300 Subject: [PATCH] feat(highlighting): implement syntax highlighting for unnamed source codes --- README.md | 30 ++-- images/syntax_highlight.png | Bin 0 -> 18844 bytes src/handlers/graphical.rs | 4 +- src/handlers/json.rs | 4 +- src/handlers/narratable.rs | 2 +- src/highlighters/blank.rs | 5 +- src/highlighters/mod.rs | 5 +- src/highlighters/syntect.rs | 25 ++-- src/lib.rs | 36 +++-- src/named_source.rs | 78 ---------- src/protocol.rs | 61 ++------ src/source_code.rs | 82 +++++++++++ tests/graphical.rs | 244 ++++++++++++++++++-------------- tests/narrated.rs | 66 ++++----- tests/test_derive_attr.rs | 26 ++-- tests/test_derive_collection.rs | 38 ++--- tests/test_json.rs | 66 ++++----- 17 files changed, 393 insertions(+), 379 deletions(-) create mode 100644 images/syntax_highlight.png delete mode 100644 src/named_source.rs create mode 100644 src/source_code.rs diff --git a/README.md b/README.md index bd2e887..012cabb 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ You can derive a `Diagnostic` from any `std::error::Error` type. `thiserror` is a great way to define them, and plays nicely with `miette`! */ -use miette::{Diagnostic, NamedSource, SourceSpan}; +use miette::{Diagnostic, MietteSourceCode, SourceSpan}; use thiserror::Error; #[derive(Error, Debug, Diagnostic)] @@ -114,7 +114,7 @@ struct MyBad { // The Source that we're gonna be printing snippets out of. // This can be a String if you don't have or care about file names. #[source_code] - src: NamedSource, + src: MietteSourceCode, // Snippets and highlights can be included in the diagnostic! #[label("This bit here")] bad_bit: SourceSpan, @@ -134,7 +134,7 @@ fn this_fails() -> Result<()> { let src = "source\n text\n here".to_string(); Err(MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), bad_bit: (9, 4).into(), })?; @@ -649,7 +649,6 @@ If you... [`MietteDiagnostic`] directly to create diagnostic on the fly. ```rust - let source = "2 + 2 * 2 = 8".to_string(); let report = miette!( labels = vec![ @@ -665,23 +664,32 @@ println!("{:?}", report) `miette` can be configured to highlight syntax in source code snippets. - + To use the built-in highlighting functionality, you must enable the `syntect-highlighter` crate feature. When this feature is enabled, `miette` will automatically use the [`syntect`] crate to highlight the `#[source_code]` field of your [`Diagnostic`]. -Syntax detection with [`syntect`] is handled by checking 2 methods on the [`SpanContents`] trait, in order: -* [`language()`](SpanContents::language) - Provides the name of the language +Syntax detection with [`syntect`] is handled by checking 2 methods on the [`SourceCode`] trait, in order: +* [`language()`](SourceCode::language) - Provides the name of the language as a string. For example `"Rust"` will indicate Rust syntax highlighting. - You can set the language of the [`SpanContents`] produced by a - [`NamedSource`] via the [`with_language`](NamedSource::with_language) + You can set the language of a [`SourceCode`] by using a + [`MietteSourceCode`], via the [`with_language`](MietteSourceCode::with_language) method. -* [`name()`](SpanContents::name) - In the absence of an explicitly set +* [`name()`](SourceCode::name) - In the absence of an explicitly set language, the name is assumed to contain a file name or file path. The highlighter will check for a file extension at the end of the name and - try to guess the syntax from that. + try to guess the syntax from that. Can also be set via the + [`with_name`](MietteSourceCod::with_name) method. + +```rust +let src = MietteSourceCode::new("fn hello(oops) -> &str { \"hello!\" }").with_language("Rust"); +let report = miette!( + labels = vec![LabeledSpan::at((9, 4), "this is wrong")], + "invalid syntax!", +).with_source_code(src); +``` If you want to use a custom highlighter, you can provide a custom implementation of the [`Highlighter`](highlighters::Highlighter) diff --git a/images/syntax_highlight.png b/images/syntax_highlight.png new file mode 100644 index 0000000000000000000000000000000000000000..25bf43e0544ef0a467790878a31384c8b7a043bc GIT binary patch literal 18844 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 z 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 - let mut highlighter_state = self.highlighter.start_highlighter_state(&*contents); + let mut highlighter_state = self.highlighter.start_highlighter_state(source, &*contents); // The max number of gutter-lines that will be active at any given // point. We need this to figure out indentation, so we do one loop @@ -663,7 +663,7 @@ impl GraphicalReportHandler { None => contents, }; - if let Some(source_name) = primary_contents.name() { + if let Some(source_name) = source.name() { writeln!( f, "[{}]", diff --git a/src/handlers/json.rs b/src/handlers/json.rs index 0b4a405..6899638 100644 --- a/src/handlers/json.rs +++ b/src/handlers/json.rs @@ -159,8 +159,8 @@ impl JSONReportHandler { ) -> fmt::Result { if let Some(mut labels) = diagnostic.labels() { if let Some(label) = labels.next() { - if let Ok(span_content) = source.read_span(label.inner(), 0, 0) { - let filename = span_content.name().unwrap_or_default(); + if source.read_span(label.inner(), 0, 0).is_ok() { + let filename = source.name().unwrap_or_default(); return write!(f, r#""filename": "{}","#, escape(filename)); } } diff --git a/src/handlers/narratable.rs b/src/handlers/narratable.rs index f8d36ae..bf9d87c 100644 --- a/src/handlers/narratable.rs +++ b/src/handlers/narratable.rs @@ -227,7 +227,7 @@ impl NarratableReportHandler { ) -> fmt::Result { let (contents, lines) = self.get_lines(source, context.inner())?; write!(f, "Begin snippet")?; - if let Some(filename) = contents.name() { + if let Some(filename) = source.name() { write!(f, " for {}", filename,)?; } writeln!( diff --git a/src/highlighters/blank.rs b/src/highlighters/blank.rs index 50a9c65..2cdac75 100644 --- a/src/highlighters/blank.rs +++ b/src/highlighters/blank.rs @@ -1,6 +1,6 @@ use owo_colors::Style; -use crate::SpanContents; +use crate::{SourceCode, SpanContents}; use super::{Highlighter, HighlighterState}; @@ -12,7 +12,8 @@ pub struct BlankHighlighter; impl Highlighter for BlankHighlighter { fn start_highlighter_state<'h>( &'h self, - _source: &dyn SpanContents<'_>, + _source: &dyn SourceCode, + _span: &dyn SpanContents<'_>, ) -> Box { Box::new(BlankHighlighterState) } diff --git a/src/highlighters/mod.rs b/src/highlighters/mod.rs index 0af1aa2..1003fcd 100644 --- a/src/highlighters/mod.rs +++ b/src/highlighters/mod.rs @@ -13,7 +13,7 @@ use std::{ops::Deref, sync::Arc}; -use crate::SpanContents; +use crate::{SourceCode, SpanContents}; use owo_colors::Styled; #[cfg(feature = "syntect-highlighter")] @@ -39,7 +39,8 @@ pub trait Highlighter { /// responsible for the actual rendering. fn start_highlighter_state<'h>( &'h self, - source: &dyn SpanContents<'_>, + source: &dyn SourceCode, + span: &dyn SpanContents<'_>, ) -> Box; } diff --git a/src/highlighters/syntect.rs b/src/highlighters/syntect.rs index 538124c..dab7dec 100644 --- a/src/highlighters/syntect.rs +++ b/src/highlighters/syntect.rs @@ -15,7 +15,7 @@ use owo_colors::{Rgb, Style, Styled}; use crate::{ highlighters::{Highlighter, HighlighterState}, - SpanContents, + SourceCode, SpanContents, }; use super::BlankHighlighterState; @@ -42,9 +42,10 @@ impl Default for SyntectHighlighter { impl Highlighter for SyntectHighlighter { fn start_highlighter_state<'h>( &'h self, - source: &dyn SpanContents<'_>, + source: &dyn SourceCode, + span: &dyn SpanContents<'_>, ) -> Box { - if let Some(syntax) = self.detect_syntax(source) { + if let Some(syntax) = self.detect_syntax(source, span) { let highlighter = syntect::Highlighter::new(&self.theme); let parse_state = syntect::ParseState::new(syntax); let highlight_state = @@ -82,13 +83,17 @@ impl SyntectHighlighter { } /// Determine syntect [`SyntaxReference`] to use for given [`SpanContents`]. - fn detect_syntax(&self, contents: &dyn SpanContents<'_>) -> Option<&syntect::SyntaxReference> { + fn detect_syntax( + &self, + source: &dyn SourceCode, + span: &dyn SpanContents<'_>, + ) -> Option<&syntect::SyntaxReference> { // use language if given - if let Some(language) = contents.language() { + if let Some(language) = source.language() { return self.syntax_set.find_syntax_by_name(language); } // otherwise try to use any file extension provided in the name - if let Some(name) = contents.name() { + if let Some(name) = source.name() { if let Some(ext) = Path::new(name).extension() { return self .syntax_set @@ -96,12 +101,8 @@ impl SyntectHighlighter { } } // finally, attempt to guess syntax based on first line - return self.syntax_set.find_syntax_by_first_line( - std::str::from_utf8(contents.data()) - .ok()? - .split('\n') - .next()?, - ); + self.syntax_set + .find_syntax_by_first_line(std::str::from_utf8(span.data()).ok()?.split('\n').next()?) } } diff --git a/src/lib.rs b/src/lib.rs index 6396c9f..092f68b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,7 +100,7 @@ //! //! `thiserror` is a great way to define them, and plays nicely with `miette`! //! */ -//! use miette::{Diagnostic, NamedSource, SourceSpan}; +//! use miette::{Diagnostic, MietteSourceCode, SourceSpan}; //! use thiserror::Error; //! //! #[derive(Error, Debug, Diagnostic)] @@ -114,7 +114,7 @@ //! // The Source that we're gonna be printing snippets out of. //! // This can be a String if you don't have or care about file names. //! #[source_code] -//! src: NamedSource, +//! src: MietteSourceCode, //! // Snippets and highlights can be included in the diagnostic! //! #[label("This bit here")] //! bad_bit: SourceSpan, @@ -134,7 +134,7 @@ //! let src = "source\n text\n here".to_string(); //! //! Err(MyBad { -//! src: NamedSource::new("bad_file.rs", src), +//! src: MietteSourceCode::new(src).with_name("bad_file.rs"), //! bad_bit: (9, 4).into(), //! })?; //! @@ -650,7 +650,6 @@ //! //! ```rust,ignore //! # use miette::{miette, LabeledSpan, Report}; -//! //! let source = "2 + 2 * 2 = 8".to_string(); //! let report = miette!( //! labels = vec![ @@ -666,23 +665,34 @@ //! //! `miette` can be configured to highlight syntax in source code snippets. //! -//! +//! //! //! To use the built-in highlighting functionality, you must enable the //! `syntect-highlighter` crate feature. When this feature is enabled, `miette` will //! automatically use the [`syntect`] crate to highlight the `#[source_code]` //! field of your [`Diagnostic`]. //! -//! Syntax detection with [`syntect`] is handled by checking 2 methods on the [`SpanContents`] trait, in order: -//! * [`language()`](SpanContents::language) - Provides the name of the language +//! Syntax detection with [`syntect`] is handled by checking 2 methods on the [`SourceCode`] trait, in order: +//! * [`language()`](SourceCode::language) - Provides the name of the language //! as a string. For example `"Rust"` will indicate Rust syntax highlighting. -//! You can set the language of the [`SpanContents`] produced by a -//! [`NamedSource`] via the [`with_language`](NamedSource::with_language) +//! You can set the language of a [`SourceCode`] by using a +//! [`MietteSourceCode`], via the [`with_language`](MietteSourceCode::with_language) //! method. -//! * [`name()`](SpanContents::name) - In the absence of an explicitly set +//! * [`name()`](SourceCode::name) - In the absence of an explicitly set //! language, the name is assumed to contain a file name or file path. //! The highlighter will check for a file extension at the end of the name and -//! try to guess the syntax from that. +//! try to guess the syntax from that. Can also be set via the +//! [`with_name`](MietteSourceCod::with_name) method. +//! +//! ```rust +//! # use miette::{miette, LabeledSpan, MietteSourceCode}; +//! # use miette::Result; +//! let src = MietteSourceCode::new("fn hello(oops) -> &str { \"hello!\" }").with_language("Rust"); +//! let report = miette!( +//! labels = vec![LabeledSpan::at((9, 4), "this is wrong")], +//! "invalid syntax!", +//! ).with_source_code(src); +//! ``` //! //! If you want to use a custom highlighter, you can provide a custom //! implementation of the [`Highlighter`](highlighters::Highlighter) @@ -781,10 +791,10 @@ pub use eyreish::*; pub use handler::*; pub use handlers::*; pub use miette_diagnostic::*; -pub use named_source::*; #[cfg(feature = "fancy")] pub use panic::*; pub use protocol::*; +pub use source_code::*; mod chain; mod diagnostic_chain; @@ -799,8 +809,8 @@ pub mod highlighters; #[doc(hidden)] pub mod macro_helpers; mod miette_diagnostic; -mod named_source; #[cfg(feature = "fancy")] mod panic; mod protocol; +mod source_code; mod source_impls; diff --git a/src/named_source.rs b/src/named_source.rs deleted file mode 100644 index ea11cd2..0000000 --- a/src/named_source.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::{MietteError, MietteSpanContents, SourceCode, SpanContents}; - -/// Utility struct for when you have a regular [`SourceCode`] type that doesn't -/// implement `name`. For example [`String`]. Or if you want to override the -/// `name` returned by the `SourceCode`. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct NamedSource { - source: S, - name: String, - language: Option, -} - -impl std::fmt::Debug for NamedSource { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("NamedSource") - .field("name", &self.name) - .field("source", &"") - .field("language", &self.language); - Ok(()) - } -} - -impl NamedSource { - /// Create a new `NamedSource` using a regular [`SourceCode`] and giving - /// its returned [`SpanContents`] a name. - pub fn new(name: impl AsRef, source: S) -> Self - where - S: Send + Sync, - { - Self { - source, - name: name.as_ref().to_string(), - language: None, - } - } - - /// Gets the name of this `NamedSource`. - pub fn name(&self) -> &str { - &self.name - } - - /// Returns a reference the inner [`SourceCode`] type for this - /// `NamedSource`. - pub fn inner(&self) -> &S { - &self.source - } - - /// Sets the [`language`](SpanContents::language) for this source code. - pub fn with_language(mut self, language: impl Into) -> Self { - self.language = Some(language.into()); - self - } -} - -impl SourceCode for NamedSource { - fn read_span<'a>( - &'a self, - span: &crate::SourceSpan, - context_lines_before: usize, - context_lines_after: usize, - ) -> Result + 'a>, MietteError> { - let inner_contents = - self.inner() - .read_span(span, context_lines_before, context_lines_after)?; - let mut contents = MietteSpanContents::new_named( - self.name.clone(), - inner_contents.data(), - *inner_contents.span(), - inner_contents.line(), - inner_contents.column(), - inner_contents.line_count(), - ); - if let Some(language) = &self.language { - contents = contents.with_language(language); - } - Ok(Box::new(contents)) - } -} diff --git a/src/protocol.rs b/src/protocol.rs index 7f09d4d..5b278de 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -253,6 +253,16 @@ pub trait SourceCode: Send + Sync { context_lines_before: usize, context_lines_after: usize, ) -> Result + 'a>, MietteError>; + + /// Optional method. Get this `SourceCode`'s name. + fn name(&self) -> Option<&str> { + None + } + + /// Optional method. Get this `SourceCode`'s language. + fn language(&self) -> Option<&str> { + None + } } /// A labeled [`SourceSpan`]. @@ -439,10 +449,6 @@ pub trait SpanContents<'a> { fn data(&self) -> &'a [u8]; /// [`SourceSpan`] representing the span covered by this `SpanContents`. fn span(&self) -> &SourceSpan; - /// An optional (file?) name for the container of this `SpanContents`. - fn name(&self) -> Option<&str> { - None - } /// The 0-indexed line in the associated [`SourceCode`] where the data /// begins. fn line(&self) -> usize; @@ -451,15 +457,6 @@ pub trait SpanContents<'a> { fn column(&self) -> usize; /// Total number of lines covered by this `SpanContents`. fn line_count(&self) -> usize; - - /// Optional method. The language name for this source code, if any. - /// This is used to drive syntax highlighting. - /// - /// Examples: Rust, TOML, C - /// - fn language(&self) -> Option<&str> { - None - } } /** @@ -477,10 +474,6 @@ pub struct MietteSpanContents<'a> { column: usize, // Number of line in this snippet. line_count: usize, - // Optional filename - name: Option, - // Optional language - language: Option, } impl<'a> MietteSpanContents<'a> { @@ -498,36 +491,8 @@ impl<'a> MietteSpanContents<'a> { line, column, line_count, - name: None, - language: None, } } - - /// Make a new [`MietteSpanContents`] object, with a name for its 'file'. - pub const fn new_named( - name: String, - data: &'a [u8], - span: SourceSpan, - line: usize, - column: usize, - line_count: usize, - ) -> MietteSpanContents<'a> { - MietteSpanContents { - data, - span, - line, - column, - line_count, - name: Some(name), - language: None, - } - } - - /// Sets the [`language`](SpanContents::language) for syntax highlighting. - pub fn with_language(mut self, language: impl Into) -> Self { - self.language = Some(language.into()); - self - } } impl<'a> SpanContents<'a> for MietteSpanContents<'a> { @@ -546,12 +511,6 @@ impl<'a> SpanContents<'a> for MietteSpanContents<'a> { fn line_count(&self) -> usize { self.line_count } - fn name(&self) -> Option<&str> { - self.name.as_deref() - } - fn language(&self) -> Option<&str> { - self.language.as_deref() - } } /// Span within a [`SourceCode`] diff --git a/src/source_code.rs b/src/source_code.rs new file mode 100644 index 0000000..eab578e --- /dev/null +++ b/src/source_code.rs @@ -0,0 +1,82 @@ +use crate::{MietteError, SourceCode, SourceSpan, SpanContents}; + +/// Utility struct for adding attributes such as `name` and `language` to a [`SourceCode`], +/// or if you want to override those attributes from another [`SourceCode`]: +/// +/// ``` +/// # use miette::MietteSourceCode; +/// let src = MietteSourceCode::new("fn f() {}").with_name("snippet").with_language("Rust"); +/// ``` +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct MietteSourceCode { + source: S, + name: Option, + language: Option, +} + +impl MietteSourceCode { + /// Make a new [`MietteSourceCode`] object. + pub fn new(source: S) -> Self { + Self { + source, + name: None, + language: None, + } + } + + /// Set the name for this source code. + pub fn with_name(mut self, name: impl AsRef) -> Self { + self.name = Some(name.as_ref().to_string()); + self + } + + /// Set the language name for this source code. + /// + /// This is used to drive syntax highlighting when the `syntect-highlighter` + /// feature is enabled. + /// + /// Examples: `"Rust"`, `"Python"`, `"C"` + /// + /// The list of language names comes from the [`syntect`] crate. + /// See https://github.com/trishume/syntect/issues/168 + pub fn with_language(mut self, language: impl AsRef) -> Self { + self.language = Some(language.as_ref().to_string()); + self + } +} + +impl std::fmt::Debug for MietteSourceCode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("NamedSource") + .field("name", &self.name) + .field("language", &self.language) + .field("source", &""); + Ok(()) + } +} + +impl SourceCode for MietteSourceCode { + fn read_span<'a>( + &'a self, + span: &SourceSpan, + context_lines_before: usize, + context_lines_after: usize, + ) -> Result + 'a>, MietteError> { + self.source + .read_span(span, context_lines_before, context_lines_after) + } + + fn name(&self) -> Option<&str> { + self.name.as_deref() + } + + fn language(&self) -> Option<&str> { + self.language.as_deref() + } +} + +impl From for MietteSourceCode { + fn from(source: S) -> Self { + MietteSourceCode::new(source) + } +} diff --git a/tests/graphical.rs b/tests/graphical.rs index b80e16d..8b3cac5 100644 --- a/tests/graphical.rs +++ b/tests/graphical.rs @@ -1,9 +1,10 @@ #![cfg(feature = "fancy-no-backtrace")] use miette::{ - Diagnostic, GraphicalReportHandler, GraphicalTheme, MietteError, NamedSource, + Diagnostic, GraphicalReportHandler, GraphicalTheme, MietteError, MietteSourceCode, NarratableReportHandler, Report, SourceSpan, }; +use std::fmt::Debug; use thiserror::Error; fn fmt_report(diag: Report) -> String { @@ -417,14 +418,14 @@ fn empty_source() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (0, 0).into(), }; let out = fmt_report(err.into()); @@ -450,22 +451,22 @@ fn multiple_spans_multiline() { #[diagnostic(severity(Error))] struct MyBad { #[source_code] - src: NamedSource<&'static str>, + src: MietteSourceCode<&'static str>, #[label("big")] big: SourceSpan, #[label("small")] small: SourceSpan, } let err = MyBad { - src: NamedSource::new( - "issue", + src: MietteSourceCode::new( "\ if true { a } else { b }", - ), + ) + .with_name("issue"), big: (0, 32).into(), small: (14, 1).into(), }; @@ -496,12 +497,12 @@ fn single_line_highlight_span_full_line() { #[diagnostic(severity(Error))] struct MyBad { #[source_code] - src: NamedSource<&'static str>, + src: MietteSourceCode<&'static str>, #[label("This bit here")] bad_bit: SourceSpan, } let err = MyBad { - src: NamedSource::new("issue", "source\ntext"), + src: MietteSourceCode::new("source\ntext").with_name("issue"), bad_bit: (7, 4).into(), }; let out = fmt_report(err.into()); @@ -527,14 +528,14 @@ fn single_line_with_wide_char() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n πŸ‘ΌπŸΌtext\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (13, 8).into(), }; let out = fmt_report(err.into()); @@ -564,7 +565,7 @@ fn single_line_with_two_tabs() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } @@ -573,7 +574,7 @@ fn single_line_with_two_tabs() -> Result<(), MietteError> { let src = "source\n\t\ttext\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; let out = fmt_report(err.into()); @@ -603,7 +604,7 @@ fn single_line_with_tab_in_middle() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } @@ -612,7 +613,7 @@ fn single_line_with_tab_in_middle() -> Result<(), MietteError> { let src = "source\ntext =\ttext\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (14, 4).into(), }; let out = fmt_report(err.into()); @@ -642,14 +643,14 @@ fn single_line_highlight() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; let out = fmt_report(err.into()); @@ -686,7 +687,7 @@ fn external_source() -> Result<(), MietteError> { let err = Report::from(MyBad { highlight: (9, 4).into(), }) - .with_source_code(NamedSource::new("bad_file.rs", src)); + .with_source_code(MietteSourceCode::new(src).with_name("bad_file.rs")); let out = fmt_report(err); println!("Error: {}", out); let expected = r#"oops::my::bad @@ -714,14 +715,14 @@ fn single_line_highlight_offset_zero() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (0, 0).into(), }; let out = fmt_report(err.into()); @@ -750,14 +751,14 @@ fn single_line_highlight_offset_end_of_line() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (6, 0).into(), }; let out = fmt_report(err.into()); @@ -786,14 +787,14 @@ fn single_line_highlight_include_end_of_line() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 5).into(), }; let out = fmt_report(err.into()); @@ -823,14 +824,14 @@ fn single_line_highlight_include_end_of_line_crlf() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\r\n text\r\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (10, 6).into(), }; let out = fmt_report(err.into()); @@ -860,14 +861,14 @@ fn single_line_highlight_with_empty_span() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 0).into(), }; let out = fmt_report(err.into()); @@ -897,14 +898,14 @@ fn single_line_highlight_no_label() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; let out = fmt_report(err.into()); @@ -933,14 +934,14 @@ fn single_line_highlight_at_line_start() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\ntext\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (7, 4).into(), }; let out = fmt_report(err.into()); @@ -970,14 +971,14 @@ fn multiline_label() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here\nand\nthis\ntoo")] highlight: SourceSpan, } let src = "source\ntext\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (7, 4).into(), }; let out = fmt_report(err.into()); @@ -1010,7 +1011,7 @@ fn multiple_multi_line_labels() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "x\ny"] highlight1: SourceSpan, #[label = "z\nw"] @@ -1021,7 +1022,7 @@ fn multiple_multi_line_labels() -> Result<(), MietteError> { let src = "source\n text text text text text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (9, 4).into(), highlight2: (14, 4).into(), highlight3: (24, 4).into(), @@ -1058,7 +1059,7 @@ fn multiple_same_line_highlights() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "x"] highlight1: SourceSpan, #[label = "y"] @@ -1069,7 +1070,7 @@ fn multiple_same_line_highlights() -> Result<(), MietteError> { let src = "source\n text text text text text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (9, 4).into(), highlight2: (14, 4).into(), highlight3: (24, 4).into(), @@ -1103,7 +1104,7 @@ fn multiple_same_line_highlights_with_tabs_in_middle() -> Result<(), MietteError #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "x"] highlight1: SourceSpan, #[label = "y"] @@ -1116,7 +1117,7 @@ fn multiple_same_line_highlights_with_tabs_in_middle() -> Result<(), MietteError let src = "source\n text text text\ttext text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (9, 4).into(), highlight2: (14, 4).into(), highlight3: (24, 4).into(), @@ -1150,14 +1151,14 @@ fn multiline_highlight_adjacent() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "these two lines"] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 11).into(), }; let out = fmt_report(err.into()); @@ -1186,14 +1187,14 @@ fn multiline_highlight_multiline_label() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "these two lines\nare the problem"] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 11).into(), }; let out = fmt_report(err.into()); @@ -1223,7 +1224,7 @@ fn multiline_highlight_flyby() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "block 1"] highlight1: SourceSpan, #[label = "block 2"] @@ -1239,7 +1240,7 @@ line5 .to_string(); let len = src.len(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, len).into(), highlight2: (10, 9).into(), }; @@ -1274,7 +1275,7 @@ fn multiline_highlight_no_label() -> Result<(), MietteError> { #[source] source: Inner, #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "block 1"] highlight1: SourceSpan, #[label] @@ -1299,7 +1300,7 @@ line5 let len = src.len(); let err = MyBad { source: Inner(InnerInner), - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, len).into(), highlight2: (10, 9).into(), }; @@ -1338,7 +1339,7 @@ fn multiple_multiline_highlights_adjacent() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "this bit here"] highlight1: SourceSpan, #[label = "also this bit"] @@ -1347,7 +1348,7 @@ fn multiple_multiline_highlights_adjacent() -> Result<(), MietteError> { let src = "source\n text\n here\nmore here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 10).into(), highlight2: (20, 6).into(), }; @@ -1384,7 +1385,7 @@ fn multiple_multiline_highlights_overlapping_lines() -> Result<(), MietteError> #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "this bit here"] highlight1: SourceSpan, #[label = "also this bit"] @@ -1393,7 +1394,7 @@ fn multiple_multiline_highlights_overlapping_lines() -> Result<(), MietteError> let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 8).into(), highlight2: (9, 10).into(), }; @@ -1412,7 +1413,7 @@ fn multiple_multiline_highlights_overlapping_offsets() -> Result<(), MietteError #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "this bit here"] highlight1: SourceSpan, #[label = "also this bit"] @@ -1421,7 +1422,7 @@ fn multiple_multiline_highlights_overlapping_offsets() -> Result<(), MietteError let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 8).into(), highlight2: (10, 10).into(), }; @@ -1516,7 +1517,7 @@ fn related() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[related] @@ -1525,10 +1526,10 @@ fn related() -> Result<(), MietteError> { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src.clone()), + src: MietteSourceCode::new(src.clone()).with_name("bad_file.rs"), highlight: (9, 4).into(), related: vec![MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (0, 6).into(), related: vec![], }], @@ -1571,7 +1572,7 @@ fn related_source_code_propagation() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[related] @@ -1588,7 +1589,7 @@ fn related_source_code_propagation() -> Result<(), MietteError> { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), related: vec![InnerError { highlight: (0, 6).into(), @@ -1631,7 +1632,7 @@ fn related_severity() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[related] @@ -1648,7 +1649,7 @@ fn related_severity() -> Result<(), MietteError> { )] Error { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, }, @@ -1661,7 +1662,7 @@ fn related_severity() -> Result<(), MietteError> { )] Warning { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, }, @@ -1674,7 +1675,7 @@ fn related_severity() -> Result<(), MietteError> { )] Advice { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, }, @@ -1682,19 +1683,19 @@ fn related_severity() -> Result<(), MietteError> { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src.clone()), + src: MietteSourceCode::new(src.clone()).with_name("bad_file.rs"), highlight: (9, 4).into(), related: vec![ MyRelated::Error { - src: NamedSource::new("bad_file.rs", src.clone()), + src: MietteSourceCode::new(src.clone()).with_name("bad_file.rs"), highlight: (0, 6).into(), }, MyRelated::Warning { - src: NamedSource::new("bad_file.rs", src.clone()), + src: MietteSourceCode::new(src.clone()).with_name("bad_file.rs"), highlight: (0, 6).into(), }, MyRelated::Advice { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (0, 6).into(), }, ], @@ -1759,12 +1760,13 @@ fn zero_length_eol_span() { #[diagnostic(severity(Error))] struct MyBad { #[source_code] - src: NamedSource<&'static str>, + src: MietteSourceCode<&'static str>, #[label("This bit here")] bad_bit: SourceSpan, } let err = MyBad { - src: NamedSource::new("issue", "this is the first line\nthis is the second line"), + src: MietteSourceCode::new("this is the first line\nthis is the second line") + .with_name("issue"), bad_bit: (23, 0).into(), }; let out = fmt_report(err.into()); @@ -1789,14 +1791,15 @@ fn primary_label() { #[error("oops!")] struct MyBad { #[source_code] - src: NamedSource<&'static str>, + src: MietteSourceCode<&'static str>, #[label] first_label: SourceSpan, #[label(primary, "nope")] second_label: SourceSpan, } let err = MyBad { - src: NamedSource::new("issue", "this is the first line\nthis is the second line"), + src: MietteSourceCode::new("this is the first line\nthis is the second line") + .with_name("issue"), first_label: (2, 4).into(), second_label: (24, 4).into(), }; @@ -1825,14 +1828,14 @@ fn single_line_with_wide_char_unaligned_span_start() -> Result<(), MietteError> #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n πŸ‘ΌπŸΌtext\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (10, 5).into(), }; let out = fmt_report(err.into()); @@ -1862,14 +1865,14 @@ fn single_line_with_wide_char_unaligned_span_end() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text πŸ‘ΌπŸΌ\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 6).into(), }; let out = fmt_report(err.into()); @@ -1899,14 +1902,14 @@ fn single_line_with_wide_char_unaligned_span_empty() -> Result<(), MietteError> #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n πŸ‘ΌπŸΌtext\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (10, 0).into(), }; let out = fmt_report(err.into()); @@ -1938,17 +1941,17 @@ fn syntax_highlighter() { #[diagnostic()] pub struct Test { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this is a label")] src_span: SourceSpan, } - let src = NamedSource::new( - "hello_world", //NOTE: intentionally missing file extension - "fn main() {\n println!(\"Hello, World!\");\n}\n".to_string(), - ) - .with_language("Rust"); + let name = "hello_world"; // NOTE: intentionally missing file extension + let src = + MietteSourceCode::new("fn main() {\n println!(\"Hello, World!\");\n}\n".to_string()) + .with_language("Rust"); + let src_with_name = src.clone().with_name(name); let err = Test { - src, + src: src_with_name, src_span: (16, 26).into(), }; let mut out = String::new(); @@ -1966,8 +1969,33 @@ fn syntax_highlighter() { ╰──── "# .trim_start_matches('\n'); - assert!(out.contains("\u{1b}[38;2;180;142;173m")); - assert_eq!(expected, strip_ansi_escapes::strip_str(out)) + let colors = "\u{1b}[38;2;180;142;173m"; + assert!(out.contains(colors)); + assert_eq!(expected, strip_ansi_escapes::strip_str(out)); + + // test unnamed source code + let err = Test { + src, + src_span: (16, 26).into(), + }; + let mut out = String::new(); + GraphicalReportHandler::new_themed(GraphicalTheme::unicode()) + .render_report(&mut out, &err) + .unwrap(); + + let expected = r#" + Γ— This is an error + ╭─[2:5] + 1 β”‚ fn main() { + 2 β”‚ println!("Hello, World!"); + Β· ─────────────┬──────────── + Β· ╰── this is a label + 3 β”‚ } + ╰──── +"# + .trim_start_matches('\n'); + assert!(out.contains(colors)); + assert_eq!(expected, strip_ansi_escapes::strip_str(out)); } // This test reads a line from the current source file and renders it with Rust @@ -1985,7 +2013,7 @@ fn syntax_highlighter_on_real_file() { #[diagnostic()] pub struct Test { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this is a label")] src_span: SourceSpan, } @@ -2000,7 +2028,7 @@ fn syntax_highlighter_on_real_file() { let file_src = std::fs::read_to_string(filename).unwrap(); let offset = miette::SourceOffset::from_location(&file_src, line, CO); let err = Test { - src: NamedSource::new(filename, file_src.clone()), + src: MietteSourceCode::new(file_src.clone()).with_name(filename), src_span: SourceSpan::new(offset, LEN), }; @@ -2037,7 +2065,7 @@ fn triple_adjacent_highlight() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "this bit here"] highlight1: SourceSpan, #[label = "also this bit"] @@ -2048,7 +2076,7 @@ fn triple_adjacent_highlight() -> Result<(), MietteError> { let src = "source\n\n\n text\n\n\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 6).into(), highlight2: (11, 4).into(), highlight3: (22, 4).into(), @@ -2086,7 +2114,7 @@ fn non_adjacent_highlight() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "this bit here"] highlight1: SourceSpan, #[label = "also this bit"] @@ -2095,7 +2123,7 @@ fn non_adjacent_highlight() -> Result<(), MietteError> { let src = "source\n\n\n\n text here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 6).into(), highlight2: (12, 4).into(), }; @@ -2129,14 +2157,14 @@ fn invalid_span_bad_offset() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("help info"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "1st"] highlight1: SourceSpan, } let src = "blabla blibli".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (50, 6).into(), }; let out = fmt_report(err.into()); @@ -2158,14 +2186,14 @@ fn invalid_span_bad_length() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("help info"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "1st"] highlight1: SourceSpan, } let src = "blabla blibli".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 50).into(), }; let out = fmt_report(err.into()); @@ -2187,14 +2215,14 @@ fn invalid_span_no_label() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("help info"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label] highlight1: SourceSpan, } let src = "blabla blibli".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (50, 6).into(), }; let out = fmt_report(err.into()); @@ -2216,7 +2244,7 @@ fn invalid_span_2nd_label() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("help info"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("1st")] highlight1: SourceSpan, #[label("2nd")] @@ -2225,7 +2253,7 @@ fn invalid_span_2nd_label() -> Result<(), MietteError> { let src = "blabla blibli".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 6).into(), highlight2: (50, 6).into(), }; @@ -2248,7 +2276,7 @@ fn invalid_span_inner() -> Result<(), MietteError> { #[diagnostic(code(oops::my::inner), help("help info"))] struct MyInner { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("inner label")] inner_label: SourceSpan, } @@ -2258,7 +2286,7 @@ fn invalid_span_inner() -> Result<(), MietteError> { #[diagnostic(code(oops::my::outer), help("help info"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("outer label")] outer_label: SourceSpan, #[source] @@ -2268,10 +2296,10 @@ fn invalid_span_inner() -> Result<(), MietteError> { let src_outer = "outer source".to_string(); let src_inner = "inner source".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src_outer), + src: MietteSourceCode::new(src_outer).with_name("bad_file.rs"), outer_label: (0, 6).into(), inner: MyInner { - src: NamedSource::new("bad_file2.rs", src_inner), + src: MietteSourceCode::new(src_inner).with_name("bad_file2.rs"), inner_label: (60, 6).into(), }, }; @@ -2299,7 +2327,7 @@ fn invalid_span_related() -> Result<(), MietteError> { #[diagnostic(code(oops::my::inner), help("help info"))] struct MyRelated { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("inner label")] inner_label: SourceSpan, } @@ -2309,7 +2337,7 @@ fn invalid_span_related() -> Result<(), MietteError> { #[diagnostic(code(oops::my::outer), help("help info"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("outer label")] outer_label: SourceSpan, #[related] @@ -2319,10 +2347,10 @@ fn invalid_span_related() -> Result<(), MietteError> { let src_outer = "outer source".to_string(); let src_inner = "related source".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src_outer), + src: MietteSourceCode::new(src_outer).with_name("bad_file.rs"), outer_label: (0, 6).into(), inner: vec![MyRelated { - src: NamedSource::new("bad_file2.rs", src_inner), + src: MietteSourceCode::new(src_inner).with_name("bad_file2.rs"), inner_label: (60, 6).into(), }], }; diff --git a/tests/narrated.rs b/tests/narrated.rs index 52acd13..e329eb0 100644 --- a/tests/narrated.rs +++ b/tests/narrated.rs @@ -1,6 +1,8 @@ #![cfg(feature = "fancy-no-backtrace")] -use miette::{Diagnostic, MietteError, NamedSource, NarratableReportHandler, Report, SourceSpan}; +use miette::{ + Diagnostic, MietteError, MietteSourceCode, NarratableReportHandler, Report, SourceSpan, +}; use miette::{GraphicalReportHandler, GraphicalTheme}; @@ -29,14 +31,14 @@ fn single_line_with_wide_char() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n πŸ‘ΌπŸΌtext\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 6).into(), }; let out = fmt_report(err.into()); @@ -65,14 +67,14 @@ fn single_line_highlight() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; let out = fmt_report(err.into()); @@ -101,14 +103,14 @@ fn single_line_highlight_offset_zero() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (0, 0).into(), }; let out = fmt_report(err.into()); @@ -136,14 +138,14 @@ fn single_line_highlight_with_empty_span() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 0).into(), }; let out = fmt_report(err.into()); @@ -172,14 +174,14 @@ fn single_line_highlight_no_label() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; let out = fmt_report(err.into()); @@ -208,14 +210,14 @@ fn single_line_highlight_at_line_start() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\ntext\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (7, 4).into(), }; let out = fmt_report(err.into()); @@ -244,7 +246,7 @@ fn multiple_same_line_highlights() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "x"] highlight1: SourceSpan, #[label = "y"] @@ -255,7 +257,7 @@ fn multiple_same_line_highlights() -> Result<(), MietteError> { let src = "source\n text text text text text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (9, 4).into(), highlight2: (14, 4).into(), highlight3: (24, 4).into(), @@ -288,14 +290,14 @@ fn multiline_highlight_adjacent() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "these two lines"] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 11).into(), }; let out = fmt_report(err.into()); @@ -325,7 +327,7 @@ fn multiline_highlight_flyby() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "block 1"] highlight1: SourceSpan, #[label = "block 2"] @@ -341,7 +343,7 @@ line5 .to_string(); let len = src.len(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, len).into(), highlight2: (10, 9).into(), }; @@ -378,7 +380,7 @@ fn multiline_highlight_no_label() -> Result<(), MietteError> { #[source] source: Inner, #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "block 1"] highlight1: SourceSpan, #[label] @@ -403,7 +405,7 @@ line5 let len = src.len(); let err = MyBad { source: Inner(InnerInner), - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, len).into(), highlight2: (10, 9).into(), }; @@ -444,7 +446,7 @@ fn multiple_multiline_highlights_adjacent() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "this bit here"] highlight1: SourceSpan, #[label = "also this bit"] @@ -453,7 +455,7 @@ fn multiple_multiline_highlights_adjacent() -> Result<(), MietteError> { let src = "source\n text\n here\nmore here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 10).into(), highlight2: (20, 6).into(), }; @@ -492,7 +494,7 @@ fn multiple_multiline_highlights_overlapping_lines() -> Result<(), MietteError> #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "this bit here"] highlight1: SourceSpan, #[label = "also this bit"] @@ -501,7 +503,7 @@ fn multiple_multiline_highlights_overlapping_lines() -> Result<(), MietteError> let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 8).into(), highlight2: (9, 10).into(), }; @@ -520,7 +522,7 @@ fn multiple_multiline_highlights_overlapping_offsets() -> Result<(), MietteError #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "this bit here"] highlight1: SourceSpan, #[label = "also this bit"] @@ -529,7 +531,7 @@ fn multiple_multiline_highlights_overlapping_offsets() -> Result<(), MietteError let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 8).into(), highlight2: (10, 10).into(), }; @@ -559,7 +561,7 @@ fn related() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[related] @@ -568,10 +570,10 @@ fn related() -> Result<(), MietteError> { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src.clone()), + src: MietteSourceCode::new(src.clone()).with_name("bad_file.rs"), highlight: (9, 4).into(), related: vec![MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (0, 6).into(), related: vec![], }], @@ -614,7 +616,7 @@ fn related_source_code_propagation() -> Result<(), MietteError> { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[related] @@ -631,7 +633,7 @@ fn related_source_code_propagation() -> Result<(), MietteError> { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), related: vec![InnerError { highlight: (0, 6).into(), diff --git a/tests/test_derive_attr.rs b/tests/test_derive_attr.rs index f1b0f3d..f664b92 100644 --- a/tests/test_derive_attr.rs +++ b/tests/test_derive_attr.rs @@ -1,5 +1,5 @@ // Testing of the `diagnostic` attr used by derive(Diagnostic) -use miette::{Diagnostic, LabeledSpan, NamedSource, SourceSpan}; +use miette::{Diagnostic, LabeledSpan, MietteSourceCode, SourceSpan}; use thiserror::Error; #[test] @@ -10,7 +10,7 @@ fn enum_uses_base_attr() { enum MyBad { Only { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, }, @@ -18,7 +18,7 @@ fn enum_uses_base_attr() { let src = "source\n text\n here".to_string(); let err = MyBad::Only { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; assert_eq!(err.code().unwrap().to_string(), "error::on::base"); @@ -32,7 +32,7 @@ fn enum_uses_variant_attr() { #[diagnostic(code(error::on::variant))] Only { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, }, @@ -40,7 +40,7 @@ fn enum_uses_variant_attr() { let src = "source\n text\n here".to_string(); let err = MyBad::Only { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; assert_eq!(err.code().unwrap().to_string(), "error::on::variant"); @@ -55,7 +55,7 @@ fn multiple_attrs_allowed_on_item() { enum MyBad { Only { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, }, @@ -63,7 +63,7 @@ fn multiple_attrs_allowed_on_item() { let src = "source\n text\n here".to_string(); let err = MyBad::Only { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; assert_eq!(err.code().unwrap().to_string(), "error::on::base"); @@ -79,7 +79,7 @@ fn multiple_attrs_allowed_on_variant() { #[diagnostic(help("try doing it correctly"))] Only { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, }, @@ -87,7 +87,7 @@ fn multiple_attrs_allowed_on_variant() { let src = "source\n text\n here".to_string(); let err = MyBad::Only { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; assert_eq!(err.code().unwrap().to_string(), "error::on::variant"); @@ -104,7 +104,7 @@ fn attrs_can_be_split_between_item_and_variants() { #[diagnostic(url("https://example.com/foo/bar"))] Only { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, }, @@ -112,7 +112,7 @@ fn attrs_can_be_split_between_item_and_variants() { let src = "source\n text\n here".to_string(); let err = MyBad::Only { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; assert_eq!(err.code().unwrap().to_string(), "error::on::base"); @@ -130,7 +130,7 @@ fn attr_not_required() { enum MyBad { Only { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, }, @@ -138,7 +138,7 @@ fn attr_not_required() { let src = "source\n text\n here".to_string(); let err = MyBad::Only { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; let err_span = err.labels().unwrap().next().unwrap(); diff --git a/tests/test_derive_collection.rs b/tests/test_derive_collection.rs index 952b505..cd854bf 100644 --- a/tests/test_derive_collection.rs +++ b/tests/test_derive_collection.rs @@ -4,7 +4,7 @@ use std::{ }; // Testing of the `diagnostic` attr used by derive(Diagnostic) -use miette::{Diagnostic, LabeledSpan, NamedSource, SourceSpan}; +use miette::{Diagnostic, LabeledSpan, MietteSourceCode, SourceSpan}; use thiserror::Error; #[test] @@ -14,7 +14,7 @@ fn attr_collection_in_enum() { enum MyBad { Only { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[label(collection, "and here")] @@ -24,7 +24,7 @@ fn attr_collection_in_enum() { let src = "source\n text\n here".to_string(); let err = MyBad::Only { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), highlight2: vec![(1, 2).into(), (3, 4).into()], }; @@ -46,7 +46,7 @@ fn attr_collection_in_struct() { #[error("oops!")] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[label(collection, "and here")] @@ -55,7 +55,7 @@ fn attr_collection_in_struct() { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), highlight2: vec![(1, 2).into(), (3, 4).into()], }; @@ -77,7 +77,7 @@ fn attr_collection_as_deque() { #[error("oops!")] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[label(collection, "and here")] @@ -86,7 +86,7 @@ fn attr_collection_as_deque() { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), highlight2: VecDeque::from([(1, 2).into(), (3, 4).into()]), }; @@ -108,7 +108,7 @@ fn attr_collection_as_linked_list() { #[error("oops!")] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[label(collection, "and here")] @@ -117,7 +117,7 @@ fn attr_collection_as_linked_list() { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), highlight2: LinkedList::from([(1, 2).into(), (3, 4).into()]), }; @@ -139,7 +139,7 @@ fn attr_collection_of_tuple() { #[error("oops!")] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[label(collection, "and here")] @@ -148,7 +148,7 @@ fn attr_collection_of_tuple() { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), highlight2: vec![(1, 2), (3, 4)], }; @@ -170,7 +170,7 @@ fn attr_collection_of_range() { #[error("oops!")] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[label(collection, "and here")] @@ -179,7 +179,7 @@ fn attr_collection_of_range() { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), highlight2: vec![1..3, 3..7], }; @@ -201,7 +201,7 @@ fn attr_collection_of_labeled_span_in_struct() { #[error("oops!")] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[label(collection, "then there")] @@ -210,7 +210,7 @@ fn attr_collection_of_labeled_span_in_struct() { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), highlight2: vec![ LabeledSpan::new_with_span(Some("continuing here".to_string()), (1, 2)), @@ -236,7 +236,7 @@ fn attr_collection_of_labeled_span_in_enum() { enum MyBad { Only { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[label(collection, "then there")] @@ -246,7 +246,7 @@ fn attr_collection_of_labeled_span_in_enum() { let src = "source\n text\n here".to_string(); let err = MyBad::Only { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), highlight2: vec![ LabeledSpan::new_with_span(Some("continuing here".to_string()), (1, 2)), @@ -271,7 +271,7 @@ fn attr_collection_multi() { #[error("oops!")] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[label(collection, "and here")] @@ -282,7 +282,7 @@ fn attr_collection_multi() { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), highlight2: vec![(1, 2).into(), (3, 4).into()], highlight3: vec![(5, 6).into(), (7, 8).into()], diff --git a/tests/test_json.rs b/tests/test_json.rs index 664318a..21d63dd 100644 --- a/tests/test_json.rs +++ b/tests/test_json.rs @@ -1,5 +1,5 @@ mod json_report_handler { - use miette::{Diagnostic, MietteError, NamedSource, Report, SourceSpan}; + use miette::{Diagnostic, MietteError, MietteSourceCode, Report, SourceSpan}; use miette::JSONReportHandler; @@ -20,14 +20,14 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n πŸ‘ΌπŸΌtext\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 6).into(), }; let out = fmt_report(err.into()); @@ -65,14 +65,14 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; let out = fmt_report(err.into()); @@ -110,14 +110,14 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (0, 0).into(), }; let out = fmt_report(err.into()); @@ -155,14 +155,14 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 0).into(), }; let out = fmt_report(err.into()); @@ -200,14 +200,14 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), }; let out = fmt_report(err.into()); @@ -244,14 +244,14 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, } let src = "source\ntext\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (7, 4).into(), }; let out = fmt_report(err.into()); @@ -289,7 +289,7 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "x"] highlight1: SourceSpan, #[label = "y"] @@ -300,7 +300,7 @@ mod json_report_handler { let src = "source\n text text text text text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (9, 4).into(), highlight2: (14, 4).into(), highlight3: (24, 4).into(), @@ -354,14 +354,14 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "these two lines"] highlight: SourceSpan, } let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 11).into(), }; let out = fmt_report(err.into()); @@ -399,7 +399,7 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "block 1"] highlight1: SourceSpan, #[label = "block 2"] @@ -415,7 +415,7 @@ mod json_report_handler { .to_string(); let len = src.len(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, len).into(), highlight2: (10, 9).into(), }; @@ -463,7 +463,7 @@ mod json_report_handler { #[source] source: Inner, #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "block 1"] highlight1: SourceSpan, #[label] @@ -488,7 +488,7 @@ mod json_report_handler { let len = src.len(); let err = MyBad { source: Inner(InnerInner), - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, len).into(), highlight2: (10, 9).into(), }; @@ -536,7 +536,7 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "this bit here"] highlight1: SourceSpan, #[label = "also this bit"] @@ -545,7 +545,7 @@ mod json_report_handler { let src = "source\n text\n here\nmore here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 10).into(), highlight2: (20, 6).into(), }; @@ -591,7 +591,7 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "this bit here"] highlight1: SourceSpan, #[label = "also this bit"] @@ -600,7 +600,7 @@ mod json_report_handler { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 8).into(), highlight2: (9, 10).into(), }; @@ -646,7 +646,7 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label = "this bit here"] highlight1: SourceSpan, #[label = "also this bit"] @@ -655,7 +655,7 @@ mod json_report_handler { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight1: (0, 8).into(), highlight2: (10, 10).into(), }; @@ -728,7 +728,7 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[related] @@ -737,16 +737,16 @@ mod json_report_handler { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src.clone()), + src: MietteSourceCode::new(src.clone()).with_name("bad_file.rs"), highlight: (9, 4).into(), related: vec![ MyBad { - src: NamedSource::new("bad_file2.rs", src.clone()), + src: MietteSourceCode::new(src.clone()).with_name("bad_file2.rs"), highlight: (0, 6).into(), related: vec![], }, MyBad { - src: NamedSource::new("bad_file3.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file3.rs"), highlight: (0, 6).into(), related: vec![], }, @@ -821,7 +821,7 @@ mod json_report_handler { #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))] struct MyBad { #[source_code] - src: NamedSource, + src: MietteSourceCode, #[label("this bit here")] highlight: SourceSpan, #[related] @@ -838,7 +838,7 @@ mod json_report_handler { let src = "source\n text\n here".to_string(); let err = MyBad { - src: NamedSource::new("bad_file.rs", src), + src: MietteSourceCode::new(src).with_name("bad_file.rs"), highlight: (9, 4).into(), related: vec![ InnerError {