mirror of https://github.com/zkat/miette.git
fix(docs): Docs overhaul (#124)
* Fixed/formatted all intradoc links. Various other small doc fixes/typography/etc. * Clarified semantic similarity with anyhow/eyre types/macros. * Removed unused MietteError::SetPrinterFailure. * README now generaed from lib.rs via `cargo readme`. * More doc fixes, made ErrorHook type public. * Indentation (docs).
This commit is contained in:
parent
fa5b5fee54
commit
5d23c0d61d
284
README.md
284
README.md
|
|
@ -1,12 +1,15 @@
|
|||
you run miette? You run her code like the software? Oh. Oh! Error code for
|
||||
|
||||
# `miette`
|
||||
|
||||
You run miette? You run her code like the software? Oh. Oh! Error code for
|
||||
coder! Error code for One Thousand Lines!
|
||||
|
||||
## About
|
||||
### 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!):
|
||||
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!):
|
||||
|
||||
<img src="https://raw.githubusercontent.com/zkat/miette/main/images/serde_json.png" alt="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:
|
||||
\
|
||||
|
|
@ -19,17 +22,17 @@ at line 1, column 1659
|
|||
snippet line 1: gs":["json"],"title":"","version":"1.0.0"},"packageContent":"https://api.nuget.o
|
||||
highlight starting at line 1, column 1699: last parsing location
|
||||
\
|
||||
diagnostic help: This is a bug. It might be in ruget, or it might be in the source you're using,
|
||||
but it's definitely a bug and should be reported.
|
||||
diagnostic help: This is a bug. It might be in ruget, or it might be in the
|
||||
source you're using, but it's definitely a bug and should be reported.
|
||||
diagnostic error code: ruget::api::bad_json
|
||||
" />
|
||||
|
||||
**NOTE: You must enable the `"fancy"` crate feature to get fancy report output
|
||||
like in the screenshots here.** You should only do this in your toplevel
|
||||
crate, as the fancy feature pulls in a number of dependencies that libraries
|
||||
and such might not want.
|
||||
> **NOTE: You must enable the `"fancy"` crate feature to get fancy report
|
||||
output like in the screenshots above.** You should only do this in your
|
||||
toplevel crate, as the fancy feature pulls in a number of dependencies that
|
||||
libraries and such might not want.
|
||||
|
||||
## Table of Contents <!-- omit in toc -->
|
||||
### Table of Contents <!-- omit in toc -->
|
||||
|
||||
- [About](#about)
|
||||
- [Features](#features)
|
||||
|
|
@ -47,26 +50,32 @@ and such might not want.
|
|||
- [Acknowledgements](#acknowledgements)
|
||||
- [License](#license)
|
||||
|
||||
## Features
|
||||
### Features
|
||||
|
||||
- Generic [Diagnostic] protocol, compatible (and dependent on) `std::error::Error`.
|
||||
- Unique error codes on every [Diagnostic].
|
||||
- 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`](https://docs.rs/anyhow)/[`eyre`](https://docs.rs/eyre)-compatible error wrapper type, [Report],
|
||||
which can be returned from `main`.
|
||||
- Generic support for arbitrary [SourceCode]s for snippet data, with default support for `String`s included.
|
||||
- Replacements for [`anyhow`](https://docs.rs/anyhow)/[`eyre`](https://docs.rs/eyre)
|
||||
types [`Result`], [`Report`] and the [`miette!`] macro for the
|
||||
`anyhow!`/`eyre!` macros.
|
||||
- Generic support for arbitrary [`SourceCode`]s for snippet data, with
|
||||
default support for `String`s included.
|
||||
|
||||
The `miette` crate also comes bundled with a default [ReportHandler] with the following features:
|
||||
The `miette` crate also comes bundled with a default [`ReportHandler`] with
|
||||
the following features:
|
||||
|
||||
- Fancy graphical [diagnostic output](#about), using ANSI/Unicode text
|
||||
- single- and multi-line highlighting support
|
||||
- Screen reader/braille support, gated on [`NO_COLOR`](http://no-color.org/), and other heuristics.
|
||||
- Fully customizable graphical theming (or overriding the printers entirely).
|
||||
- Screen reader/braille support, gated on [`NO_COLOR`](http://no-color.org/),
|
||||
and other heuristics.
|
||||
- Fully customizable graphical theming (or overriding the printers
|
||||
entirely).
|
||||
- Cause chain printing
|
||||
- Turns diagnostic codes into links in [supported terminals](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda).
|
||||
|
||||
## Installing
|
||||
### Installing
|
||||
|
||||
Using [`cargo-edit`](https://crates.io/crates/cargo-edit):
|
||||
|
||||
|
|
@ -80,11 +89,11 @@ If you want to use the fancy printer in all these screenshots:
|
|||
$ cargo add miette --features fancy
|
||||
```
|
||||
|
||||
## Example
|
||||
### Example
|
||||
|
||||
```rust
|
||||
/*
|
||||
You can derive a Diagnostic from any `std::error::Error` type.
|
||||
You can derive a `Diagnostic` from any `std::error::Error` type.
|
||||
|
||||
`thiserror` is a great way to define them, and plays nicely with `miette`!
|
||||
*/
|
||||
|
|
@ -96,7 +105,7 @@ use thiserror::Error;
|
|||
#[diagnostic(
|
||||
code(oops::my::bad),
|
||||
url(docsrs),
|
||||
help("try doing it better next time?"),
|
||||
help("try doing it better next time?")
|
||||
)]
|
||||
struct MyBad {
|
||||
// The Source that we're gonna be printing snippets out of.
|
||||
|
|
@ -111,11 +120,11 @@ struct MyBad {
|
|||
/*
|
||||
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 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};
|
||||
use miette::{NamedSource, Result};
|
||||
fn this_fails() -> Result<()> {
|
||||
// You can use plain strings as a `Source`, or anything that implements
|
||||
// the one-method `Source` trait.
|
||||
|
|
@ -131,10 +140,11 @@ fn this_fails() -> Result<()> {
|
|||
}
|
||||
|
||||
/*
|
||||
Now to get everything printed nicely, just return a Result<()>
|
||||
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_hook()`
|
||||
Note: You can swap out the default reporter for a custom one using
|
||||
`miette::set_hook()`
|
||||
*/
|
||||
fn pretend_this_is_main() -> Result<()> {
|
||||
// kaboom~
|
||||
|
|
@ -161,24 +171,25 @@ diagnostic help: Change int or string to be the right types and try again.
|
|||
diagnostic code: nu::parser::unsupported_operation
|
||||
For more details, see https://docs.rs/nu-parser/0.1.0/nu-parser/enum.ParseError.html#variant.UnsupportedOperation">
|
||||
|
||||
## Using
|
||||
### Using
|
||||
|
||||
### ... in libraries
|
||||
#### ... 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].
|
||||
regular [`std::error::Error`].
|
||||
|
||||
We highly recommend using something like [`thiserror`](https://docs.rs/thiserror) to define unique error types and error wrappers for your library.
|
||||
We highly recommend using something like [`thiserror`](https://docs.rs/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`.
|
||||
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`.
|
||||
|
||||
```rust
|
||||
// lib/error.rs
|
||||
use thiserror::Error;
|
||||
use miette::Diagnostic;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Diagnostic, Debug)]
|
||||
pub enum MyLibError {
|
||||
|
|
@ -194,21 +205,21 @@ pub enum MyLibError {
|
|||
|
||||
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.
|
||||
using something like [`Report`] in a library.
|
||||
|
||||
### ... in application code
|
||||
#### ... 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.
|
||||
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::Error`s into [Diagnostic]s. Additionally, there's a
|
||||
[Result] type alias that you can use to be more terse.
|
||||
For this situation, `miette` includes two tools: [`Report`] and
|
||||
[`IntoDiagnostic`]. They work in tandem to make it easy to convert regular
|
||||
`std::error::Error`s 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:
|
||||
When dealing with non-`Diagnostic` types, you'll want to
|
||||
`.into_diagnostic()` them:
|
||||
|
||||
```rust
|
||||
// my_app/lib/my_internal_file.rs
|
||||
|
|
@ -220,9 +231,10 @@ pub fn some_tool() -> Result<Version> {
|
|||
}
|
||||
```
|
||||
|
||||
`miette` also includes an `anyhow`/`eyre`-style `Context`/`WrapErr` traits that
|
||||
you can import to add ad-hoc context messages to your `Diagnostic`s, as well,
|
||||
though you'll still need to use `.into_diagnostic()` to make use of it:
|
||||
`miette` also includes an `anyhow`/`eyre`-style `Context`/`WrapErr` traits
|
||||
that you can import to add ad-hoc context messages to your `Diagnostic`s, as
|
||||
well, though you'll still need to use `.into_diagnostic()` to make use of
|
||||
it:
|
||||
|
||||
```rust
|
||||
// my_app/lib/my_internal_file.rs
|
||||
|
|
@ -230,23 +242,26 @@ use miette::{IntoDiagnostic, Result, WrapErr};
|
|||
use semver::Version;
|
||||
|
||||
pub fn some_tool() -> Result<Version> {
|
||||
Ok("1.2.x".parse().into_diagnostic().wrap_err("Parsing this tool's semver version failed.")?)
|
||||
Ok("1.2.x"
|
||||
.parse()
|
||||
.into_diagnostic()
|
||||
.wrap_err("Parsing this tool's semver version failed.")?)
|
||||
}
|
||||
```
|
||||
|
||||
### ... in `main()`
|
||||
#### ... 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.
|
||||
`Result` as your return value, and it will pretty-print your diagnostics
|
||||
automatically.
|
||||
|
||||
**NOTE: You must enable the `"fancy"` crate feature to get fancy report output
|
||||
like in the screenshots here.** You should only do this in your toplevel
|
||||
crate, as the fancy feature pulls in a number of dependencies that libraries
|
||||
and such might not want.
|
||||
> **NOTE:** You must enable the `"fancy"` crate feature to get fancy report
|
||||
output like in the screenshots here.** You should only do this in your
|
||||
toplevel crate, as the fancy feature pulls in a number of dependencies that
|
||||
libraries and such might not want.
|
||||
|
||||
```rust
|
||||
use miette::{Result, IntoDiagnostic};
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
use semver::Version;
|
||||
|
||||
fn pretend_this_is_main() -> Result<()> {
|
||||
|
|
@ -264,23 +279,24 @@ enabled:
|
|||
miette = { version = "X.Y.Z", features = ["fancy"] }
|
||||
```
|
||||
|
||||
### ... diagnostic code URLs
|
||||
#### ... 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:
|
||||
`miette` supports providing a URL for individual diagnostics. This URL will
|
||||
be displayed as an actual link in supported terminals, like so:
|
||||
|
||||
<img
|
||||
src="https://raw.githubusercontent.com/zkat/miette/main/images/code_linking.png"
|
||||
alt=" 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.
|
||||
alt=" 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:
|
||||
To use this, you can add a `url()` sub-param to your `#[diagnostic]`
|
||||
attribute:
|
||||
|
||||
```rust
|
||||
use miette::Diagnostic;
|
||||
|
|
@ -299,8 +315,8 @@ 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:
|
||||
link to this diagnostic on `docs.rs`, so folks can just go straight to your
|
||||
(very high quality and detailed!) documentation on this diagnostic:
|
||||
|
||||
```rust
|
||||
use miette::Diagnostic;
|
||||
|
|
@ -316,21 +332,21 @@ use thiserror::Error;
|
|||
struct MyErr;
|
||||
```
|
||||
|
||||
### ... snippets
|
||||
#### ... snippets
|
||||
|
||||
Along with its general error handling and reporting features, `miette` also
|
||||
includes facilities for adding error spans/annotations/labels 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!
|
||||
includes facilities for adding error spans/annotations/labels 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 [SourceCode] and, along
|
||||
with the latter, gives `miette` all the information it needs to pretty-print
|
||||
some snippets! You can also use your own `Into<SourceSpan>` types as label
|
||||
spans.
|
||||
To achieve this, `miette` defines its own lightweight [`SourceSpan`] type.
|
||||
This is a basic byte-offset and length into an associated [`SourceCode`]
|
||||
and, along with the latter, gives `miette` all the information it needs to
|
||||
pretty-print some snippets! You can also use your own `Into<SourceSpan>`
|
||||
types as label spans.
|
||||
|
||||
The easiest way to define errors like this is to use the `derive(Diagnostic)`
|
||||
macro:
|
||||
The easiest way to define errors like this is to use the
|
||||
`derive(Diagnostic)` macro:
|
||||
|
||||
```rust
|
||||
use miette::{Diagnostic, SourceSpan};
|
||||
|
|
@ -352,11 +368,11 @@ pub struct MyErrorType {
|
|||
// You can add as many labels as you want.
|
||||
// They'll be rendered sequentially.
|
||||
#[label("This is bad")]
|
||||
snip2: (usize, usize), // (usize, usize) is Into<SourceSpan>!
|
||||
snip2: (usize, usize), // `(usize, usize)` is `Into<SourceSpan>`!
|
||||
}
|
||||
```
|
||||
|
||||
### ... multiple related errors
|
||||
#### ... multiple related errors
|
||||
|
||||
`miette` supports collecting multiple errors into a single diagnostic, and
|
||||
printing them all together nicely.
|
||||
|
|
@ -376,13 +392,13 @@ struct MyError {
|
|||
}
|
||||
```
|
||||
|
||||
### ... delayed source code
|
||||
#### ... 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
|
||||
option is to use [`with_source_code()`](Report::with_source_code) method for
|
||||
that:
|
||||
|
||||
```rust,no_run
|
||||
```rust
|
||||
use miette::{Diagnostic, SourceSpan};
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
@ -397,7 +413,9 @@ pub struct MyErrorType {
|
|||
|
||||
fn do_something() -> miette::Result<()> {
|
||||
// This function emits actual error with label
|
||||
return Err(MyErrorType { err_span: (7..11).into() })?;
|
||||
return Err(MyErrorType {
|
||||
err_span: (7..11).into(),
|
||||
})?;
|
||||
}
|
||||
|
||||
fn main() -> miette::Result<()> {
|
||||
|
|
@ -406,15 +424,14 @@ fn main() -> miette::Result<()> {
|
|||
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:
|
||||
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,no_run
|
||||
use miette::{Report, Diagnostic, SourceSpan};
|
||||
```rust
|
||||
use miette::{Diagnostic, Report, SourceSpan};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Diagnostic, Debug, Error)]
|
||||
|
|
@ -440,68 +457,85 @@ pub struct MultiError {
|
|||
|
||||
fn do_something() -> Result<(), Vec<InnerError>> {
|
||||
Err(vec![
|
||||
InnerError { err_span: (0..6).into() },
|
||||
InnerError { err_span: (7..11).into() },
|
||||
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,
|
||||
}
|
||||
do_something().map_err(|err_list| MultiError {
|
||||
source_code: "source code".into(),
|
||||
related: err_list,
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### ... handler options
|
||||
#### ... 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.
|
||||
[`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())
|
||||
Box::new(
|
||||
miette::MietteHandlerOpts::new()
|
||||
.terminal_links(true)
|
||||
.unicode(false)
|
||||
.context_lines(3)
|
||||
.tab_width(4)
|
||||
.build(),
|
||||
)
|
||||
}))
|
||||
|
||||
# .unwrap()
|
||||
```
|
||||
|
||||
See the docs for [MietteHandlerOpts] for more details on what you can customize!
|
||||
See the docs for [`MietteHandlerOpts`] for more details on what you can
|
||||
customize!
|
||||
|
||||
## Acknowledgements
|
||||
### Acknowledgements
|
||||
|
||||
`miette` was not developed in a void. It owes enormous credit to various other projects and their authors:
|
||||
`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.
|
||||
- [`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.
|
||||
- `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
|
||||
### License
|
||||
|
||||
`miette` is released to the Rust community under the [Apache license 2.0](./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
|
||||
[`IntoDiagnostic`]: https://docs.rs/miette/latest/miette/trait.IntoDiagnostic.html
|
||||
[`MietteHandlerOpts`]: https://docs.rs/miette/latest/miette/struct.MietteHandlerOpts.html
|
||||
[`MietteHandler`]: https://docs.rs/miette/latest/miette/struct.MietteHandler.html
|
||||
[`Report`]: https://docs.rs/miette/latest/miette/struct.Report.html
|
||||
[`ReportHandler`]: https://docs.rs/miette/latest/miette/struct.ReportHandler.html
|
||||
[`Result`]: https://docs.rs/miette/latest/miette/type.Result.html
|
||||
[`SourceCode`]: https://docs.rs/miette/latest/miette/struct.SourceCode.html
|
||||
[`SourceSpan`]: https://docs.rs/miette/latest/miette/struct.SourceSpan.html
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
# `{{crate}}`
|
||||
|
||||
{{readme}}
|
||||
|
||||
[`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
|
||||
[`IntoDiagnostic`]: https://docs.rs/miette/latest/miette/trait.IntoDiagnostic.html
|
||||
[`MietteHandlerOpts`]: https://docs.rs/miette/latest/miette/struct.MietteHandlerOpts.html
|
||||
[`MietteHandler`]: https://docs.rs/miette/latest/miette/struct.MietteHandler.html
|
||||
[`Report`]: https://docs.rs/miette/latest/miette/struct.Report.html
|
||||
[`ReportHandler`]: https://docs.rs/miette/latest/miette/struct.ReportHandler.html
|
||||
[`Result`]: https://docs.rs/miette/latest/miette/type.Result.html
|
||||
[`SourceCode`]: https://docs.rs/miette/latest/miette/struct.SourceCode.html
|
||||
[`SourceSpan`]: https://docs.rs/miette/latest/miette/struct.SourceSpan.html
|
||||
|
|
@ -82,7 +82,8 @@ pub(crate) fn gen_unused_pat(fields: &syn::Fields) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
/// Goes in the slot `let Self #pat = self;` or `match self { Self #pat => ... }`.
|
||||
/// Goes in the slot `let Self #pat = self;` or `match self { Self #pat => ...
|
||||
/// }`.
|
||||
fn gen_fields_pat(fields: &syn::Fields) -> TokenStream {
|
||||
let member_idents = fields.iter().enumerate().map(|(i, field)| {
|
||||
field
|
||||
|
|
@ -102,8 +103,9 @@ fn gen_fields_pat(fields: &syn::Fields) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
/// The returned tokens go in the slot `let Self #pat = self;` or `match self { Self #pat => ... }`.
|
||||
/// The members can be passed to `Display::expand_shorthand[_cloned]`.
|
||||
/// The returned tokens go in the slot `let Self #pat = self;` or `match self {
|
||||
/// Self #pat => ... }`. The members can be passed to
|
||||
/// `Display::expand_shorthand[_cloned]`.
|
||||
pub(crate) fn display_pat_members(fields: &syn::Fields) -> (TokenStream, HashSet<syn::Member>) {
|
||||
let pat = gen_fields_pat(fields);
|
||||
let members: HashSet<syn::Member> = fields
|
||||
|
|
@ -124,7 +126,8 @@ pub(crate) fn display_pat_members(fields: &syn::Fields) -> (TokenStream, HashSet
|
|||
}
|
||||
|
||||
impl Display {
|
||||
/// Returns `(fmt, args)` which must be passed to some kind of format macro without tokens in between, i.e. `format!(#fmt #args)`.
|
||||
/// Returns `(fmt, args)` which must be passed to some kind of format macro
|
||||
/// without tokens in between, i.e. `format!(#fmt #args)`.
|
||||
pub(crate) fn expand_shorthand_cloned(
|
||||
&self,
|
||||
members: &HashSet<syn::Member>,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
edition = "2021"
|
||||
wrap_comments = true
|
||||
format_code_in_doc_comments = true
|
||||
13
src/error.rs
13
src/error.rs
|
|
@ -9,13 +9,14 @@ Error enum for miette. Used by certain operations in the protocol.
|
|||
*/
|
||||
#[derive(Debug, Diagnostic, Error)]
|
||||
pub enum MietteError {
|
||||
/// Wrapper around [std::io::Error]. This is returned when something went
|
||||
/// wrong while reading a [crate::Source].
|
||||
/// Wrapper around [`std::io::Error`]. This is returned when something went
|
||||
/// wrong while reading a [`SourceCode`](crate::SourceCode).
|
||||
#[error(transparent)]
|
||||
#[diagnostic(code(miette::io_error), url(docsrs))]
|
||||
IoError(#[from] io::Error),
|
||||
|
||||
/// Returned when a [crate::SourceSpan] extends beyond the bounds of a given [crate::Source].
|
||||
/// Returned when a [`SourceSpan`](crate::SourceSpan) extends beyond the
|
||||
/// bounds of a given [`SourceCode`](crate::SourceCode).
|
||||
#[error("The given offset is outside the bounds of its Source")]
|
||||
#[diagnostic(
|
||||
code(miette::span_out_of_bounds),
|
||||
|
|
@ -23,10 +24,4 @@ pub enum MietteError {
|
|||
url(docsrs)
|
||||
)]
|
||||
OutOfBounds,
|
||||
|
||||
/// Returned when installing a [crate::ReportHandler] failed.
|
||||
/// Typically, this will be because [crate::set_printer] was called twice.
|
||||
#[error("Failed to install ReportHandler")]
|
||||
#[diagnostic(code(miette::set_printer_failed), url(docsrs))]
|
||||
SetPrinterFailure,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ impl Report {
|
|||
/// #
|
||||
/// # use ffi::{Input, Output};
|
||||
/// #
|
||||
/// use miette::{Report, Result};
|
||||
/// use futures::stream::{Stream, StreamExt, TryStreamExt};
|
||||
/// use miette::{Report, Result};
|
||||
///
|
||||
/// async fn demo<S>(stream: S) -> Result<Vec<Output>>
|
||||
/// where
|
||||
|
|
@ -193,13 +193,13 @@ impl Report {
|
|||
|
||||
/// Create a new error from an error message to wrap the existing error.
|
||||
///
|
||||
/// For attaching a higher level error message to a `Result` as it is propagated, the
|
||||
/// [crate::WrapErr] extension trait may be more convenient than this function.
|
||||
///
|
||||
/// The primary reason to use `error.wrap_err(...)` instead of `result.wrap_err(...)` via the
|
||||
/// `WrapErr` trait would be if the message needs to depend on some data held by the underlying
|
||||
/// error:
|
||||
/// For attaching a higher level error message to a `Result` as it is
|
||||
/// propagated, the [crate::WrapErr] extension trait may be more
|
||||
/// convenient than this function.
|
||||
///
|
||||
/// The primary reason to use `error.wrap_err(...)` instead of
|
||||
/// `result.wrap_err(...)` via the `WrapErr` trait would be if the
|
||||
/// message needs to depend on some data held by the underlying error:
|
||||
pub fn wrap_err<D>(mut self, msg: D) -> Self
|
||||
where
|
||||
D: Display + Send + Sync + 'static,
|
||||
|
|
@ -258,7 +258,7 @@ impl Report {
|
|||
/// cause's cause etc.
|
||||
///
|
||||
/// The root cause is the last error in the iterator produced by
|
||||
/// [`chain()`][Report::chain].
|
||||
/// [`chain()`](Report::chain).
|
||||
pub fn root_cause(&self) -> &(dyn StdError + 'static) {
|
||||
let mut chain = self.chain();
|
||||
let mut root_cause = chain.next().unwrap();
|
||||
|
|
@ -270,9 +270,10 @@ impl Report {
|
|||
|
||||
/// Returns true if `E` is the type held by this error object.
|
||||
///
|
||||
/// For errors constructed from messages, this method returns true if `E` matches the type of
|
||||
/// the message `D` **or** the type of the error on which the message has been attached. For
|
||||
/// details about the interaction between message and downcasting, [see here].
|
||||
/// For errors constructed from messages, this method returns true if `E`
|
||||
/// matches the type of the message `D` **or** the type of the error on
|
||||
/// which the message has been attached. For details about the
|
||||
/// interaction between message and downcasting, [see here].
|
||||
///
|
||||
/// [see here]: trait.WrapErr.html#effect-on-downcasting
|
||||
pub fn is<E>(&self) -> bool
|
||||
|
|
|
|||
|
|
@ -2,19 +2,20 @@ use thiserror::Error;
|
|||
|
||||
use crate::{Diagnostic, Report};
|
||||
|
||||
/// Convenience [Diagnostic] that can be used as an "anonymous" wrapper for
|
||||
/// Errors. This is intended to be paired with [IntoDiagnostic].
|
||||
/// Convenience [`Diagnostic`] that can be used as an "anonymous" wrapper for
|
||||
/// Errors. This is intended to be paired with [`IntoDiagnostic`].
|
||||
#[derive(Debug, Error)]
|
||||
#[error(transparent)]
|
||||
struct DiagnosticError(Box<dyn std::error::Error + Send + Sync + 'static>);
|
||||
impl Diagnostic for DiagnosticError {}
|
||||
|
||||
/**
|
||||
Convenience trait that adds a `.into_diagnostic()` method that converts a type to a `Result<T, Report>`.
|
||||
Convenience trait that adds a `.into_diagnostic()` method that converts a type
|
||||
to a `Result<T, Report>`.
|
||||
*/
|
||||
pub trait IntoDiagnostic<T, E> {
|
||||
/// Converts [Result]-like types that return regular errors into a
|
||||
/// `Result` that returns a [Diagnostic].
|
||||
/// Converts [`Result`]-like types that return regular errors into a
|
||||
/// `Result` that returns a [`Diagnostic`].
|
||||
fn into_diagnostic(self) -> Result<T, Report>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,6 +146,10 @@ macro_rules! ensure {
|
|||
/// # Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## `anyhow`/`eyre` Users
|
||||
///
|
||||
/// You can just replace `use`s of the `anyhow!`/`eyre!` macros with `miette!`.
|
||||
#[macro_export]
|
||||
macro_rules! miette {
|
||||
($msg:literal $(,)?) => {
|
||||
|
|
|
|||
|
|
@ -44,17 +44,23 @@ mod wrapper;
|
|||
|
||||
/**
|
||||
Core Diagnostic wrapper type.
|
||||
|
||||
## `eyre` Users
|
||||
|
||||
You can just replace `use`s of `eyre::Report` with `miette::Report`.
|
||||
*/
|
||||
pub struct Report {
|
||||
inner: ManuallyDrop<Box<ErrorImpl<()>>>,
|
||||
}
|
||||
|
||||
type ErrorHook =
|
||||
///
|
||||
pub type ErrorHook =
|
||||
Box<dyn Fn(&(dyn Diagnostic + 'static)) -> Box<dyn ReportHandler> + Sync + Send + 'static>;
|
||||
|
||||
static HOOK: OnceCell<ErrorHook> = OnceCell::new();
|
||||
|
||||
/// Error indicating that `set_hook` was unable to install the provided ErrorHook
|
||||
/// Error indicating that [`set_hook()`] was unable to install the provided
|
||||
/// [`ErrorHook`].
|
||||
#[derive(Debug)]
|
||||
pub struct InstallError;
|
||||
|
||||
|
|
@ -68,7 +74,7 @@ impl StdError for InstallError {}
|
|||
impl Diagnostic for InstallError {}
|
||||
|
||||
/**
|
||||
Set the hook?
|
||||
Set the error hook.
|
||||
*/
|
||||
pub fn set_hook(hook: ErrorHook) -> Result<(), InstallError> {
|
||||
HOOK.set(hook).map_err(|_| InstallError)
|
||||
|
|
@ -139,9 +145,8 @@ pub trait ReportHandler: core::any::Any + Send + Sync {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use miette::Diagnostic;
|
||||
/// use miette::ReportHandler;
|
||||
/// use indenter::indented;
|
||||
/// use miette::{Diagnostic, ReportHandler};
|
||||
///
|
||||
/// pub struct Handler;
|
||||
///
|
||||
|
|
@ -193,8 +198,9 @@ pub trait ReportHandler: core::any::Any + Send + Sync {
|
|||
|
||||
/// type alias for `Result<T, Report>`
|
||||
///
|
||||
/// This is a reasonable return type to use throughout your application but also for `fn main`; if
|
||||
/// you do, failures will be printed along with a backtrace if one was captured.
|
||||
/// This is a reasonable return type to use throughout your application but also
|
||||
/// for `main()`. If you do, failures will be printed along with a backtrace if
|
||||
/// one was captured.
|
||||
///
|
||||
/// `miette::Result` may be used with one *or* two type parameters.
|
||||
///
|
||||
|
|
@ -239,9 +245,14 @@ pub trait ReportHandler: core::any::Any + Send + Sync {
|
|||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ## `anyhow`/`eyre` Users
|
||||
///
|
||||
/// You can just replace `use`s of `anyhow::Result`/`eyre::Result` with
|
||||
/// `miette::Result`.
|
||||
pub type Result<T, E = Report> = core::result::Result<T, E>;
|
||||
|
||||
/// Provides the `wrap_err` method for `Result`.
|
||||
/// Provides the [`wrap_err()`](WrapErr::wrap_err) method for [`Result`].
|
||||
///
|
||||
/// This trait is sealed and cannot be implemented for types outside of
|
||||
/// `miette`.
|
||||
|
|
@ -250,8 +261,7 @@ pub type Result<T, E = Report> = core::result::Result<T, E>;
|
|||
///
|
||||
/// ```
|
||||
/// use miette::{WrapErr, IntoDiagnostic, Result};
|
||||
/// use std::fs;
|
||||
/// use std::path::PathBuf;
|
||||
/// use std::{fs, path::PathBuf};
|
||||
///
|
||||
/// pub struct ImportantThing {
|
||||
/// path: PathBuf,
|
||||
|
|
@ -272,7 +282,10 @@ pub type Result<T, E = Report> = core::result::Result<T, E>;
|
|||
/// let path = &it.path;
|
||||
/// let content = fs::read(path)
|
||||
/// .into_diagnostic()
|
||||
/// .wrap_err_with(|| format!("Failed to read instrs from {}", path.display()))?;
|
||||
/// .wrap_err_with(|| format!(
|
||||
/// "Failed to read instrs from {}",
|
||||
/// path.display())
|
||||
/// )?;
|
||||
///
|
||||
/// Ok(content)
|
||||
/// }
|
||||
|
|
@ -288,12 +301,15 @@ pub type Result<T, E = Report> = core::result::Result<T, E>;
|
|||
/// No such file or directory (os error 2)
|
||||
/// ```
|
||||
///
|
||||
/// # Wrapping Types That Don't impl `Error` (e.g. `&str` and `Box<dyn Error>`)
|
||||
/// # Wrapping Types That Do Not Implement `Error`
|
||||
///
|
||||
/// Due to restrictions for coherence `Report` cannot impl `From` for types that don't impl
|
||||
/// `Error`. Attempts to do so will give "this type might implement Error in the future" as an
|
||||
/// error. As such, `wrap_err`, which uses `From` under the hood, cannot be used to wrap these
|
||||
/// types. Instead we encourage you to use the combinators provided for `Result` in `std`/`core`.
|
||||
/// For example `&str` and `Box<dyn Error>`.
|
||||
///
|
||||
/// Due to restrictions for coherence `Report` cannot implement `From` for types
|
||||
/// that don't implement `Error`. Attempts to do so will give `"this type might
|
||||
/// implement Error in the future"` as an error. As such, `wrap_err()`, which
|
||||
/// uses `From` under the hood, cannot be used to wrap these types. Instead we
|
||||
/// encourage you to use the combinators provided for `Result` in `std`/`core`.
|
||||
///
|
||||
/// For example, instead of this:
|
||||
///
|
||||
|
|
@ -301,7 +317,9 @@ pub type Result<T, E = Report> = core::result::Result<T, E>;
|
|||
/// use std::error::Error;
|
||||
/// use miette::{WrapErr, Report};
|
||||
///
|
||||
/// fn wrap_example(err: Result<(), Box<dyn Error + Send + Sync + 'static>>) -> Result<(), Report> {
|
||||
/// fn wrap_example(err: Result<(), Box<dyn Error + Send + Sync + 'static>>)
|
||||
/// -> Result<(), Report>
|
||||
/// {
|
||||
/// err.wrap_err("saw a downstream error")
|
||||
/// }
|
||||
/// ```
|
||||
|
|
@ -309,30 +327,31 @@ pub type Result<T, E = Report> = core::result::Result<T, E>;
|
|||
/// We encourage you to write this:
|
||||
///
|
||||
/// ```rust
|
||||
/// use miette::{miette, Report, WrapErr};
|
||||
/// use std::error::Error;
|
||||
/// use miette::{WrapErr, Report, miette};
|
||||
///
|
||||
/// fn wrap_example(err: Result<(), Box<dyn Error + Send + Sync + 'static>>) -> Result<(), Report> {
|
||||
/// err.map_err(|e| miette!(e)).wrap_err("saw a downstream error")
|
||||
/// err.map_err(|e| miette!(e))
|
||||
/// .wrap_err("saw a downstream error")
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Effect on downcasting
|
||||
/// # Effect on Downcasting
|
||||
///
|
||||
/// After attaching a message of type `D` onto an error of type `E`, the resulting
|
||||
/// `miette::Error` may be downcast to `D` **or** to `E`.
|
||||
/// After attaching a message of type `D` onto an error of type `E`, the
|
||||
/// resulting `miette::Error` may be downcast to `D` **or** to `E`.
|
||||
///
|
||||
/// That is, in codebases that rely on downcasting, miette's wrap_err supports
|
||||
/// both of the following use cases:
|
||||
/// That is, in codebases that rely on downcasting, `miette`'s `wrap_err()`
|
||||
/// supports both of the following use cases:
|
||||
///
|
||||
/// - **Attaching messages whose type is insignificant onto errors whose type
|
||||
/// is used in downcasts.**
|
||||
///
|
||||
/// In other error libraries whose wrap_err is not designed this way, it can
|
||||
/// be risky to introduce messages to existing code because new message might
|
||||
/// break existing working downcasts. In miette, any downcast that worked
|
||||
/// before adding the message will continue to work after you add a message, so
|
||||
/// you should freely wrap errors wherever it would be helpful.
|
||||
/// In other error libraries whose `wrap_err()` is not designed this way, it
|
||||
/// can be risky to introduce messages to existing code because new message
|
||||
/// might break existing working downcasts. In miette, any downcast that
|
||||
/// worked before adding the message will continue to work after you add a
|
||||
/// message, so you should freely wrap errors wherever it would be helpful.
|
||||
///
|
||||
/// ```
|
||||
/// # use miette::bail;
|
||||
|
|
@ -422,13 +441,13 @@ pub trait WrapErr<T, E>: context::private::Sealed {
|
|||
D: Display + Send + Sync + 'static,
|
||||
F: FnOnce() -> D;
|
||||
|
||||
/// Compatibility re-export of wrap_err for interop with `anyhow`
|
||||
/// Compatibility re-export of `wrap_err()` for interop with `anyhow`
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
fn context<D>(self, msg: D) -> Result<T, Report>
|
||||
where
|
||||
D: Display + Send + Sync + 'static;
|
||||
|
||||
/// Compatibility re-export of wrap_err_with for interop with `anyhow`
|
||||
/// Compatibility re-export of `wrap_err_with()` for interop with `anyhow`
|
||||
#[cfg_attr(track_caller, track_caller)]
|
||||
fn with_context<D, F>(self, f: F) -> Result<T, Report>
|
||||
where
|
||||
|
|
@ -436,7 +455,7 @@ pub trait WrapErr<T, E>: context::private::Sealed {
|
|||
F: FnOnce() -> D;
|
||||
}
|
||||
|
||||
// Not public API. Referenced by macro-generated code.
|
||||
// Private API. Referenced by macro-generated code.
|
||||
#[doc(hidden)]
|
||||
pub mod private {
|
||||
use super::Report;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::ThemeCharacters;
|
|||
use crate::ThemeStyles;
|
||||
|
||||
/**
|
||||
Create a custom [MietteHandler] from options.
|
||||
Create a custom [`MietteHandler`] from options.
|
||||
|
||||
## Example
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ pub struct MietteHandlerOpts {
|
|||
}
|
||||
|
||||
impl MietteHandlerOpts {
|
||||
/// Create a new [MietteHandlerOpts].
|
||||
/// Create a new `MietteHandlerOpts`.
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
|
@ -56,15 +56,16 @@ impl MietteHandlerOpts {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set a graphical theme for the handler when rendering in graphical
|
||||
/// mode. Use [MietteHandlerOpts::force_graphical] to force graphical
|
||||
/// mode. This option overrides [MietteHandlerOpts::color].
|
||||
/// Set a graphical theme for the handler when rendering in graphical mode.
|
||||
/// Use [`force_graphical()`](`MietteHandlerOpts::force_graphical) to force
|
||||
/// graphical mode. This option overrides
|
||||
/// [`color()`](`MietteHandlerOpts::color).
|
||||
pub fn graphical_theme(mut self, theme: GraphicalTheme) -> Self {
|
||||
self.theme = Some(theme);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the width to wrap the report at. Defaults
|
||||
/// Sets the width to wrap the report at. Defaults to 80.
|
||||
pub fn width(mut self, width: usize) -> Self {
|
||||
self.width = Some(width);
|
||||
self
|
||||
|
|
@ -126,7 +127,7 @@ impl MietteHandlerOpts {
|
|||
self
|
||||
}
|
||||
|
||||
/// Builds a [MietteHandler] from this builder.
|
||||
/// Builds a [`MietteHandler`] from this builder.
|
||||
pub fn build(self) -> MietteHandler {
|
||||
let graphical = self.is_graphical();
|
||||
let width = self.get_width();
|
||||
|
|
@ -216,15 +217,18 @@ impl MietteHandlerOpts {
|
|||
}
|
||||
|
||||
/**
|
||||
A [ReportHandler] that displays a given [crate::Report] in a quasi-graphical
|
||||
way, using terminal colors, unicode drawing characters, and other such things.
|
||||
A [`ReportHandler`] that displays a given [`Report`](crate::Report) in a
|
||||
quasi-graphical way, using terminal colors, unicode drawing characters, and
|
||||
other such things.
|
||||
|
||||
This is the default reporter bundled with `miette`.
|
||||
|
||||
This printer can be customized by using `new_themed()` and handing it a
|
||||
[GraphicalTheme] of your own creation (or using one of its own defaults!)
|
||||
This printer can be customized by using
|
||||
[`GraphicalReportHandler::new_themed()`] and handing it a [`GraphicalTheme`] of
|
||||
your own creation (or using one of its own defaults).
|
||||
|
||||
See [crate::set_hook] for more details on customizing your global printer.
|
||||
See [`set_hook`](crate::set_hook) for more details on customizing your global
|
||||
printer.
|
||||
*/
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct MietteHandler {
|
||||
|
|
@ -232,7 +236,7 @@ pub struct MietteHandler {
|
|||
}
|
||||
|
||||
impl MietteHandler {
|
||||
/// Creates a new [MietteHandler] with default settings.
|
||||
/// Creates a new [`MietteHandler`] with default settings.
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::fmt;
|
|||
use crate::{protocol::Diagnostic, ReportHandler};
|
||||
|
||||
/**
|
||||
[ReportHandler] that renders plain text and avoids extraneous graphics.
|
||||
[`ReportHandler`] that renders plain text and avoids extraneous graphics.
|
||||
It's optimized for screen readers and braille users, but is also used in any
|
||||
non-graphical environments, such as non-TTY output.
|
||||
*/
|
||||
|
|
@ -11,8 +11,8 @@ non-graphical environments, such as non-TTY output.
|
|||
pub struct DebugReportHandler;
|
||||
|
||||
impl DebugReportHandler {
|
||||
/// Create a new [NarratableReportHandler]. There are no customization
|
||||
/// options.
|
||||
/// Create a new [`NarratableReportHandler`](crate::NarratableReportHandler)
|
||||
/// There are no customization options.
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
|
@ -25,10 +25,9 @@ impl Default for DebugReportHandler {
|
|||
}
|
||||
|
||||
impl DebugReportHandler {
|
||||
/// Render a [Diagnostic]. This function is mostly internal and meant to
|
||||
/// be called by the toplevel [ReportHandler] handler, but is
|
||||
/// made public to make it easier (possible) to test in isolation from
|
||||
/// global state.
|
||||
/// Render a [`Diagnostic`]. This function is mostly internal and meant to
|
||||
/// be called by the toplevel [`ReportHandler`] handler, but is made public
|
||||
/// to make it easier (possible) to test in isolation from global state.
|
||||
pub fn render_report(
|
||||
&self,
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
|
|
|
|||
|
|
@ -8,15 +8,17 @@ use crate::protocol::{Diagnostic, Severity};
|
|||
use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
|
||||
|
||||
/**
|
||||
A [ReportHandler] that displays a given [crate::Report] in a quasi-graphical
|
||||
way, using terminal colors, unicode drawing characters, and other such things.
|
||||
A [`ReportHandler`] that displays a given [`Report`](crate::Report) in a
|
||||
quasi-graphical way, using terminal colors, unicode drawing characters, and
|
||||
other such things.
|
||||
|
||||
This is the default reporter bundled with `miette`.
|
||||
|
||||
This printer can be customized by using `new_themed()` and handing it a
|
||||
[GraphicalTheme] of your own creation (or using one of its own defaults!)
|
||||
This printer can be customized by using [`new_themed()`](GraphicalReportHandler::new_themed) and handing it a
|
||||
[`GraphicalTheme`] of your own creation (or using one of its own defaults!)
|
||||
|
||||
See [crate::set_hook] for more details on customizing your global printer.
|
||||
See [`set_hook()`](crate::set_hook) for more details on customizing your global
|
||||
printer.
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GraphicalReportHandler {
|
||||
|
|
@ -29,8 +31,8 @@ pub struct GraphicalReportHandler {
|
|||
}
|
||||
|
||||
impl GraphicalReportHandler {
|
||||
/// Create a new [GraphicalReportHandler] with the default
|
||||
/// [GraphicalTheme]. This will use both unicode characters and colors.
|
||||
/// Create a new `GraphicalReportHandler` with the default
|
||||
/// [`GraphicalTheme`]. This will use both unicode characters and colors.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
linkify_code: true,
|
||||
|
|
@ -42,7 +44,7 @@ impl GraphicalReportHandler {
|
|||
}
|
||||
}
|
||||
|
||||
///Create a new [GraphicalReportHandler] with a given [GraphicalTheme].
|
||||
///Create a new `GraphicalReportHandler` with a given [`GraphicalTheme`].
|
||||
pub fn new_themed(theme: GraphicalTheme) -> Self {
|
||||
Self {
|
||||
linkify_code: true,
|
||||
|
|
@ -60,7 +62,7 @@ impl GraphicalReportHandler {
|
|||
self
|
||||
}
|
||||
|
||||
/// Whether to enable error code linkification using [Diagnostic::url].
|
||||
/// Whether to enable error code linkification using [`Diagnostic::url()`].
|
||||
pub fn with_links(mut self, links: bool) -> Self {
|
||||
self.linkify_code = links;
|
||||
self
|
||||
|
|
@ -78,7 +80,7 @@ impl GraphicalReportHandler {
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the "global" footer for this handler.
|
||||
/// Sets the 'global' footer for this handler.
|
||||
pub fn with_footer(mut self, footer: String) -> Self {
|
||||
self.footer = Some(footer);
|
||||
self
|
||||
|
|
@ -98,10 +100,9 @@ impl Default for GraphicalReportHandler {
|
|||
}
|
||||
|
||||
impl GraphicalReportHandler {
|
||||
/// Render a [Diagnostic]. This function is mostly internal and meant to
|
||||
/// be called by the toplevel [ReportHandler] handler, but is
|
||||
/// made public to make it easier (possible) to test in isolation from
|
||||
/// global state.
|
||||
/// Render a [`Diagnostic`]. This function is mostly internal and meant to
|
||||
/// be called by the toplevel [`ReportHandler`] handler, but is made public
|
||||
/// to make it easier (possible) to test in isolation from global state.
|
||||
pub fn render_report(
|
||||
&self,
|
||||
f: &mut impl fmt::Write,
|
||||
|
|
@ -294,8 +295,8 @@ impl GraphicalReportHandler {
|
|||
{
|
||||
contexts.pop();
|
||||
contexts.push((
|
||||
new_span, // We'll throw this away later
|
||||
left_conts,
|
||||
// We'll throw this away later
|
||||
new_span, left_conts,
|
||||
));
|
||||
} else {
|
||||
contexts.push((right, right_conts));
|
||||
|
|
@ -346,7 +347,8 @@ impl GraphicalReportHandler {
|
|||
max_gutter = std::cmp::max(max_gutter, num_highlights);
|
||||
}
|
||||
|
||||
// Oh and one more thing: We need to figure out how much room our line numbers need!
|
||||
// Oh and one more thing: We need to figure out how much room our line
|
||||
// numbers need!
|
||||
let linum_width = lines[..]
|
||||
.last()
|
||||
.expect("get_lines should always return at least one line?")
|
||||
|
|
@ -569,7 +571,8 @@ impl GraphicalReportHandler {
|
|||
let hl_len = std::cmp::max(1, hl.len());
|
||||
|
||||
let local_offset = if let Some(w) = self.tab_width {
|
||||
// Only count tabs that affect the position of the highlighted line and ignore tabs past the span.
|
||||
// Only count tabs that affect the position of the highlighted
|
||||
// line and ignore tabs past the span.
|
||||
let tab_count = &line.text[..hl.offset() - line.offset].matches('\t').count();
|
||||
let tabs_as_spaces = tab_count * w - tab_count;
|
||||
hl.offset() - line.offset + tabs_as_spaces
|
||||
|
|
@ -610,7 +613,8 @@ impl GraphicalReportHandler {
|
|||
.iter()
|
||||
.map(|hl| {
|
||||
let local_offset = if let Some(w) = self.tab_width {
|
||||
// Only count tabs that affect the position of the highlighted line and ignore tabs past the span.
|
||||
// Only count tabs that affect the position of the
|
||||
// highlighted line and ignore tabs past the span.
|
||||
let tab_count = &line.text[..hl.offset() - line.offset].matches('\t').count();
|
||||
let tabs_as_spaces = tab_count * w - tab_count;
|
||||
hl.offset() - line.offset + tabs_as_spaces
|
||||
|
|
@ -756,11 +760,12 @@ impl Line {
|
|||
|| (span.offset() + span.len() > self.offset && span.offset() + span.len() <= self.offset + self.length)
|
||||
}
|
||||
|
||||
// A "flyby" is a multi-line span that technically covers this line, but
|
||||
// A 'flyby' is a multi-line span that technically covers this line, but
|
||||
// does not begin or end within the line itself. This method is used to
|
||||
// calculate gutters.
|
||||
fn span_flyby(&self, span: &FancySpan) -> bool {
|
||||
// the span itself starts before this line's starting offset (so, in a prev line)
|
||||
// The span itself starts before this line's starting offset (so, in a
|
||||
// prev line).
|
||||
span.offset() < self.offset
|
||||
// ...and it stops after this line's end.
|
||||
&& span.offset() + span.len() > self.offset + self.length
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@ use std::fmt::{self, Write};
|
|||
use crate::{protocol::Diagnostic, ReportHandler, Severity, SourceCode};
|
||||
|
||||
/**
|
||||
[ReportHandler] that renders json output.
|
||||
It's a machine-readable output.
|
||||
[`ReportHandler`] that renders JSON output. It's a machine-readable output.
|
||||
*/
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct JSONReportHandler;
|
||||
|
||||
impl JSONReportHandler {
|
||||
/// Create a new [JSONReportHandler]. There are no customization
|
||||
/// Create a new [`JSONReportHandler`]. There are no customization
|
||||
/// options.
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
|
|
@ -54,10 +53,9 @@ fn escape(input: &'_ str) -> Escape<'_> {
|
|||
}
|
||||
|
||||
impl JSONReportHandler {
|
||||
/// Render a [Diagnostic]. This function is mostly internal and meant to
|
||||
/// be called by the toplevel [ReportHandler] handler, but is
|
||||
/// made public to make it easier (possible) to test in isolation from
|
||||
/// global state.
|
||||
/// Render a [`Diagnostic`]. This function is mostly internal and meant to
|
||||
/// be called by the toplevel [`ReportHandler`] handler, but is made public
|
||||
/// to make it easier (possible) to test in isolation from global state.
|
||||
pub fn render_report(
|
||||
&self,
|
||||
f: &mut impl fmt::Write,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::protocol::{Diagnostic, Severity};
|
|||
use crate::{LabeledSpan, MietteError, ReportHandler, SourceCode, SourceSpan, SpanContents};
|
||||
|
||||
/**
|
||||
[ReportHandler] that renders plain text and avoids extraneous graphics.
|
||||
[`ReportHandler`] that renders plain text and avoids extraneous graphics.
|
||||
It's optimized for screen readers and braille users, but is also used in any
|
||||
non-graphical environments, such as non-TTY output.
|
||||
*/
|
||||
|
|
@ -18,7 +18,7 @@ pub struct NarratableReportHandler {
|
|||
}
|
||||
|
||||
impl NarratableReportHandler {
|
||||
/// Create a new [NarratableReportHandler]. There are no customization
|
||||
/// Create a new [`NarratableReportHandler`]. There are no customization
|
||||
/// options.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
|
|
@ -47,8 +47,8 @@ impl Default for NarratableReportHandler {
|
|||
}
|
||||
|
||||
impl NarratableReportHandler {
|
||||
/// Render a [Diagnostic]. This function is mostly internal and meant to
|
||||
/// be called by the toplevel [ReportHandler] handler, but is
|
||||
/// Render a [`Diagnostic`]. This function is mostly internal and meant to
|
||||
/// be called by the toplevel [`ReportHandler`] handler, but is
|
||||
/// made public to make it easier (possible) to test in isolation from
|
||||
/// global state.
|
||||
pub fn render_report(
|
||||
|
|
@ -345,7 +345,8 @@ enum SpanAttach {
|
|||
Ends { col_end: usize },
|
||||
}
|
||||
|
||||
/// Returns column at offset, and nearest boundary if offset is in the middle of the character
|
||||
/// Returns column at offset, and nearest boundary if offset is in the middle of
|
||||
/// the character
|
||||
fn safe_get_column(text: &str, offset: usize, start: bool) -> usize {
|
||||
let mut column = text.get(0..offset).map(|s| s.width()).unwrap_or_else(|| {
|
||||
let mut column = 0;
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ use atty::Stream;
|
|||
use owo_colors::Style;
|
||||
|
||||
/**
|
||||
Theme used by [crate::GraphicalReportHandler] to render fancy [crate::Diagnostic] reports.
|
||||
Theme used by [`GraphicalReportHandler`](crate::GraphicalReportHandler) to
|
||||
render fancy [`Diagnostic`](crate::Diagnostic) reports.
|
||||
|
||||
A theme consists of two things: the set of characters to be used for drawing,
|
||||
and the [owo_colors::Style]s to be used to paint various items.
|
||||
and the
|
||||
[`owo_colors::Style`](https://docs.rs/owo-colors/latest/owo_colors/struct.Style.html)s to be used to paint various items.
|
||||
|
||||
You can create your own custom graphical theme using this type, or you can use
|
||||
one of the predefined ones using the methods below.
|
||||
|
|
@ -27,7 +29,8 @@ impl GraphicalTheme {
|
|||
}
|
||||
}
|
||||
|
||||
/// Graphical theme that draws using both ansi colors and unicode characters.
|
||||
/// Graphical theme that draws using both ansi colors and unicode
|
||||
/// characters.
|
||||
pub fn unicode() -> Self {
|
||||
Self {
|
||||
characters: ThemeCharacters::unicode(),
|
||||
|
|
@ -95,7 +98,7 @@ fn style() -> Style {
|
|||
|
||||
impl ThemeStyles {
|
||||
/// Nice RGB colors.
|
||||
/// Credit: http://terminal.sexy/#FRUV0NDQFRUVrEFCkKlZ9L91ap-1qnWfdbWq0NDQUFBQrEFCkKlZ9L91ap-1qnWfdbWq9fX1
|
||||
/// [Credit](http://terminal.sexy/#FRUV0NDQFRUVrEFCkKlZ9L91ap-1qnWfdbWq0NDQUFBQrEFCkKlZ9L91ap-1qnWfdbWq9fX1).
|
||||
pub fn rgb() -> Self {
|
||||
Self {
|
||||
error: style().fg_rgb::<255, 30, 30>(),
|
||||
|
|
@ -143,11 +146,12 @@ impl ThemeStyles {
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------
|
||||
// ----------------------------------------
|
||||
// Most of these characters were taken from
|
||||
// https://github.com/zesterer/ariadne/blob/e3cb394cb56ecda116a0a1caecd385a49e7f6662/src/draw.rs
|
||||
|
||||
/// Characters to be used when drawing when using [crate::GraphicalReportHandler].
|
||||
/// Characters to be used when drawing when using
|
||||
/// [crate::GraphicalReportHandler].
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct ThemeCharacters {
|
||||
|
|
|
|||
529
src/lib.rs
529
src/lib.rs
|
|
@ -1,7 +1,532 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
#![deny(missing_docs, missing_debug_implementations, nonstandard_style)]
|
||||
#![warn(unreachable_pub, rust_2018_idioms)]
|
||||
|
||||
//! 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!):
|
||||
//!
|
||||
//! <img src="https://raw.githubusercontent.com/zkat/miette/main/images/serde_json.png" alt="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":["json"],"title":"","version":"1.0.0"},"packageContent":"https://api.nuget.o
|
||||
//! highlight starting at line 1, column 1699: last parsing location
|
||||
//! \
|
||||
//! diagnostic help: This is a bug. It might be in ruget, or it might be in the
|
||||
//! source you're using, but it's definitely a bug and should be reported.
|
||||
//! diagnostic error code: ruget::api::bad_json
|
||||
//! " />
|
||||
//!
|
||||
//! > **NOTE: You must enable the `"fancy"` crate feature to get fancy report
|
||||
//! output like in the screenshots above.** You should only do this in your
|
||||
//! toplevel crate, as the fancy feature pulls in a number of dependencies that
|
||||
//! libraries and such might not want.
|
||||
//!
|
||||
//! ## Table of Contents <!-- omit in toc -->
|
||||
//!
|
||||
//! - [About](#about)
|
||||
//! - [Features](#features)
|
||||
//! - [Installing](#installing)
|
||||
//! - [Example](#example)
|
||||
//! - [Using](#using)
|
||||
//! - [... in libraries](#-in-libraries)
|
||||
//! - [... in application code](#-in-application-code)
|
||||
//! - [... in `main()`](#-in-main)
|
||||
//! - [... diagnostic code URLs](#-diagnostic-code-urls)
|
||||
//! - [... snippets](#-snippets)
|
||||
//! - [... multiple related errors](#-multiple-related-errors)
|
||||
//! - [... delayed source code](#-delayed-source-code)
|
||||
//! - [... handler options](#-handler-options)
|
||||
//! - [Acknowledgements](#acknowledgements)
|
||||
//! - [License](#license)
|
||||
//!
|
||||
//! ## 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.
|
||||
//! - Replacements for [`anyhow`](https://docs.rs/anyhow)/[`eyre`](https://docs.rs/eyre)
|
||||
//! types [`Result`], [`Report`] and the [`miette!`] macro for the
|
||||
//! `anyhow!`/`eyre!` macros.
|
||||
//! - Generic support for arbitrary [`SourceCode`]s for snippet data, with
|
||||
//! default support for `String`s included.
|
||||
//!
|
||||
//! The `miette` crate also comes bundled with a default [`ReportHandler`] with
|
||||
//! the following features:
|
||||
//!
|
||||
//! - Fancy graphical [diagnostic output](#about), using ANSI/Unicode text
|
||||
//! - single- and multi-line highlighting support
|
||||
//! - Screen reader/braille support, gated on [`NO_COLOR`](http://no-color.org/),
|
||||
//! and other heuristics.
|
||||
//! - Fully customizable graphical theming (or overriding the printers
|
||||
//! entirely).
|
||||
//! - Cause chain printing
|
||||
//! - Turns diagnostic codes into links in [supported terminals](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda).
|
||||
//!
|
||||
//! ## Installing
|
||||
//!
|
||||
//! Using [`cargo-edit`](https://crates.io/crates/cargo-edit):
|
||||
//!
|
||||
//! ```sh
|
||||
//! $ cargo add miette
|
||||
//! ```
|
||||
//!
|
||||
//! If you want to use the fancy printer in all these screenshots:
|
||||
//!
|
||||
//! ```sh
|
||||
//! $ cargo add miette --features fancy
|
||||
//! ```
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! /*
|
||||
//! 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),
|
||||
//! url(docsrs),
|
||||
//! 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.
|
||||
//! #[source_code]
|
||||
//! src: NamedSource,
|
||||
//! // Snippets and highlights can be included in the diagnostic!
|
||||
//! #[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::{NamedSource, Result};
|
||||
//! 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),
|
||||
//! 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_hook()`
|
||||
//! */
|
||||
//! fn pretend_this_is_main() -> Result<()> {
|
||||
//! // kaboom~
|
||||
//! this_fails()?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! And this is the output you'll get if you run this program:
|
||||
//!
|
||||
//! <img src="https://raw.githubusercontent.com/zkat/miette/main/images/single-line-example.png" alt="
|
||||
//! Narratable printout:
|
||||
//! \
|
||||
//! Error: Types mismatched for operation.
|
||||
//! Diagnostic severity: error
|
||||
//! Begin snippet starting at line 1, column 1
|
||||
//! \
|
||||
//! snippet line 1: 3 + "5"
|
||||
//! label starting at line 1, column 1: int
|
||||
//! label starting at line 1, column 1: doesn't support these values.
|
||||
//! label starting at line 1, column 1: string
|
||||
//! diagnostic help: Change int or string to be the right types and try again.
|
||||
//! diagnostic code: nu::parser::unsupported_operation
|
||||
//! For more details, see https://docs.rs/nu-parser/0.1.0/nu-parser/enum.ParseError.html#variant.UnsupportedOperation">
|
||||
//!
|
||||
//! ## 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`](https://docs.rs/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`.
|
||||
//!
|
||||
//! ```rust
|
||||
//! // lib/error.rs
|
||||
//! use miette::Diagnostic;
|
||||
//! use thiserror::Error;
|
||||
//!
|
||||
//! #[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::Error`s 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:
|
||||
//!
|
||||
//! ```rust
|
||||
//! // my_app/lib/my_internal_file.rs
|
||||
//! use miette::{IntoDiagnostic, Result};
|
||||
//! use semver::Version;
|
||||
//!
|
||||
//! pub fn some_tool() -> Result<Version> {
|
||||
//! 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 `Diagnostic`s, as
|
||||
//! well, though you'll still need to use `.into_diagnostic()` to make use of
|
||||
//! it:
|
||||
//!
|
||||
//! ```rust
|
||||
//! // my_app/lib/my_internal_file.rs
|
||||
//! use miette::{IntoDiagnostic, Result, WrapErr};
|
||||
//! use semver::Version;
|
||||
//!
|
||||
//! pub fn some_tool() -> Result<Version> {
|
||||
//! 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.
|
||||
//!
|
||||
//! > **NOTE:** You must enable the `"fancy"` crate feature to get fancy report
|
||||
//! output like in the screenshots here.** You should only do this in your
|
||||
//! toplevel crate, as the fancy feature pulls in a number of dependencies that
|
||||
//! libraries and such might not want.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use miette::{IntoDiagnostic, Result};
|
||||
//! use semver::Version;
|
||||
//!
|
||||
//! fn pretend_this_is_main() -> Result<()> {
|
||||
//! let version: Version = "1.2.x".parse().into_diagnostic()?;
|
||||
//! println!("{}", version);
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Please note: in order to get fancy diagnostic rendering with all the pretty
|
||||
//! colors and arrows, you should install `miette` with the `fancy` feature
|
||||
//! enabled:
|
||||
//!
|
||||
//! ```toml
|
||||
//! miette = { version = "X.Y.Z", features = ["fancy"] }
|
||||
//! ```
|
||||
//!
|
||||
//! ### ... 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:
|
||||
//!
|
||||
//! <img
|
||||
//! src="https://raw.githubusercontent.com/zkat/miette/main/images/code_linking.png"
|
||||
//! alt=" 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:
|
||||
//!
|
||||
//! ```rust
|
||||
//! 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:
|
||||
//!
|
||||
//! ```rust
|
||||
//! 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/annotations/labels 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 [`SourceCode`]
|
||||
//! and, along with the latter, gives `miette` all the information it needs to
|
||||
//! pretty-print some snippets! You can also use your own `Into<SourceSpan>`
|
||||
//! types as label spans.
|
||||
//!
|
||||
//! The easiest way to define errors like this is to use the
|
||||
//! `derive(Diagnostic)` macro:
|
||||
//!
|
||||
//! ```rust
|
||||
//! 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.
|
||||
//! #[source_code]
|
||||
//! src: String,
|
||||
//!
|
||||
//! // This will underline/mark the specific code inside the larger
|
||||
//! // snippet context.
|
||||
//! #[label = "This is the highlight"]
|
||||
//! err_span: SourceSpan,
|
||||
//!
|
||||
//! // You can add as many labels as you want.
|
||||
//! // They'll be rendered sequentially.
|
||||
//! #[label("This is bad")]
|
||||
//! snip2: (usize, usize), // `(usize, usize)` is `Into<SourceSpan>`!
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ### ... 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<MyError>,
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ### ... 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,no_run
|
||||
//! 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,no_run
|
||||
//! 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<InnerError>,
|
||||
//! }
|
||||
//!
|
||||
//! fn do_something() -> Result<(), Vec<InnerError>> {
|
||||
//! 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(())
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ### ... 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(),
|
||||
//! )
|
||||
//! }))
|
||||
//!
|
||||
//! # .unwrap()
|
||||
//! ```
|
||||
//!
|
||||
//! 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.
|
||||
pub use miette_derive::*;
|
||||
|
||||
pub use error::*;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use crate::{MietteError, MietteSpanContents, SourceCode, SpanContents};
|
||||
|
||||
/// Utility struct for when you have a regular [Source] type, such as a String,
|
||||
/// that doesn't implement `name`, or if you want to override the `.name()`
|
||||
/// returned by the `Source`.
|
||||
/// 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`.
|
||||
pub struct NamedSource {
|
||||
source: Box<dyn SourceCode + 'static>,
|
||||
name: String,
|
||||
|
|
@ -18,7 +18,8 @@ impl std::fmt::Debug for NamedSource {
|
|||
}
|
||||
|
||||
impl NamedSource {
|
||||
/// Create a new [NamedSource] using a regular [SourceCode] and giving its returned [SpanContents] a name.
|
||||
/// Create a new `NamedSource` using a regular [`SourceCode`] and giving
|
||||
/// its returned [`SpanContents`] a name.
|
||||
pub fn new(name: impl AsRef<str>, source: impl SourceCode + Send + Sync + 'static) -> Self {
|
||||
Self {
|
||||
source: Box::new(source),
|
||||
|
|
@ -26,7 +27,8 @@ impl NamedSource {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a reference the inner [SourceCode] type for this [NamedSource].
|
||||
/// Returns a reference the inner [`SourceCode`] type for this
|
||||
/// `NamedSource`.
|
||||
pub fn inner(&self) -> &(dyn SourceCode + 'static) {
|
||||
&*self.source
|
||||
}
|
||||
|
|
|
|||
110
src/protocol.rs
110
src/protocol.rs
|
|
@ -1,9 +1,8 @@
|
|||
/*!
|
||||
This module defines the core of the miette protocol: a series of types and traits
|
||||
that you can implement to get access to miette's (and related library's) full
|
||||
reporting and such features.
|
||||
This module defines the core of the miette protocol: a series of types and
|
||||
traits that you can implement to get access to miette's (and related library's)
|
||||
full reporting and such features.
|
||||
*/
|
||||
|
||||
use std::{
|
||||
fmt::{self, Display},
|
||||
fs,
|
||||
|
|
@ -12,50 +11,51 @@ use std::{
|
|||
|
||||
use crate::MietteError;
|
||||
|
||||
/**
|
||||
Adds rich metadata to your Error that can be used by [Report] to print
|
||||
really nice and human-friendly error messages.
|
||||
*/
|
||||
/// Adds rich metadata to your Error that can be used by
|
||||
/// [`Report`](crate::Report) to print really nice and human-friendly error
|
||||
/// messages.
|
||||
pub trait Diagnostic: std::error::Error {
|
||||
/// Unique diagnostic code that can be used to look up more information
|
||||
/// about this Diagnostic. Ideally also globally unique, and documented in
|
||||
/// the toplevel crate's documentation for easy searching. Rust path
|
||||
/// about this `Diagnostic`. Ideally also globally unique, and documented
|
||||
/// in the toplevel crate's documentation for easy searching. Rust path
|
||||
/// format (`foo::bar::baz`) is recommended, but more classic codes like
|
||||
/// `E0123` or Enums will work just fine.
|
||||
/// `E0123` or enums will work just fine.
|
||||
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Diagnostic severity. This may be used by [ReportHandler]s to change the
|
||||
/// display format of this diagnostic.
|
||||
/// Diagnostic severity. This may be used by
|
||||
/// [`ReportHandler`](crate::ReportHandler)s to change the display format
|
||||
/// of this diagnostic.
|
||||
///
|
||||
/// If `None`, reporters should treat this as [Severity::Error]
|
||||
/// If `None`, reporters should treat this as [`Severity::Error`].
|
||||
fn severity(&self) -> Option<Severity> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Additional help text related to this Diagnostic. Do you have any
|
||||
/// Additional help text related to this `Diagnostic`. Do you have any
|
||||
/// advice for the poor soul who's just run into this issue?
|
||||
fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// URL to visit for a more detailed explanation/help about this Diagnostic.
|
||||
/// URL to visit for a more detailed explanation/help about this
|
||||
/// `Diagnostic`.
|
||||
fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Source code to apply this Diagnostic's [Diagnostic::labels] to.
|
||||
/// Source code to apply this `Diagnostic`'s [`Diagnostic::labels`] to.
|
||||
fn source_code(&self) -> Option<&dyn SourceCode> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Labels to apply to this Diagnostic's [Diagnostic::source_code]
|
||||
/// Labels to apply to this `Diagnostic`'s [`Diagnostic::source_code`]
|
||||
fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Additional related Diagnostics.
|
||||
/// Additional related `Diagnostic`s.
|
||||
fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
|
||||
None
|
||||
}
|
||||
|
|
@ -153,8 +153,9 @@ impl From<Box<dyn std::error::Error + Send + Sync>> for Box<dyn Diagnostic + Sen
|
|||
}
|
||||
|
||||
/**
|
||||
[Diagnostic] severity. Intended to be used by [ReportHandler]s to change the
|
||||
way different Diagnostics are displayed.
|
||||
[`Diagnostic`] severity. Intended to be used by
|
||||
[`ReportHandler`](crate::ReportHandler)s to change the way different
|
||||
[`Diagnostic`]s are displayed.
|
||||
*/
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Severity {
|
||||
|
|
@ -169,13 +170,13 @@ pub enum Severity {
|
|||
/**
|
||||
Represents readable source code of some sort.
|
||||
|
||||
This trait is able to support simple Source types like [String]s, as well
|
||||
as more involved types like indexes into centralized `SourceMap`-like types,
|
||||
file handles, and even network streams.
|
||||
This trait is able to support simple `SourceCode` types like [`String`]s, as
|
||||
well as more involved types like indexes into centralized `SourceMap`-like
|
||||
types, file handles, and even network streams.
|
||||
|
||||
If you can read it, you can source it,
|
||||
and it's not necessary to read the whole thing--meaning you should be able to
|
||||
support SourceCodes which are gigabytes or larger in size.
|
||||
If you can read it, you can source it, and it's not necessary to read the
|
||||
whole thing--meaning you should be able to support `SourceCode`s which are
|
||||
gigabytes or larger in size.
|
||||
*/
|
||||
pub trait SourceCode: Send + Sync {
|
||||
/// Read the bytes for a specific span from this SourceCode, keeping a
|
||||
|
|
@ -188,9 +189,7 @@ pub trait SourceCode: Send + Sync {
|
|||
) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError>;
|
||||
}
|
||||
|
||||
/**
|
||||
A labeled [SourceSpan].
|
||||
*/
|
||||
/// A labeled [`SourceSpan`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct LabeledSpan {
|
||||
label: Option<String>,
|
||||
|
|
@ -214,12 +213,12 @@ impl LabeledSpan {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the (optional) label string for this LabeledSpan.
|
||||
/// Gets the (optional) label string for this `LabeledSpan`.
|
||||
pub fn label(&self) -> Option<&str> {
|
||||
self.label.as_deref()
|
||||
}
|
||||
|
||||
/// Returns a reference to the inner [SourceSpan].
|
||||
/// Returns a reference to the inner [`SourceSpan`].
|
||||
pub fn inner(&self) -> &SourceSpan {
|
||||
&self.span
|
||||
}
|
||||
|
|
@ -229,52 +228,53 @@ impl LabeledSpan {
|
|||
self.span.offset()
|
||||
}
|
||||
|
||||
/// Returns the number of bytes this LabeledSpan spans.
|
||||
/// Returns the number of bytes this `LabeledSpan` spans.
|
||||
pub fn len(&self) -> usize {
|
||||
self.span.len()
|
||||
}
|
||||
|
||||
/// True if this LabeledSpan is empty.
|
||||
/// True if this `LabeledSpan` is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.span.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Contents of a [SourceCode] covered by [SourceSpan].
|
||||
Contents of a [`SourceCode`] covered by [`SourceSpan`].
|
||||
|
||||
Includes line and column information to optimize highlight calculations.
|
||||
*/
|
||||
pub trait SpanContents<'a> {
|
||||
/// Reference to the data inside the associated span, in bytes.
|
||||
fn data(&self) -> &'a [u8];
|
||||
/// [SourceSpan] representing the span covered by this SpanContents.
|
||||
/// [`SourceSpan`] representing the span covered by this `SpanContents`.
|
||||
fn span(&self) -> &SourceSpan;
|
||||
/// An optional (file?) name for the container of this SpanContents.
|
||||
/// 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.
|
||||
/// The 0-indexed line in the associated [`SourceCode`] where the data
|
||||
/// begins.
|
||||
fn line(&self) -> usize;
|
||||
/// The 0-indexed column in the associated [SourceCode] where the data begins,
|
||||
/// relative to `line`.
|
||||
/// The 0-indexed column in the associated [`SourceCode`] where the data
|
||||
/// begins, relative to `line`.
|
||||
fn column(&self) -> usize;
|
||||
/// Total number of lines covered by this SpanContents.
|
||||
/// Total number of lines covered by this `SpanContents`.
|
||||
fn line_count(&self) -> usize;
|
||||
}
|
||||
|
||||
/**
|
||||
Basic implementation of the [SpanContents] trait, for convenience.
|
||||
Basic implementation of the [`SpanContents`] trait, for convenience.
|
||||
*/
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MietteSpanContents<'a> {
|
||||
// Data from a [SourceCode], in bytes.
|
||||
// Data from a [`SourceCode`], in bytes.
|
||||
data: &'a [u8],
|
||||
// span actually covered by this SpanContents.
|
||||
span: SourceSpan,
|
||||
// The 0-indexed line where the associated [SourceSpan] _starts_.
|
||||
// The 0-indexed line where the associated [`SourceSpan`] _starts_.
|
||||
line: usize,
|
||||
// The 0-indexed column where the associated [SourceSpan] _starts_.
|
||||
// The 0-indexed column where the associated [`SourceSpan`] _starts_.
|
||||
column: usize,
|
||||
// Number of line in this snippet.
|
||||
line_count: usize,
|
||||
|
|
@ -283,7 +283,7 @@ pub struct MietteSpanContents<'a> {
|
|||
}
|
||||
|
||||
impl<'a> MietteSpanContents<'a> {
|
||||
/// Make a new [MietteSpanContents] object.
|
||||
/// Make a new [`MietteSpanContents`] object.
|
||||
pub fn new(
|
||||
data: &'a [u8],
|
||||
span: SourceSpan,
|
||||
|
|
@ -301,7 +301,7 @@ impl<'a> MietteSpanContents<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Make a new [MietteSpanContents] object, with a name for its "file".
|
||||
/// Make a new [`MietteSpanContents`] object, with a name for its 'file'.
|
||||
pub fn new_named(
|
||||
name: String,
|
||||
data: &'a [u8],
|
||||
|
|
@ -343,7 +343,7 @@ impl<'a> SpanContents<'a> for MietteSpanContents<'a> {
|
|||
}
|
||||
|
||||
/**
|
||||
Span within a [SourceCode] with an associated message.
|
||||
Span within a [`SourceCode`] with an associated message.
|
||||
*/
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct SourceSpan {
|
||||
|
|
@ -354,7 +354,7 @@ pub struct SourceSpan {
|
|||
}
|
||||
|
||||
impl SourceSpan {
|
||||
/// Create a new [SourceSpan].
|
||||
/// Create a new [`SourceSpan`].
|
||||
pub fn new(start: SourceOffset, length: SourceOffset) -> Self {
|
||||
Self {
|
||||
offset: start,
|
||||
|
|
@ -362,17 +362,17 @@ impl SourceSpan {
|
|||
}
|
||||
}
|
||||
|
||||
/// The absolute offset, in bytes, from the beginning of a [SourceCode].
|
||||
/// The absolute offset, in bytes, from the beginning of a [`SourceCode`].
|
||||
pub fn offset(&self) -> usize {
|
||||
self.offset.offset()
|
||||
}
|
||||
|
||||
/// Total length of the [SourceSpan], in bytes.
|
||||
/// Total length of the [`SourceSpan`], in bytes.
|
||||
pub fn len(&self) -> usize {
|
||||
self.length.offset()
|
||||
}
|
||||
|
||||
/// Whether this [SourceSpan] has a length of zero. It may still be useful
|
||||
/// Whether this [`SourceSpan`] has a length of zero. It may still be useful
|
||||
/// to point to a specific point.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.length.offset() == 0
|
||||
|
|
@ -407,12 +407,12 @@ impl From<std::ops::Range<ByteOffset>> for SourceSpan {
|
|||
}
|
||||
|
||||
/**
|
||||
"Raw" type for the byte offset from the beginning of a [SourceCode].
|
||||
"Raw" type for the byte offset from the beginning of a [`SourceCode`].
|
||||
*/
|
||||
pub type ByteOffset = usize;
|
||||
|
||||
/**
|
||||
Newtype that represents the [ByteOffset] from the beginning of a [SourceCode]
|
||||
Newtype that represents the [`ByteOffset`] from the beginning of a [`SourceCode`]
|
||||
*/
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct SourceOffset(ByteOffset);
|
||||
|
|
@ -453,7 +453,7 @@ impl SourceOffset {
|
|||
/// function's caller with `#[track_caller]` (and so on and so forth).
|
||||
///
|
||||
/// Returns both the filename that was given and the offset of the caller
|
||||
/// as a SourceOffset
|
||||
/// as a [`SourceOffset`].
|
||||
///
|
||||
/// Keep in mind that this fill only work if the file your Rust source
|
||||
/// file was compiled from is actually available at that location. If
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*!
|
||||
Default trait implementations for [SourceCode].
|
||||
Default trait implementations for [`SourceCode`].
|
||||
*/
|
||||
use std::{
|
||||
borrow::{Cow, ToOwned},
|
||||
|
|
@ -172,8 +172,11 @@ impl<T: SourceCode> SourceCode for Arc<T> {
|
|||
|
||||
impl<T: ?Sized + SourceCode + ToOwned> SourceCode for Cow<'_, T>
|
||||
where
|
||||
// The minimal bounds are used here. `T::Owned` need not be `SourceCode`,
|
||||
// because `&T` can always be obtained from `Cow<'_, T>`.
|
||||
// The minimal bounds are used here.
|
||||
// `T::Owned` need not be
|
||||
// `SourceCode`, because `&T`
|
||||
// can always be obtained from
|
||||
// `Cow<'_, T>`.
|
||||
T::Owned: Debug + Send + Sync,
|
||||
{
|
||||
fn read_span<'a>(
|
||||
|
|
|
|||
|
|
@ -652,7 +652,8 @@ fn multiple_multiline_highlights_adjacent() -> Result<(), MietteError> {
|
|||
}
|
||||
|
||||
#[test]
|
||||
// TODO: This breaks because those highlights aren't "truly" overlapping (in absolute byte offset), but they ARE overlapping in lines. Need to detect the latter case better
|
||||
// TODO: This breaks because those highlights aren't "truly" overlapping (in absolute byte offset),
|
||||
// but they ARE overlapping in lines. Need to detect the latter case better
|
||||
#[ignore]
|
||||
/// Lines are overlapping, but the offsets themselves aren't, so they _look_
|
||||
/// disjunct if you only look at offsets.
|
||||
|
|
|
|||
|
|
@ -481,7 +481,8 @@ diagnostic code: oops::my::bad
|
|||
}
|
||||
|
||||
#[test]
|
||||
// TODO: This breaks because those highlights aren't "truly" overlapping (in absolute byte offset), but they ARE overlapping in lines. Need to detect the latter case better
|
||||
// TODO: This breaks because those highlights aren't "truly" overlapping (in absolute byte offset),
|
||||
// but they ARE overlapping in lines. Need to detect the latter case better
|
||||
#[ignore]
|
||||
/// Lines are overlapping, but the offsets themselves aren't, so they _look_
|
||||
/// disjunct if you only look at offsets.
|
||||
|
|
|
|||
Loading…
Reference in New Issue