diff --git a/README.md b/README.md index bc905fd..c01d7ad 100644 --- a/README.md +++ b/README.md @@ -383,6 +383,229 @@ pub struct MyErrorType { ##### ... help text `miette` provides two facilities for supplying help text for your errors: +The first is the `#[help()]` format attribute that applies to structs or +enum variants: + +```rust +use miette::Diagnostic; +use thiserror::Error; + +#[derive(Debug, Diagnostic, Error)] +#[error("welp")] +#[diagnostic(help("try doing this instead"))] +struct Foo; +``` + +The other is by programmatically supplying the help text as a field to +your diagnostic: + +```rust +use miette::Diagnostic; +use thiserror::Error; + +#[derive(Debug, Diagnostic, Error)] +#[error("welp")] +#[diagnostic()] +struct Foo { + #[help] + advice: Option, // Can also just be `String` +} + +let err = Foo { + advice: Some("try doing this instead".to_string()), +}; +``` + +#### ... multiple related errors + +`miette` supports collecting multiple errors into a single diagnostic, and +printing them all together nicely. + +To do so, use the `#[related]` tag on any `IntoIter` field in your +`Diagnostic` type: + +```rust +use miette::Diagnostic; +use thiserror::Error; + +#[derive(Debug, Error, Diagnostic)] +#[error("oops")] +struct MyError { + #[related] + others: Vec, +} +``` + +#### ... delayed source code + +Sometimes it makes sense to add source code to the error message later. +One option is to use [`with_source_code()`](Report::with_source_code) +method for that: + +```rust +use miette::{Diagnostic, SourceSpan}; +use thiserror::Error; + +#[derive(Diagnostic, Debug, Error)] +#[error("oops")] +#[diagnostic()] +pub struct MyErrorType { + // Note: label but no source code + #[label] + err_span: SourceSpan, +} + +fn do_something() -> miette::Result<()> { + // This function emits actual error with label + return Err(MyErrorType { + err_span: (7..11).into(), + })?; +} + +fn main() -> miette::Result<()> { + do_something().map_err(|error| { + // And this code provides the source code for inner error + error.with_source_code(String::from("source code")) + }) +} +``` + +Also source code can be provided by a wrapper type. This is especially +useful in combination with `related`, when multiple errors should be +emitted at the same time: + +```rust +use miette::{Diagnostic, Report, SourceSpan}; +use thiserror::Error; + +#[derive(Diagnostic, Debug, Error)] +#[error("oops")] +#[diagnostic()] +pub struct InnerError { + // Note: label but no source code + #[label] + err_span: SourceSpan, +} + +#[derive(Diagnostic, Debug, Error)] +#[error("oops: multiple errors")] +#[diagnostic()] +pub struct MultiError { + // Note source code by no labels + #[source_code] + source_code: String, + // The source code above is used for these errors + #[related] + related: Vec, +} + +fn do_something() -> Result<(), Vec> { + Err(vec![ + InnerError { + err_span: (0..6).into(), + }, + InnerError { + err_span: (7..11).into(), + }, + ]) +} + +fn main() -> miette::Result<()> { + do_something().map_err(|err_list| MultiError { + source_code: "source code".into(), + related: err_list, + })?; + Ok(()) +} +``` + +#### ... Diagnostic-based error sources. + +When one uses the `#[source]` attribute on a field, that usually comes +from `thiserror`, and implements a method for +[`std::error::Error::source`]. This works in many cases, but it's lossy: +if the source of the diagnostic is a diagnostic itself, the source will +simply be treated as an `std::error::Error`. + +While this has no effect on the existing _reporters_, since they don't use +that information right now, APIs who might want this information will have +no access to it. + +If it's important for you for this information to be available to users, +you can use `#[diagnostic_source]` alongside `#[source]`. Not that you +will likely want to use _both_: + +```rust +use miette::Diagnostic; +use thiserror::Error; + +#[derive(Debug, Diagnostic, Error)] +#[error("MyError")] +struct MyError { + #[source] + #[diagnostic_source] + the_cause: OtherError, +} + +#[derive(Debug, Diagnostic, Error)] +#[error("OtherError")] +struct OtherError; +``` + +#### ... handler options + +[`MietteHandler`] is the default handler, and is very customizable. In +most cases, you can simply use [`MietteHandlerOpts`] to tweak its behavior +instead of falling back to your own custom handler. + +Usage is like so: + +```rust +miette::set_hook(Box::new(|_| { + Box::new( + miette::MietteHandlerOpts::new() + .terminal_links(true) + .unicode(false) + .context_lines(3) + .tab_width(4) + .build(), + ) +})) + +``` + +See the docs for [`MietteHandlerOpts`] for more details on what you can +customize! + +### Acknowledgements + +`miette` was not developed in a void. It owes enormous credit to various +other projects and their authors: + +- [`anyhow`](http://crates.io/crates/anyhow) and + [`color-eyre`](https://crates.io/crates/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`](https://crates.io/crates/thiserror) for setting the + standard for library-level error definitions, and for being the + inspiration behind `miette`'s derive macro. +- `rustc` and [@estebank](https://github.com/estebank) for their + state-of-the-art work in compiler diagnostics. +- [`ariadne`](https://crates.io/crates/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](./LICENSE). + +It also includes code taken from [`eyre`](https://github.com/yaahc/eyre), +and some from [`thiserror`](https://github.com/dtolnay/thiserror), also +under the Apache License. Some code is taken from +[`ariadne`](https://github.com/zesterer/ariadne), which is MIT licensed. + [`miette!`]: https://docs.rs/miette/latest/miette/macro.miette.html [`std::error::Error`]: https://doc.rust-lang.org/nightly/std/error/trait.Error.html [`Diagnostic`]: https://docs.rs/miette/latest/miette/struct.Diagnostic.html diff --git a/src/lib.rs b/src/lib.rs index 8c68a4c..27875fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -381,7 +381,7 @@ //! //! #### ... help text //! `miette` provides two facilities for supplying help text for your errors: -// +//! //! The first is the `#[help()]` format attribute that applies to structs or //! enum variants: //!