Merge branch 'main' into fmt-width

This commit is contained in:
Dion Dokter 2025-11-26 11:22:15 +01:00
commit 2d303d8507
16 changed files with 59 additions and 78 deletions

View File

@ -33,11 +33,11 @@ jobs:
strategy: strategy:
matrix: matrix:
features: [fancy, syntect-highlighter] features: [fancy, syntect-highlighter]
rust: [1.70.0, stable] rust: [1.82.0, stable]
os: [ubuntu-latest, macOS-latest, windows-latest] os: [ubuntu-latest, macOS-latest, windows-latest]
exclude: exclude:
- features: syntect-highlighter - features: syntect-highlighter
rust: 1.70.0 rust: 1.82.0
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -52,7 +52,7 @@ jobs:
if: matrix.rust == 'stable' if: matrix.rust == 'stable'
run: cargo test --all --verbose --features ${{matrix.features}} run: cargo test --all --verbose --features ${{matrix.features}}
- name: Run tests - name: Run tests
if: matrix.rust == '1.70.0' if: matrix.rust == '1.82.0'
run: cargo test --all --verbose --features ${{matrix.features}} no-format-args-capture run: cargo test --all --verbose --features ${{matrix.features}} no-format-args-capture
wasm: wasm:

View File

@ -9,12 +9,12 @@ documentation = "https://docs.rs/miette"
license = "Apache-2.0" license = "Apache-2.0"
readme = "README.md" readme = "README.md"
edition = "2018" edition = "2018"
rust-version = "1.70.0" rust-version = "1.82.0"
exclude = ["images/", "tests/", "miette-derive/"] exclude = ["images/", "tests/", "miette-derive/"]
[dependencies] [dependencies]
miette-derive = { path = "miette-derive", version = "=7.6.0", optional = true } miette-derive = { path = "miette-derive", version = "=7.6.0", optional = true }
unicode-width = "0.1.11" unicode-width = "0.2.0"
cfg-if = "1.0.0" cfg-if = "1.0.0"
owo-colors = { version = "4.0.0", optional = true } owo-colors = { version = "4.0.0", optional = true }
@ -39,7 +39,6 @@ rustversion = "1.0"
trybuild = { version = "1.0.89", features = ["diff"] } trybuild = { version = "1.0.89", features = ["diff"] }
syn = { version = "2.0.87", features = ["full"] } syn = { version = "2.0.87", features = ["full"] }
regex = "1.10" regex = "1.10"
lazy_static = "1.4"
serde = { version = "1.0.196", features = ["derive"] } serde = { version = "1.0.196", features = ["derive"] }
serde_json = "1.0.113" serde_json = "1.0.113"

View File

