miette is a diagnostic library for Rust. It includes a series of traits/protocols that allow you to hook into its error reporting facilities, and even write your own error reports!

Overview

you run miette? You run her code like the software? Oh. Oh! Error code for coder! Error code for One Thousand Lines!

About

miette is a diagnostic library for Rust. It includes a series of traits/protocols that allow you to hook into its error reporting facilities, and even write your own error reports! It lets you define error types that can print out like this (or in any format you like!):

Hi! miette also includes a screen-reader-oriented diagnostic printer that's enabled in various situations, such as when you use NO_COLOR or CLICOLOR settings, or on CI. This behavior is also fully configurable and customizable. For example, this is what this particular diagnostic will look like when the narrated printer is enabled:
\
Error: Received some bad JSON from the source. Unable to parse.
Caused by: missing field `foo` at line 1 column 1700
\
Begin snippet for https://api.nuget.org/v3/registration5-gz-semver2/json.net/index.json starting
at line 1, column 1659
\
snippet line 1: gs

Table of Contents

Features

  • Generic [Diagnostic] protocol, compatible (and dependent on) std::error::Error.
  • Unique error codes on every [Diagnostic].
  • Custom links to get more details on error codes.
  • Super handy derive macro for defining diagnostic metadata.
  • anyhow/eyre-compatible error wrapper type, [Report], which can be returned from main.
  • Generic support for arbitrary [Source]s for snippet data, with default support for Strings included.

The miette crate also comes bundled with a default [ReportHandler] with the following features:

  • Fancy graphical diagnostic output, using ANSI/Unicode text
  • single- and multi-line highlighting support
  • Screen reader/braille support, gated on NO_COLOR, and other heuristics.
  • Fully customizable graphical theming (or overriding the printers entirely).
  • Cause chain printing
  • Turns diagnostic codes into links in supported terminals.

Installing

Using cargo-edit:

$ cargo add miette

Example

Result<()> { // You can use plain strings as a `Source`, or anything that implements // the one-method `Source` trait. let src = "source\n text\n here".to_string(); let len = src.len(); Err(MyBad { src: NamedSource::new("bad_file.rs", src), snip: (0, len).into(), bad_bit: (9, 4).into(), })?; Ok(()) } /* Now to get everything printed nicely, just return a Result<()> and you're all set! Note: You can swap out the default reporter for a custom one using `miette::set_reporter()` */ fn pretend_this_is_main() -> Result<()> { // kaboom~ this_fails()?; Ok(()) } ">
/*
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, SourceSpan};
use thiserror::Error;

#[derive(Error, Debug, Diagnostic)]
#[error("oops!")]
#[diagnostic(
    code(oops::my::bad),
    help("try doing it better next time?"),
)]
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.
    src: NamedSource,
    // Snippets and highlights can be included in the diagnostic!
    #[snippet(src, message("This is the part that broke"))]
    snip: SourceSpan,
    #[highlight(snip, label("This bit here"))]
    bad_bit: SourceSpan,
}

/*
Now let's define a function!

Use this Result type (or its expanded version) as the return type
throughout your app (but NOT your libraries! Those should always return concrete
types!).
*/
use miette::{Result, NamedSource};
fn this_fails() -> Result<()> {
    // You can use plain strings as a `Source`, or anything that implements
    // the one-method `Source` trait.
    let src = "source\n  text\n    here".to_string();
    let len = src.len();

    Err(MyBad {
        src: NamedSource::new("bad_file.rs", src),
        snip: (0, len).into(),
        bad_bit: (9, 4).into(),
    })?;

    Ok(())
}

/*
Now to get everything printed nicely, just return a Result<()>
and you're all set!

Note: You can swap out the default reporter for a custom one using `miette::set_reporter()`
*/
fn pretend_this_is_main() -> Result<()> {
    // kaboom~
    this_fails()?;

    Ok(())
}

And this is the output you'll get if you run this program:


Narratable printout:
\
Error: oops!
Diagnostic severity: error
\
Begin snippet for bad_file.rs starting at line 1, column 1
\
snippet line 1: source
snippet line 2:   text
highlight starting at line 2, column 3: these two lines
snippet line 3:     here
\
diagnostic help: try doing it better next time?
diagnostic error code: oops::my::bad

Using

... in libraries

miette is fully compatible with library usage. Consumers who don't know about, or don't want, miette features can safely use its error types as regular [std::error::Error].

We highly recommend using something like thiserror to define unique error types and error wrappers for your library.

While miette integrates smoothly with thiserror, it is not required. If you don't want to use the [Diagnostic] derive macro, you can implement the trait directly, just like with std::error::Error.

// lib/error.rs
use thiserror::Error;
use miette::Diagnostic;

#[derive(Error, Diagnostic, Debug)]
pub enum MyLibError {
    #[error(transparent)]
    #[diagnostic(code(my_lib::io_error))]
    IoError(#[from] std::io::Error),

    #[error("Oops it blew up")]
    #[diagnostic(code(my_lib::bad_code))]
    BadThingHappened,
}

Then, return this error type from all your fallible public APIs. It's a best practice to wrap any "external" error types in your error enum instead of using something like [Report] in a library.

... in application code

Application code tends to work a little differently than libraries. You don't always need or care to define dedicated error wrappers for errors coming from external libraries and tools.

For this situation, miette includes two tools: [Report] and [IntoDiagnostic]. They work in tandem to make it easy to convert regular std::error::Errors into [Diagnostic]s. Additionally, there's a [Result] type alias that you can use to be more terse.

When dealing with non-Diagnostic types, you'll want to .into_diagnostic() them:

// my_app/lib/my_internal_file.rs
use miette::{IntoDiagnostic, Result};
use semver::Version;

pub fn some_tool() -> Result {
    Ok("1.2.x".parse().into_diagnostic()?)
}

miette also includes an anyhow/eyre-style Context/WrapErr traits that you can import to add ad-hoc context messages to your Diagnostics, as well, though you'll still need to use .into_diagnostic() to make use of it:

// my_app/lib/my_internal_file.rs
use miette::{IntoDiagnostic, Result, WrapErr};
use semver::Version;

pub fn some_tool() -> Result {
    Ok("1.2.x".parse().into_diagnostic().wrap_err("Parsing this tool's semver version failed.")?)
}

... in main()

main() is just like any other part of your application-internal code. Use Result as your return value, and it will pretty-print your diagnostics automatically.

use miette::{Result, IntoDiagnostic};
use semver::Version;

fn pretend_this_is_main() -> Result<()> {
    let version: Version = "1.2.x".parse().into_diagnostic()?;
    println!("{}", version);
    Ok(())
}

... diagnostic code URLs

miette supports providing a URL for individual diagnostics. This URL will be displayed as an actual link in supported terminals, like so:

 Example showing the graphical report printer for miette pretty-printing
an error code. The code is underlined and followed by text saying to 'click
here'. A hover tooltip shows a full-fledged URL that can be Ctrl+Clicked to
open in a browser.
\
This feature is also available in the narratable printer. It will add a line after printing the error code showing a plain URL that you can visit.

To use this, you can add a url() sub-param to your #[diagnostic] attribute:

use miette::Diagnostic;
use thiserror::Error;

#[derive(Error, Diagnostic, Debug)]
#[error("kaboom")]
#[diagnostic(
    code(my_app::my_error),
    // You can do formatting!
    url("https://my_website.com/error_codes#{}", self.code().unwrap())
)]
struct MyErr;

