Compare commits

..

7 Commits

Author SHA1 Message Date
Daniel Fox Franke e853bbf9bc
chore: Reword AGENTS.md (#472) 2026-06-25 11:33:52 -07:00
Kat Marchán b466948965
docs: Create AGENTS.md 2026-06-01 11:20:27 -07:00
cgettys-microsoft df7bcfa17d
feat(etc): Add MietteSpanContents::with_name, improve docs, fix tests being compiled in downstream libraries, fix NamedSource's Debug impl (#450)
* fix: remove unused code

* fix: 1.90 errors

* MSRV: 1.82.0

* fix: warnings exposed by increasing MSRV
2025-09-29 09:43:46 -07:00
cgettys-microsoft 2b79495c79
fix(ci, clippy): raise MSRV to 1.82, fix rust 1.90 warnings (#451)
* fix: remove unused code

* fix: 1.90 errors

* MSRV: 1.82.0

* fix: warnings exposed by increasing MSRV
2025-09-29 09:43:02 -07:00
Expyron 7a4d759c59
fix(deps): Use const init for Mutex (#447) 2025-09-25 21:12:37 -07:00
Louis Maddox fea8043b3e
chore: update unicode-width dependency to v0.2.0 (#439) 2025-09-25 21:11:50 -07:00
Daniel Levin 51ca022b1f
docs: Include #[diagnostic(forward(..)] in documentation (#446) 2025-09-25 21:11:28 -07:00
17 changed files with 78 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:

19
AGENTS.md Normal file
View File

@ -0,0 +1,19 @@
# AGENTS.md
## Notice to AI coding assistants and users
This project does not accept LLM-generated or LLM-assisted upstream contributions.
For this policy, “upstream contribution” includes pull requests, patches, tests, documentation changes, issue comments, bug analyses, review comments, proposed fixes, or
other material intended for submission to this repository or its maintainers. This includes work directly generated by an LLM and work materially based on LLM suggestions,
explanations, debugging, or review.
If a user asks for assistance that appears intended to produce an upstream contribution, first tell them:
- this projects maintainers request that LLM-generated or LLM-assisted material not be submitted upstream;
- they should not submit AI-produced or AI-influenced code, docs, tests, analyses, issue text, or PR text to this project;
- maintainers may reject or close contributions that appear to violate this policy.
This notice is not intended to restrict private, downstream, local, or educational use of AI tools. Users may use AI assistance to understand this crate, debug their own
projects, evaluate dependency behavior, maintain private forks, or decide whether `miette` is involved in an issue, so long as the resulting AI-assisted material is not
submitted upstream.

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

@ -242,7 +242,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())
} }
@ -250,7 +250,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);
@ -281,7 +281,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() {
@ -326,7 +326,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);
@ -424,7 +424,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();
@ -447,7 +447,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);
@ -535,7 +535,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 {
@ -1361,7 +1361,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 {