@ -211,6 +211,17 @@ pub enum MyLibError {
// Use `#[diagnostic(transparent)]` to wrap another [`Diagnostic`]. You won't see labels otherwise // Use `#[diagnostic(transparent)]` to wrap another [`Diagnostic`]. You won't see labels otherwise
#[diagnostic(transparent)] #[diagnostic(transparent)]
AnotherError(#[from] AnotherError), AnotherError(#[from] AnotherError),
/// Forward the diagnostic to a particular field.
#[error("other error")]
#[diagnostic(forward(the_actual_diagnostic))]
EvenMoreData {
unrelated_field_1: String,
unrelated_field_2: usize,
#[source]
the_actual_diagnostic: AnotherError,
}
} }
#[derive(Error, Diagnostic, Debug)] #[derive(Error, Diagnostic, Debug)]
@ -774,7 +785,7 @@ println!("{:?}", report.with_source_code("About something or another or yet anot
### MSRV ### MSRV
This crate requires rustc 1.70.0 or later. This crate requires rustc 1.82.0 or later.
### Acknowledgements ### Acknowledgements

View File

@ -1 +1 @@
msrv = "1.70.0" msrv = "1.82.0"

View File

@ -150,7 +150,7 @@ impl Forward {
Self::#variant { #field_name, .. } => #field_name.#method_call, Self::#variant { #field_name, .. } => #field_name.#method_call,
}, },
Forward::Unnamed(index) => { Forward::Unnamed(index) => {
let underscores: Vec<_> = core::iter::repeat(quote! { _, }).take(*index).collect(); let underscores: Vec<_> = std::iter::repeat_n(quote! { _, }, *index).collect();
let unnamed = format_ident!("unnamed"); let unnamed = format_ident!("unnamed");
quote! { quote! {
Self::#variant ( #(#underscores)* #unnamed, .. ) => #unnamed.#method_call, Self::#variant ( #(#underscores)* #unnamed, .. ) => #unnamed.#method_call,

View File

@ -1,40 +1,6 @@
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens}; use quote::{format_ident, quote};
use syn::{ use syn::spanned::Spanned;
parse::{Parse, ParseStream},
spanned::Spanned,
};
pub(crate) enum MemberOrString {
Member(syn::Member),
String(syn::LitStr),
}
impl ToTokens for MemberOrString {
fn to_tokens(&self, tokens: &mut TokenStream) {
use MemberOrString::*;
match self {
Member(member) => member.to_tokens(tokens),
String(string) => string.to_tokens(tokens),
}
}
}
impl Parse for MemberOrString {
fn parse(input: ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(syn::Ident) || lookahead.peek(syn::LitInt) {
Ok(MemberOrString::Member(input.parse()?))
} else if lookahead.peek(syn::LitStr) {
Ok(MemberOrString::String(input.parse()?))
} else {
Err(syn::Error::new(
input.span(),
"Expected a string or a field reference.",
))
}
}
}
use crate::{ use crate::{
diagnostic::{DiagnosticConcreteArgs, DiagnosticDef}, diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},

View File

@ -172,11 +172,7 @@ pub trait ReportHandler: core::any::Any + Send + Sync {
/// } /// }
/// } /// }
/// ``` /// ```
fn debug( fn debug(&self, error: &dyn Diagnostic, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result;
&self,
error: &(dyn Diagnostic),
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result;
/// Override for the `Display` format /// Override for the `Display` format
fn display( fn display(

View File

@ -402,7 +402,7 @@ impl Default for MietteHandler {
} }
impl ReportHandler for MietteHandler { impl ReportHandler for MietteHandler {
fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result { fn debug(&self, diagnostic: &dyn Diagnostic, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() { if f.alternate() {
return fmt::Debug::fmt(diagnostic, f); return fmt::Debug::fmt(diagnostic, f);
} }

View File

@ -31,7 +31,7 @@ impl DebugReportHandler {
pub fn render_report( pub fn render_report(
&self, &self,
f: &mut fmt::Formatter<'_>, f: &mut fmt::Formatter<'_>,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
) -> fmt::Result { ) -> fmt::Result {
let mut diag = f.debug_struct("Diagnostic"); let mut diag = f.debug_struct("Diagnostic");
diag.field("message", &format!("{}", diagnostic)); diag.field("message", &format!("{}", diagnostic));
@ -61,7 +61,7 @@ impl DebugReportHandler {
} }
impl ReportHandler for DebugReportHandler { impl ReportHandler for DebugReportHandler {
fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result { fn debug(&self, diagnostic: &dyn Diagnostic, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() { if f.alternate() {
return fmt::Debug::fmt(diagnostic, f); return fmt::Debug::fmt(diagnostic, f);
} }

View File

@ -250,7 +250,7 @@ impl GraphicalReportHandler {
pub fn render_report( pub fn render_report(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
) -> fmt::Result { ) -> fmt::Result {
self.render_report_inner(f, diagnostic, diagnostic.source_code()) self.render_report_inner(f, diagnostic, diagnostic.source_code())
} }
@ -258,7 +258,7 @@ impl GraphicalReportHandler {
fn render_report_inner( fn render_report_inner(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
parent_src: Option<&dyn SourceCode>, parent_src: Option<&dyn SourceCode>,
) -> fmt::Result { ) -> fmt::Result {
let src = diagnostic.source_code().or(parent_src); let src = diagnostic.source_code().or(parent_src);
@ -289,7 +289,7 @@ impl GraphicalReportHandler {
fn render_header( fn render_header(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
is_nested: bool, is_nested: bool,
) -> fmt::Result { ) -> fmt::Result {
let severity_style = match diagnostic.severity() { let severity_style = match diagnostic.severity() {
@ -334,7 +334,7 @@ impl GraphicalReportHandler {
fn render_causes( fn render_causes(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
parent_src: Option<&dyn SourceCode>, parent_src: Option<&dyn SourceCode>,
) -> fmt::Result { ) -> fmt::Result {
let src = diagnostic.source_code().or(parent_src); let src = diagnostic.source_code().or(parent_src);
@ -432,7 +432,7 @@ impl GraphicalReportHandler {
Ok(()) Ok(())
} }
fn render_footer(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result { fn render_footer(&self, f: &mut impl fmt::Write, diagnostic: &dyn Diagnostic) -> fmt::Result {
if let Some(help) = diagnostic.help() { if let Some(help) = diagnostic.help() {
let width = self.termwidth.saturating_sub(2); let width = self.termwidth.saturating_sub(2);
let initial_indent = " help: ".style(self.theme.styles.help).to_string(); let initial_indent = " help: ".style(self.theme.styles.help).to_string();
@ -455,7 +455,7 @@ impl GraphicalReportHandler {
fn render_related( fn render_related(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
parent_src: Option<&dyn SourceCode>, parent_src: Option<&dyn SourceCode>,
) -> fmt::Result { ) -> fmt::Result {
let src = diagnostic.source_code().or(parent_src); let src = diagnostic.source_code().or(parent_src);
@ -543,7 +543,7 @@ impl GraphicalReportHandler {
fn render_snippets( fn render_snippets(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
opt_source: Option<&dyn SourceCode>, opt_source: Option<&dyn SourceCode>,
) -> fmt::Result { ) -> fmt::Result {
let source = match opt_source { let source = match opt_source {
@ -1369,7 +1369,7 @@ impl GraphicalReportHandler {
} }
impl ReportHandler for GraphicalReportHandler { impl ReportHandler for GraphicalReportHandler {
fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result { fn debug(&self, diagnostic: &dyn Diagnostic, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() { if f.alternate() {
return fmt::Debug::fmt(diagnostic, f); return fmt::Debug::fmt(diagnostic, f);
} }

View File

@ -60,7 +60,7 @@ impl JSONReportHandler {
pub fn render_report( pub fn render_report(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
) -> fmt::Result { ) -> fmt::Result {
self._render_report(f, diagnostic, None) self._render_report(f, diagnostic, None)
} }
@ -68,7 +68,7 @@ impl JSONReportHandler {
fn _render_report( fn _render_report(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
parent_src: Option<&dyn SourceCode>, parent_src: Option<&dyn SourceCode>,
) -> fmt::Result { ) -> fmt::Result {
write!(f, r#"{{"message": "{}","#, escape(&diagnostic.to_string()))?; write!(f, r#"{{"message": "{}","#, escape(&diagnostic.to_string()))?;
@ -154,7 +154,7 @@ impl JSONReportHandler {
fn render_snippets( fn render_snippets(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
source: &dyn SourceCode, source: &dyn SourceCode,
) -> fmt::Result { ) -> fmt::Result {
if let Some(mut labels) = diagnostic.labels() { if let Some(mut labels) = diagnostic.labels() {
@ -170,7 +170,7 @@ impl JSONReportHandler {
} }
impl ReportHandler for JSONReportHandler { impl ReportHandler for JSONReportHandler {
fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result { fn debug(&self, diagnostic: &dyn Diagnostic, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.render_report(f, diagnostic) self.render_report(f, diagnostic)
} }
} }

View File

@ -69,7 +69,7 @@ impl NarratableReportHandler {
pub fn render_report( pub fn render_report(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
) -> fmt::Result { ) -> fmt::Result {
self.render_header(f, diagnostic)?; self.render_header(f, diagnostic)?;
if self.with_cause_chain { if self.with_cause_chain {
@ -85,7 +85,7 @@ impl NarratableReportHandler {
Ok(()) Ok(())
} }
fn render_header(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result { fn render_header(&self, f: &mut impl fmt::Write, diagnostic: &dyn Diagnostic) -> fmt::Result {
writeln!(f, "{}", diagnostic)?; writeln!(f, "{}", diagnostic)?;
let severity = match diagnostic.severity() { let severity = match diagnostic.severity() {
Some(Severity::Error) | None => "error", Some(Severity::Error) | None => "error",
@ -96,7 +96,7 @@ impl NarratableReportHandler {
Ok(()) Ok(())
} }
fn render_causes(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result { fn render_causes(&self, f: &mut impl fmt::Write, diagnostic: &dyn Diagnostic) -> fmt::Result {
if let Some(cause_iter) = diagnostic if let Some(cause_iter) = diagnostic
.diagnostic_source() .diagnostic_source()
.map(DiagnosticChain::from_diagnostic) .map(DiagnosticChain::from_diagnostic)
@ -110,7 +110,7 @@ impl NarratableReportHandler {
Ok(()) Ok(())
} }
fn render_footer(&self, f: &mut impl fmt::Write, diagnostic: &(dyn Diagnostic)) -> fmt::Result { fn render_footer(&self, f: &mut impl fmt::Write, diagnostic: &dyn Diagnostic) -> fmt::Result {
if let Some(help) = diagnostic.help() { if let Some(help) = diagnostic.help() {
writeln!(f, "diagnostic help: {}", help)?; writeln!(f, "diagnostic help: {}", help)?;
} }
@ -126,7 +126,7 @@ impl NarratableReportHandler {
fn render_related( fn render_related(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
parent_src: Option<&dyn SourceCode>, parent_src: Option<&dyn SourceCode>,
) -> fmt::Result { ) -> fmt::Result {
if let Some(related) = diagnostic.related() { if let Some(related) = diagnostic.related() {
@ -152,7 +152,7 @@ impl NarratableReportHandler {
fn render_snippets( fn render_snippets(
&self, &self,
f: &mut impl fmt::Write, f: &mut impl fmt::Write,
diagnostic: &(dyn Diagnostic), diagnostic: &dyn Diagnostic,
source_code: Option<&dyn SourceCode>, source_code: Option<&dyn SourceCode>,
) -> fmt::Result { ) -> fmt::Result {
if let Some(source) = source_code { if let Some(source) = source_code {
@ -344,7 +344,7 @@ impl NarratableReportHandler {
} }
impl ReportHandler for NarratableReportHandler { impl ReportHandler for NarratableReportHandler {
fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result { fn debug(&self, diagnostic: &dyn Diagnostic, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() { if f.alternate() {
return fmt::Debug::fmt(diagnostic, f); return fmt::Debug::fmt(diagnostic, f);
} }

View File

@ -125,7 +125,7 @@ impl HighlighterState for SyntectHighlighterState<'_> {
line, line,
&self.highlighter, &self.highlighter,
) )
.map(|(style, str)| (convert_style(style, use_bg_color).style(str))) .map(|(style, str)| convert_style(style, use_bg_color).style(str))
.collect() .collect()
} else { } else {
vec![Style::default().style(line)] vec![Style::default().style(line)]

View File

@ -211,6 +211,17 @@
//! // Use `#[diagnostic(transparent)]` to wrap another [`Diagnostic`]. You won't see labels otherwise //! // Use `#[diagnostic(transparent)]` to wrap another [`Diagnostic`]. You won't see labels otherwise
//! #[diagnostic(transparent)] //! #[diagnostic(transparent)]
//! AnotherError(#[from] AnotherError), //! AnotherError(#[from] AnotherError),
//!
//! /// Forward the diagnostic to a particular field.
//! #[error("other error")]
//! #[diagnostic(forward(the_actual_diagnostic))]
//! EvenMoreData {
//! unrelated_field_1: String,
//! unrelated_field_2: usize,
//!
//! #[source]
//! the_actual_diagnostic: AnotherError,
//! }
//! } //! }
//! //!
//! #[derive(Error, Diagnostic, Debug)] //! #[derive(Error, Diagnostic, Debug)]
@ -775,7 +786,7 @@
//! //!
//! ## MSRV //! ## MSRV
//! //!
//! This crate requires rustc 1.70.0 or later. //! This crate requires rustc 1.82.0 or later.
//! //!
//! ## Acknowledgements //! ## Acknowledgements
//! //!

View File

@ -1,6 +1,5 @@
#![cfg(feature = "fancy-no-backtrace")] #![cfg(feature = "fancy-no-backtrace")]
use lazy_static::lazy_static;
use miette::{Diagnostic, MietteHandler, MietteHandlerOpts, ReportHandler, RgbColors}; use miette::{Diagnostic, MietteHandler, MietteHandlerOpts, ReportHandler, RgbColors};
use regex::Regex; use regex::Regex;
use std::ffi::OsString; use std::ffi::OsString;
@ -69,9 +68,7 @@ impl Drop for EnvVarGuard<'_> {
} }
} }
lazy_static! { static COLOR_ENV_VARS: Mutex<()> = Mutex::new(());
static ref COLOR_ENV_VARS: Mutex<()> = Mutex::new(());
}
/// Assert the color format used by a handler with different levels of terminal /// Assert the color format used by a handler with different levels of terminal
/// support. /// support.

View File

@ -376,6 +376,7 @@ enum NestedEnumError {
}, },
} }
#[cfg(feature = "fancy-no-backtrace")]
#[derive(Debug, miette::Diagnostic, thiserror::Error)] #[derive(Debug, miette::Diagnostic, thiserror::Error)]
#[error("I am the inner error")] #[error("I am the inner error")]
struct Case1Inner { struct Case1Inner {