Additionally, if you're developing a library and your error type is exported from your crate's top level, you can use a special url(docsrs) option instead of manually constructing the URL. This will automatically create a link to this diagnostic on docs.rs, so folks can just go straight to your (very high quality and detailed!) documentation on this diagnostic:

use miette::Diagnostic;
use thiserror::Error;

#[derive(Error, Diagnostic, Debug)]
#[diagnostic(
    code(my_app::my_error),
    // Will link users to https://docs.rs/my_crate/0.0.0/my_crate/struct.MyErr.html
    url(docsrs)
)]
#[error("kaboom")]
struct MyErr;

... snippets

Along with its general error handling and reporting features, miette also includes facilities for adding error spans and annotations/highlights to your output. This can be very useful when an error is syntax-related, but you can even use it to print out sections of your own source code!

To achieve this, miette defines its own lightweight [SourceSpan] type. This is a basic byte-offset and length into an associated [Source] and, along with the latter, gives miette all the information it needs to pretty-print some snippets!

The easiest way to define errors like this is to use the derive(Diagnostic) macro:

use miette::{Diagnostic, SourceSpan};
use thiserror::Error;

#[derive(Diagnostic, Debug, Error)]
#[error("oops")]
#[diagnostic(code(my_lib::random_error))]
pub struct MyErrorType {
    // The `Source` that miette will use.
    src: String,

    // A snippet that points to `src`, our `Source`.
    #[snippet(
        src,
        message("This is the snippet")
    )]
    snip: SourceSpan,

    // A highlight for the `snip` snippet we defined above. This will
    // underline/mark the specific code inside the larger snippet context.
    #[highlight(snip, label("This is the highlight"))]
    err_span: SourceSpan,

    // You can add as many snippets as you want against the same Source.
    // They'll be rendered sequentially.
    #[snippet(
        src,
        message("This is a warning")
    )]
    snip2: SourceSpan,
}

Acknowledgements

miette was not developed in a void. It owes enormous credit to various other projects and their authors:

  • anyhow and color-eyre: these two enormously influential error handling libraries have pushed forward the experience of application-level error handling and error reporting. miette's Report type is an attempt at a very very rough version of their Report types.
  • thiserror for setting the standard for library-level error definitions, and for being the inspiration behind miette's derive macro.
  • rustc and @estebank for their state-of-the-art work in compiler diagnostics.
  • ariadne for pushing forward how pretty these diagnostics can really look!

License

miette is released to the Rust community under the Apache license 2.0.

It also includes code taken from eyre, and some from thiserror, also under the Apache License. Some code is taken from ariadne, which is MIT licensed.

Comments
  • split off DiagnosticReport + reporters into their own library?

    split off DiagnosticReport + reporters into their own library?

    No rush, I think, because the intention is very much that anyone using miette will also probably be using the reporter, but I'm hoping people write their own bespoke reporters against the "protocol".

    ...maybe that means we need miette-protocol, and miette is the Big Chonker library? That would let us do this refactor without being semver-breaking. πŸ€”

    opened by zkat 17
  • severity(warning) should probably not use an `Error:` introducer

    severity(warning) should probably not use an `Error:` introducer

    Example:

    use miette::{Diagnostic, NamedSource, Result, SourceSpan};
    use thiserror::Error;
    
    #[derive(Error, Debug, Diagnostic)]
    #[error("oops!")]
    #[diagnostic(
        code(oops::my::bad),
        url(docsrs),
        help("try doing it better next time?"),
        severity(warning)
    )]
    struct MyBad {
        #[source_code]
        src: NamedSource,
        #[label("This bit here")]
        bad_bit: SourceSpan,
    }
    
    fn main() -> Result<()> {
        let src = "source\n  text\n    here".to_string();
    
        Err(MyBad {
            src: NamedSource::new("bad_file.rs", src),
            bad_bit: (9, 4).into(),
        })?;
    
        Ok(())
    }
    
    Error: oops::my::bad (link)
    
      ⚠ oops!
       ╭─[bad_file.rs:1:1]
     1 β”‚ source
     2 β”‚   text
       Β·   ──┬─
       Β·     ╰── This bit here
     3 β”‚     here
       ╰────
      help: try doing it better next time?
    

    image

    Similarly with severity(advice).

    A more realistic example with #[related]:

    use miette::{Diagnostic, Result, SourceSpan};
    use std::{error::Error, fmt::Display};
    use thiserror::Error;
    
    #[derive(Error, Debug, Diagnostic)]
    #[diagnostic(code(D0000), severity(error))]
    #[error("I won't allow this")]
    struct SourceError {
        #[label]
        span: SourceSpan,
    }
    
    #[derive(Error, Debug, Diagnostic)]
    #[diagnostic(code(D4000), severity(warning))]
    #[error("I don't like this")]
    struct SourceWarning {
        #[label]
        span: SourceSpan,
    }
    
    #[derive(Error, Debug, Diagnostic)]
    #[diagnostic(code(D8000), severity(advice))]
    #[error("This could be better")]
    struct SourceAdvice {
        #[label]
        span: SourceSpan,
    }
    
    #[derive(Debug)]
    struct DynDiagnostic {
        inner: Box<dyn Diagnostic + Send + Sync + 'static>,
    }
    
    impl Display for DynDiagnostic {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            self.inner.fmt(f)
        }
    }
    
    impl Error for DynDiagnostic {
        fn source(&self) -> Option<&(dyn Error + 'static)> {
            self.inner.source()
        }
    }
    
    impl Diagnostic for DynDiagnostic {
        fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
            self.inner.code()
        }
    
        fn severity(&self) -> Option<miette::Severity> {
            self.inner.severity()
        }
    
        fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
            self.inner.help()
        }
    
        fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
            self.inner.url()
        }
    
        fn source_code(&self) -> Option<&dyn miette::SourceCode> {
            self.inner.source_code()
        }
    
        fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
            self.inner.labels()
        }
    
        fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
            self.inner.related()
        }
    }
    
    impl DynDiagnostic {
        fn new(diagnostic: impl Diagnostic + Send + Sync + 'static) -> Self {
            DynDiagnostic {
                inner: diagnostic.into(),
            }
        }
    }
    
    #[derive(Error, Debug, Diagnostic)]
    #[diagnostic(severity(error))]
    #[error("compilation failed")]
    struct SourceDiagnostics {
        #[source_code]
        src: String,
        #[related]
        diagnostics: Vec<DynDiagnostic>,
    }
    
    fn main() -> Result<()> {
        let src = "\
    this is an error
    this is a warning
    this is an advice
    ";
    
        let error = SourceError {
            span: (11..16).into(),
        };
        let warning = SourceWarning {
            span: (27..34).into(),
        };
        let advice = SourceAdvice {
            span: (46..52).into(),
        };
    
        let diagnostics = SourceDiagnostics {
            src: src.into(),
            diagnostics: vec![
                DynDiagnostic::new(error),
                DynDiagnostic::new(warning),
                DynDiagnostic::new(advice),
            ],
        };
    
        Err(diagnostics)?;
        Ok(())
    }
    
    Error:
      Γ— compilation failed
    
    Error: D0000
    
      Γ— I won't allow this
       ╭─[1:1]
     1 β”‚ this is an error
       Β·            ─────
     2 β”‚ this is a warning
       ╰────
    Error: D4000
    
      ⚠ I don't like this
       ╭─[1:1]
     1 β”‚ this is an error
     2 β”‚ this is a warning
       Β·           ───────
     3 β”‚ this is an advice
       ╰────
    Error: D8000
    
      ☞ This could be better
       ╭─[2:1]
     2 β”‚ this is a warning
     3 β”‚ this is an advice
       Β·            ──────
       ╰────
    

    image

    enhancement help wanted 
    opened by CAD97 10
  • Add `#[diagnostic(forward(field_name), code(...))]`

    Add `#[diagnostic(forward(field_name), code(...))]`

    This PR solves a problem I imagined. Not sure if it's real or not yet. I made a demo though: https://gist.github.com/cormacrelf/09ef573df0f5b41c9fa252f5866336ba

    There are bugfix components of this that unquestionably need to be merged, but they were done on top of the other work so I'd have to redo it basically.

    As described in #36:

    The forwarding branch, in addition to that, adds a forward(field_name) arg that must be used with a code(...) like any other arg. When you supply it, it makes any unspecified things forward their implementation to the specified field. It works with named and unnamed (forward(0)) structs and enum variants. The test suite shows what you can do with it -- the ForwardsTo struct is used for the snippets, all the other bits of info can be overridden.

    The question before we land this PR is a bikeshed, whether these two different argument names for arguably the same functionality are a good idea or not. Which is preferable of these?

    • Only diagnostic(transparent)
    • diagnostic(transparent), diagnostic(code(...), forward(field_name)) as described
    • diagnostic(transparent), diagnostic(code(...), transparent(field_name))
    • diagnostic(transparent), diagnostic(code(...), default(field_name). I kinda like this but I only just thought of it.
    opened by cormacrelf 10
  • Words on the first line being dropped?

    Words on the first line being dropped?

    Hey,

    First up, this library is dope. Love your work. πŸš€

    I'm having one small issue though - if I have a SourceSpan that points somewhere in the first line of some source code, that first line seems to get chopped.

    Here's a test to reproduce:

    #[cfg(test)]
    mod miette_test {
        use miette::{
            Diagnostic, GraphicalReportHandler, GraphicalTheme, SourceSpan, ThemeCharacters,
            ThemeStyles,
        };
        use thiserror::Error;
    
        #[derive(Error, Debug, Diagnostic)]
        #[error("some error")]
        #[diagnostic(help("where did the word 'imagine' go!?"))]
        struct SomeError {
            #[source_code]
            some_code: String,
            #[label("'imagine' should come before this")]
            some_span: SourceSpan,
        }
    
        #[test]
        fn whytho() {
            let mut rendered = String::new();
            let diagnostic = SomeError {
                some_code: "imagine this is some code\n\nyou're seeing all of this line".to_owned(),
                some_span: (8, 0).into(),
            };
    
            GraphicalReportHandler::new()
                .with_theme(GraphicalTheme {
                    characters: ThemeCharacters::ascii(),
                    styles: ThemeStyles::none(),
                })
                .with_context_lines(3)
                .render_report(&mut rendered, &diagnostic)
                .unwrap();
            assert_eq!(
                &rendered,
                r#"
      x some error
       ,-[1:1]
     1 | this is some code
       : ^
       : `-- 'imagine' should come before this
     2 | 
     3 | you're seeing all of this line
       `----
      help: where did the word 'imagine' go!?
    "#
            );
        }
    }
    
    bug help wanted good first issue Hacktoberfest 
    opened by jmackie 9
  • fix(graphical): Fix panic with span extending past end of line (#215)

    fix(graphical): Fix panic with span extending past end of line (#215)

    This also changes the behavior with spans including a CRLF line-ending. Before the panic bug was introduced, these were rendered with the CRLF being two visual columns wide. Now, any span extending past the EOL is treated as including one extra visual column. See https://github.com/zkat/miette/issues/215#issuecomment-1301560478 for an example of this.

    This PR notably does not fix the rendering bug with spans including the EOF. These were rendered incorrectly before the panic bug was introduced. @Boshen mentioned that they were seeing a panic with EOF in #215, but I haven't been able to reproduce that. We may want to wait for a response from them before merging this, since it seems like I'm missing something here.

    opened by Benjamin-L 7
  • Add caused_by to Diagnostic

    Add caused_by to Diagnostic

    Hi!

    Currently, miette does not support error causes which contain a Diagnostic.

    This draft tries to change that. It is related to #164 , as I worked with @TheNeikos on implementing this.

    Tell me what you think! :heart:


    Please note that I will rebase this PR until we all agree on a way forward!

    opened by matthiasbeyer 7
  • Add anyhow/eyre interop example

    Add anyhow/eyre interop example

    The docs state that Report is an "anyhow/eyre-compatible error wrapper type" I couldn't find any example showing how this works.

    I expected to be able to call into_diagnostic() on anyhow::Error after reading this but this doesn't work.

    An example would be highly appreciated – maybe add one for eyre too, while at it. Cheers!

    documentation help wanted good first issue 
    opened by virtualritz 7
  • Indentation with tabs throws off labels

    Indentation with tabs throws off labels

    (Sorry to not provide a proper repro. I’ll provide one later if you want, just wanted to get the issue opened before I forget).

    If I have code indented with tabs, it seems that something goes wrong with the labelled spans:

    function lol(): void {
    	const x: i32 = 1;
    };
    
    Screenshot 2021-10-10 at 14 35 29

    If I instead indent the code with spaces, it looks correct:

    Screenshot 2021-10-10 at 14 35 35

    I’m assuming that this might be due to terminal configuration how to display tabs?

    bug help wanted good first issue 
    opened by surma 7
  • Derive macro: single field for multiple snippets

    Derive macro: single field for multiple snippets

    Allowing dynamic list of spans to provide highlights you can be good for using miette to wrap tools like TypeScript (tsc).

    Looking at the source code, maybe Vec<SourceSpan> might not cut it, but introducing a new LabelledSourceSpan and allowing everything that is Into<Vec<LabelledSourceSpan>> could also make sense.

    What do you think?

    enhancement help wanted good first issue 
    opened by Schniz 7
  • Add `#[diagnostic(transparent)]`

    Add `#[diagnostic(transparent)]`

    Fixes #16.

    I struggled hard naming some of the syntax structs/enums so rename them if you can think of something better. I also didn't implement it for single field structs, mainly because I couldn't be bothered. The only reason I can imagine that being useful is wrapping a foreign diagnostic type, and adding impls for std traits like PartialEq, etc. If anyone needs that it wouldn't be hard.

    opened by cormacrelf 7
  • Panic when span is on `\n` in v5.4.1

    Panic when span is on `\n` in v5.4.1

    Input text: "/\n" Input span: 0..2

    thread '<unnamed>' panicked at 'byte index 2 is out of bounds of /', /Users/boshenchen/.cargo/registry/src/github.com-1ecc6299db9ec823/miette-5.4.1/src/handlers/graphical.rs:624:21

    https://github.com/zkat/miette/blob/3e25fd5b86324e16b33dd7e9192faa8015ead562/src/handlers/graphical.rs#L624

    cc @Benjamin-L

    opened by Boshen 6
  • Switching out `atty`?

    Switching out `atty`?

    Would you accept a PR to switch out atty for something else? This would also affect supports_unicode and supports_hyperlinks.

    There’s been an audit failure on atty for a while now which requires explicit suppression if you’re using something like cargo-audit or cargo-deny.

    As to replacements, is-terminal seems to have been picked up by several projects such as clap.

    enhancement help wanted good first issue 
    opened by Porges 2
  • Graphical handler panics when span endpoints are not aligned to char boundaries

    Graphical handler panics when span endpoints are not aligned to char boundaries

    This is another regression introduced by #202.

    Steps to reproduce

    Source: source\n πŸ‘ΌπŸΌtext\n here Span: (10, 5)

    Result:

    thread 'single_line_with_wide_char_unaligned_span_start' panicked at 'byte index 3 is not a char boundary; it is inside 'πŸ‘Ό' (bytes 2..6) of `  πŸ‘ΌπŸΌtext`', library/core/src/str/mod.rs:127:5
    

    Expected Behavior

    When the span boundaries are inside a char, the rendered highlight should extend to include that char instead of panicking.

    This is almost the same as the current behavior of the narratable report handler. The current narratable report handler behaves differently when the start of the span is not char-aligned. In this case, the reported span does not include the char that the span start is inside. I think it makes more sense for the start of the span to be extended backwards, and and then end to be extended forwards. This way, whenever a span endpoint lies inside a char, that char is always included.

    Unit tests for this
    #[test]
    fn single_line_with_wide_char_unaligned_span_start() -> Result<(), MietteError> {
      #[derive(Debug, Diagnostic, Error)]
      #[error("oops!")]
      #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
      struct MyBad {
          #[source_code]
          src: NamedSource,
          #[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),
          highlight: (10, 5).into(),
      };
      let out = fmt_report(err.into());
      println!("Error: {}", out);
      let expected = r#"oops::my::bad
    
    Γ— oops!
     ╭─[bad_file.rs:1:1]
    1 β”‚ source
    2 β”‚   πŸ‘ΌπŸΌtext
     Β·   ────┬───
     Β·       ╰── this bit here
    3 β”‚     here
     ╰────
    help: try doing it better next time?
    "#
      .trim_start()
      .to_string();
      assert_eq!(expected, out);
      Ok(())
    }
    
    #[test]
    fn single_line_with_wide_char_unaligned_span_end() -> Result<(), MietteError> {
      #[derive(Debug, Diagnostic, Error)]
      #[error("oops!")]
      #[diagnostic(code(oops::my::bad), help("try doing it better next time?"))]
      struct MyBad {
          #[source_code]
          src: NamedSource,
          #[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),
          highlight: (9, 6).into(),
      };
      let out = fmt_report(err.into());
      println!("Error: {}", out);
      let expected = r#"oops::my::bad
    
    Γ— oops!
     ╭─[bad_file.rs:1:1]
    1 β”‚ source
    2 β”‚   text πŸ‘ΌπŸΌ
     Β·   ───┬───
     Β·      ╰── this bit here
    3 β”‚     here
     ╰────
    help: try doing it better next time?
    "#
      .trim_start()
      .to_string();
      assert_eq!(expected, out);
      Ok(())
    }
    
    bug 
    opened by Benjamin-L 1
  • Optional impl From<OldMiette> for NewMiette

    Optional impl From for NewMiette

    This is an issue to gauge interest, I'm happy to implement and PR.

    Miette has not feared to break API and release new majors swiftly. In many ways, this is great! But it means that some libraries are stuck with e.g. miette 4 because they haven't needed an update, and updating the miette dep would anyway be a breaking change if they expose a miette return type.

    I propose a feature-gated pattern where miette N gets a dependency on miette N-1, and a way to upgrade errors to the newer compatible type. This would be recommended for use only by end-user applications with this specific need.

    I don't yet have details on how the implementation would work, but it feels possible.

    What do you think?

    opened by passcod 4
  • Narratable report handler produces bad output with labels including EOL or EOF

    Narratable report handler produces bad output with labels including EOL or EOF

    The graphical report handler supports spans that include the EOL (or, at least, it will once #215 is fixed). These are rendered like this:

    Source: source\ntext\n here Span: (7, 5)

    Error: oops::my::bad
    
      Γ— oops!
       ╭─[bad_file.rs:1:1]
     1 β”‚ source
     2 β”‚ text
       Β· ──┬──
       Β·   ╰── this bit here
     3 β”‚   here
       ╰────
      help: try doing it better next time?
    

    Passed the same input, the narratable handler produces:

    Error: oops!
        Diagnostic severity: error
    Begin snippet for bad_file.rs starting at line 1, column 1
    
    snippet line 1: source
    snippet line 2: text
        label starting at line 2, column 1: this bit here
    snippet line 3:   here
        label ending at line 3, column 0: this bit here
    diagnostic help: try doing it better next time?
    diagnostic code: oops::my::bad
    

    When the span extends past EOF, the result is:

    Source: source\ntext Span: (7, 5)

    Error: oops!
        Diagnostic severity: error
    Begin snippet for bad_file.rs starting at line 1, column 1
    
    snippet line 1: source
    snippet line 2: text
        label starting at line 2, column 1: this bit here
    diagnostic help: try doing it better next time?
    diagnostic code: oops::my::bad
    

    With a trailing newline on the source input:

    Source: source\ntext\n Span: (7, 5)

    Error: oops!
        Diagnostic severity: error
    Begin snippet for bad_file.rs starting at line 1, column 1
    
    snippet line 1: source
    snippet line 2: text
        label at line 2, columns 1 to 4: this bit here
    diagnostic help: try doing it better next time?
    diagnostic code: oops::my::bad
    

    All three of these cases should probably be rendered as label at line 2, columns 1 to 5: this bit here. When solving this, we should consider the edge cases from https://github.com/zkat/miette/issues/215#issuecomment-1301560478 as well.

    opened by Benjamin-L 0
  • miette fails silently when span is wrong

    miette fails silently when span is wrong

    OK I now understand why I just get an error message without the full beautiful report:

    Screen Shot 2022-10-30 at 7 50 38 PM

    it's because my span is wrong. It would have been nice if an error would have been thrown so that it's easier to understand why no report is displayed : o

    opened by mimoo 2
Releases(v5.5.0)
  • v5.5.0(Nov 24, 2022)

  • v5.4.1(Oct 28, 2022)

  • v5.4.0(Oct 28, 2022)

  • v5.3.1(Oct 28, 2022)

  • v5.3.0(Oct 28, 2022)

  • v5.2.0(Oct 28, 2022)

  • v5.1.1(Jul 9, 2022)

  • v5.1.0(Jun 25, 2022)

  • v5.0.0(Jun 25, 2022)

    Breaking Changes

    • theme: restructure automatic color selection (#177) (1816b06a)
      • The default theme now prefers ANSI colors, even if RGB is supported
      • MietteHandlerOpts::ansi_colors is removed
      • MietteHandlerOpts::rgb_color now takes an enum that controls the color format used when color support is enabled, and has no effect otherwise.

    Bug Fixes

    • json: Don't escape single-quotes, that's not valid json (#180) (b193d3c0)
    Source code(tar.gz)
    Source code(zip)
  • v4.7.1(May 15, 2022)

  • v4.7.0(May 5, 2022)

  • v4.6.0(May 5, 2022)

  • v4.5.0(Apr 18, 2022)

    Features

    • spans: make SourceSpan implement Copy (#151) (5e54b29a)
    • help: update macro to allow optional help text (#152) (45093c2f)
    • labels: allow optional labels in derive macro (#153) (23ee3642)
    • help: allow non-option values in #[help] fields (ea55f458)
    • label: use macro magic instead of optional flag for optional labels (9da62cd0)

    Bug Fixes

    • theme: set correct field in MietteHandlerOpts::ansi_colors (#150) (97197601)
    Source code(tar.gz)
    Source code(zip)
  • v4.4.0(Apr 18, 2022)

  • v4.3.0(Apr 18, 2022)

    Features

    • reporter: Allow GraphicalReportHandler to disable url display (#137) (b6a6cc9e)

    Bug Fixes

    • colors: handler_opts.color(false) should disable color (#133) (209275d4)
    • handler: Apply MietteHandlerOpts::graphical_theme (#138) (70e84f9a)

    Documentation

    • readme: Fix a couple links (#141) (126ffc58)

    Miscellaneous Tasks

    • deps: Update textwrap to 0.15.0 (#143) (2d0054b3)
    Source code(tar.gz)
    Source code(zip)
  • v4.2.1(Apr 18, 2022)

  • v4.2.0(Apr 18, 2022)

  • v4.1.0(Apr 18, 2022)

  • v4.0.1(Apr 18, 2022)

  • v4.0.0(Apr 18, 2022)

    Breaking Changes

    • colors: treat no-color mode as no-color instead of narratable (#94) (9dcce5f1)
      • BREAKING CHANGE: NO_COLOR no longer triggers the narrated handler. Use NO_GRAPHICS instead.
    • derive: Make derive macro diagnostic attribute more flexible. (#115) (5b8b5478)
      • BREAKING CHANGE: diagnostic attribute duplication will now error.

    Features

    • Report: adds .context() method to the Report (#109) (2649fd27)

    Bug Fixes

    • handlers: Fix label position (#107) (f158f4e3)
    Source code(tar.gz)
    Source code(zip)
  • v3.3.0(Apr 18, 2022)

  • v3.2.0(Apr 18, 2022)

  • v3.1.0(Oct 1, 2021)

  • v3.0.1(Sep 26, 2021)

  • v3.0.0(Sep 23, 2021)

    It's here! Have fun!

    It's a pretty significant change, so if you were using miette's snippet support previously, you'll need to update your code.

    Bug Fixes

    • report: miscellaneous, hacky tweaks to graphical rendering (80036781)
    • protocol: implement source/cause for Box (c3505fac)
    • derive: Code is no longer required (92a31509)
    • graphical: stop rendering red vbars before the last item (e2e4027f)
    • graphical: fix coalescing adjacent things when they cross boundaries (18e0ed77)
    • context: get labels/snippets working when using .context() (41cb710a)
    • api: put panic handler properly behind a flag (55ca8e0b)
    • deps: We do not use ci_info directly anymore (8d1170e2)
    • graphical: Fix off-by-one span_applies calculation (#70) (a6902042)
    • theme: remove code styling (ce0dea54)
    • graphical: render URLs even without a code (77c5899b)
    • deps: remove dep on itertools (612967d3)

    Features

    • report: make a single big MietteHandler that can switch modes (4c2463f9)
      • BREAKING CHANGE: linkification option method on GraphicalReportHandler has been changed to .with_links(bool)
    • deps: move fancy reporter (and its deps) to a feature (247e8f8b)
      • BREAKING CHANGE: The default fancy reporter is no longer available unless you enable the "fancy" feature. This also means you will not be pulling in a bunch of deps if you are using miette for a library
    • footer: add footer support to graphical and narrated (93374173)
    • theme: rename some theme items for clarity (c5c0576e)
      • BREAKING CHANGE: These were part of the public API, so if you were using theming, this might have broken for you
    • theme: more styling changes (2c437403)
    • report: add debug report as default, instead of narrated one (9841d6fd)
    • labels: replace snippet stuff with simpler labels (#62) (f87b158b)
    • protocol: Make SourceCode Send+Sync (9aa8ff0d)
    • handlers: Update graphical handler to use new label protocol (#66) (4bb9d121)
    • report: nicer, non-overlapping same-line highlights (1a0f359e)
    • panic: Add basic panic handler and installation function (c6daee7b)
    • panic: add backtrace support to panic handler and move set_panic_hook into fancy features (858ac169)
    • graphical: simplify graphical header and remove a dep (6c648463)
    • related: Add related diagnostics (#68) (8e11baab)
    • graphical: compact graphical display a bit (db637a36)
    • graphical: compact even more (72c0bb9e)
    • graphical: add theming customization for linums (717f8e3d)
    • handler: context lines config support (b33084bd)
    • narrated: updated narrated handler (fbf6664e)
    • narrated: global footer and related diagnostics support (3213fa61)
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta.0(Sep 23, 2021)

    Time to get ready for release!

    Bug Fixes

    • graphical: stop rendering red vbars before the last item (dc2635e1)
    • graphical: fix coalescing adjacent things when they cross boundaries (491ce7c0)
    • context: get labels/snippets working when using .context() (e0296578)

    Features

    • report: nicer, non-overlapping same-line highlights (338c885a)
    • panic: Add basic panic handler and installation function (11a708a2)
    • panic: add backtrace support to panic handler and move set_panic_hook into fancy features (183ecb9b)
    • graphical: simplify graphical header and remove a dep (9f36a4c2)
    • related: Add related diagnostics (#68) (25e434a2)
    • graphical: compact graphical display a bit (9d07dc5a)
    • graphical: compact even more (712e75fd)
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-alpha.0(Sep 23, 2021)

    This is the first WIP alpha release of miette 3.0!

    It's a MAJOR rewrite of the entire snippet definition and rendering system, and you can expect even more changes before 3.0 goes live.

    In the meantime, there's this. :)

    Bug Fixes

    • report: miscellaneous, hacky tweaks to graphical rendering (8029f9c6)
    • protocol: implement source/cause for Box (3e8a27e2)
    • derive: Code is no longer required (8a0f71e6)

    Features

    • report: make a single big MietteHandler that can switch modes (3d74a500)
      • BREAKING CHANGE: linkification option method on GraphicalReportHandler has been changed to .with_links(bool)
    • deps: move fancy reporter (and its deps) to a feature (bc495e6e)
      • BREAKING CHANGE: The default fancy reporter is no longer available unless you enable the "fancy" feature. This also means you will not be pulling in a bunch of deps if you are using miette for a library
    • footer: add footer support to graphical and narrated (412436cd)
    • theme: rename some theme items for clarity (12a9235b)
      • BREAKING CHANGE: These were part of the public API, so if you were using theming, this might have broken for you
    • theme: more styling changes (9901030e)
    • report: add debug report as default, instead of narrated one (eb1b7222)
    • labels: replace snippet stuff with simpler labels (#62) (0ef2853f)
    • protocol: Make SourceCode Send+Sync (eb485658)
    • handlers: Update graphical handler to use new label protocol (#66) (6cd44a86)
    Source code(tar.gz)
    Source code(zip)
  • v2.2.0(Sep 14, 2021)

    So it turns out 3.0.0 is already under way, if you didn't already hear!

    It's going to be an exciting release, but we'll still be putting out bugfixes and (backwards-compatible) features in the 2.x line until that's ready.

    And there's definitely stuff in this one to be excited about! Not least of all the ability to forward diagnostic metadata when wrapping other Diagnostics. Huge thanks to @cormacrelf for that one!

    We've also got some nice improvements to reporter formatting that should make output look at least a little nicer--most notably, we now wrap messages and footers along the appropriate column so formatting keeps looking good even when you use newlines!

    Finally, huge thanks to @icewind1991 for fixing a really weird-looking bug caused by an off-by-one error. Oopsies πŸ˜…

    Features

    • report: wrap multiline messages to keep formatting (f482dcec)
    • report: take terminal width into account for wrapping text (bc725324)
    • report: make header line as wide as terminal (eaebde92)
    • derive: Add #[diagnostic(forward(field_name), code(...))] (#41) (2fa5551c)

    Bug Fixes

    • report: get rid of the weird arrow thing. it does not look good (1ba3f2f5)
    • report: fix wrapping for header and add wrapping for footer (eb07d5bd)
    • report: Fix end of previous line wrongly being included in highlight (#52) (d994add9)
    Source code(tar.gz)
    Source code(zip)
  • v2.1.2(Sep 10, 2021)

    So it turns out I forgot to make snippets and other stuff forward through when you use .context() &co. This should be fixed now πŸ˜…

    Bug Fixes

    • context: pass on diagnostic metadata when wrapping with Report (e4fdac38)
    Source code(tar.gz)
    Source code(zip)
  • v2.1.1(Sep 9, 2021)

    This is a small release with a handful of quality of life improvements (and a small bugfix).

    Features

    • printer: use uparrow for empty highlights and fix 0-offset display bug (824cd8be)
    • derive: make #[diagnostic] optional for enums, too (ffe1b558)
    Source code(tar.gz)
    Source code(zip)
Owner
Kat MarchΓ‘n
rustacean πŸ¦€, @NuGet team 🍫. Formerly @npmjs 😩
Kat MarchΓ‘n
Flexcord! A custom Discord client to allow you to do what you want!

Disclaimer Flexcord is NO WHERE near done. Flexcord What is it? Flexcord is a Discord client that flexes for your needs, it allows you to do exactly w

null 2 Dec 5, 2022
tracing - a framework for instrumenting Rust programs to collect structured, event-based diagnostic information

tracing-appender Writers for logging events and spans Documentation | Chat Overview tracing is a framework for instrumenting Rust programs to collect

Cris Liao 1 Mar 9, 2022
Make the github cli even better with fuzzy finding

github-repo-clone (grc) Github Repo Clone is a command line utility written in rust that leverages the power of fuzzy finding with the github cli Usag

Jared Moulton 2 Jul 9, 2022
Rust crate for creating filters with DirectX shaders. Includes Scale, Color conversion using DirectX api.

DxFilter Scale and ColorConversion done with DirectX filters. You can also create your own filters with the provided api. Crate contains various tools

null 4 Aug 13, 2022
A git hook to manage derivative files automatically.

git-derivative A git hook to manage derivative files automatically. For example if you checked out to a branch with different yarn.lock, git-derivativ

Sung Jeon 3 Oct 30, 2022
A git prepare-commit-msg hook for authoring commit messages with GPT-3.

gptcommit A git prepare-commit-msg hook for authoring commit messages with GPT-3. With this tool, you can easily generate clear, comprehensive and des

Roger Zurawicki 3 Jan 19, 2023
A fetcher hook for the Plato document reader that syncs an e-reader with an OPDS catalogue.

plato-opds A fetcher hook for the Plato document reader that syncs an e-reader with an OPDS catalogue. Motivation I wanted to be able to sync my e-rea

null 11 Nov 8, 2023
Annotation to easily define ad-hoc / one-shot extension traits

Annotation to easily define ad-hoc / one-shot extension traits

Daniel Henry-Mantilla 2 Apr 19, 2022
Async `TryFrom/TryInto` traits

async-convert Async TryFrom/TryInto traits API Docs | Releases | Contributing Installation $ cargo add async-convert Safety This crate uses #![deny(un

Yosh 4 Mar 4, 2022
Various extention traits for providing asynchronous higher-order functions

async-hofs Various extention traits for providing asynchronous higher-order functions. // This won't make any name conflicts since all imports inside

γ‹γ‚γˆγ‚‚γ‚“ 5 Jun 28, 2022
Stdto provides a set of functional traits for conversion between various data representations.

Stdto stdto provides a set of functional traits for conversion between various data representations. | Examples | Docs | Latest Note | stdto = "0.13.0

Doha Lee 5 Dec 21, 2022
Repo for Monaco, a DCA engine for Solana. Built on Solend and lending protocols (Jet, Solend, Port, etc...)

Monaco Monaco is a DCA protocol for solana built on top of Serum and compatible with any program that implements or extends the instruction interface

Rohan Kapur 19 Apr 13, 2022
Async implementation of the StatusNotifierItem and DbusMenu protocols for building system trays.

System Tray An async implementation of the StatusNotifierItem and DbusMenu protocols for building system trays. Requires Tokio. Example use system_tra

Jake Stanger 3 Mar 29, 2024
Error context library with support for type-erased sources and backtraces, targeting full support of all features on stable Rust

Error context library with support for type-erased sources and backtraces, targeting full support of all features on stable Rust, and with an eye towards serializing runtime errors using serde.

Findora Foundation 1 Feb 12, 2022
Rust drivers for the SIM7000 series of modems

sim7000 This crate provides drivers for the SIM7000 series of chips. The current code implements enough commands to bring up a TCP connection and run

The Techno Creatives 11 Dec 29, 2022
Bongo Copy Cat wants to be involved in everything you do but instead just imitates you hitting your keyboard all day. After all it's just a cat.

Bongo Copy Cat Introduction Bongo Copy Cat wants to be involved in everything you do but instead just imitates you hitting your keyboard all day. Afte

Abhijeet Singh 4 Jan 23, 2023
Twidge is a fresh approach to productivity. It integrates with your workflow and allows you to be your most productive self.

Twidge A productivity app which is an extension to your mind Twidge is a cross platform productivity app, powered by rust, tauri, prisma-client-rust T

Twidge 187 Jun 28, 2023
Rust Util Collection, a simple and friendly error-chain

RUC Rust Util Collection, a simple and friendly error-chain, with many useful utils as an addition. The painful experience of using error-chain gave b

ζΌ’ 8 Dec 8, 2022
Rust Util Collection, a simple and friendly error-chain, with many useful utils as an addition.

RUC Rust Util Collection, a simple and friendly error-chain, with many useful utils as an addition. The painful experience of using error-chain gave b

ζΌ’ 6 Mar 27, 2022