mirror of https://github.com/zkat/miette.git
feat(printer): rename default printer and consistify some naming conventions with printing
BREAKING CHANGE: This is a significant API break.
This commit is contained in:
parent
e980b72373
commit
aafa4a3de1
|
|
@ -8,34 +8,52 @@ use crate::protocol::{Diagnostic, DiagnosticReportPrinter, DiagnosticSnippet, Se
|
||||||
use crate::{SourceSpan, SpanContents};
|
use crate::{SourceSpan, SpanContents};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reference implementation of the [DiagnosticReportPrinter] trait. This is generally
|
A [DiagnosticReportPrinter] that displays a given [crate::DiagnosticReport] in a quasi-graphical way, using terminal colors, unicode drawing characters, and other such things.
|
||||||
good enough for simple use-cases, and is the default one installed with `miette`,
|
|
||||||
but you might want to implement your own if you want custom reporting for your
|
This is the default reporter bundled with `miette`.
|
||||||
tool or app.
|
|
||||||
|
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!)
|
||||||
|
|
||||||
|
See [crate::set_printer] for more details on customizing your global printer.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```
|
||||||
|
use miette::{GraphicalReportPrinter, GraphicalTheme};
|
||||||
|
miette::set_printer(GraphicalReportPrinter::new_themed(GraphicalTheme::unicode_nocolor()));
|
||||||
|
```
|
||||||
*/
|
*/
|
||||||
pub struct DefaultReportPrinter {
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) theme: MietteTheme,
|
pub struct GraphicalReportPrinter {
|
||||||
|
pub(crate) theme: GraphicalTheme,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefaultReportPrinter {
|
impl GraphicalReportPrinter {
|
||||||
|
/// Create a new [GraphicalReportPrinter] with the default
|
||||||
|
/// [GraphicalTheme]. This will use both unicode characters and colors.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
theme: MietteTheme::default(),
|
theme: GraphicalTheme::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_themed(theme: MietteTheme) -> Self {
|
///Create a new [GraphicalReportPrinter] with a given [GraphicalTheme].
|
||||||
|
pub fn new_themed(theme: GraphicalTheme) -> Self {
|
||||||
Self { theme }
|
Self { theme }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DefaultReportPrinter {
|
impl Default for GraphicalReportPrinter {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefaultReportPrinter {
|
impl GraphicalReportPrinter {
|
||||||
|
/// Render a [Diagnostic]. This function is mostly internal and meant to
|
||||||
|
/// be called by the toplevel [DiagnosticReportPrinter] handler, but is
|
||||||
|
/// made public to make it easier (possible) to test in isolation from
|
||||||
|
/// global state.
|
||||||
pub fn render_report(
|
pub fn render_report(
|
||||||
&self,
|
&self,
|
||||||
f: &mut impl fmt::Write,
|
f: &mut impl fmt::Write,
|
||||||
|
|
@ -116,7 +134,7 @@ impl DefaultReportPrinter {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_snippet(&self, f: &mut impl fmt::Write, snippet: &DiagnosticSnippet) -> fmt::Result {
|
fn render_snippet(&self, f: &mut impl fmt::Write, snippet: &DiagnosticSnippet<'_>) -> fmt::Result {
|
||||||
let (contents, lines) = self.get_lines(snippet)?;
|
let (contents, lines) = self.get_lines(snippet)?;
|
||||||
|
|
||||||
// Highlights are the bits we're going to underline in our overall
|
// Highlights are the bits we're going to underline in our overall
|
||||||
|
|
@ -408,7 +426,7 @@ impl DefaultReportPrinter {
|
||||||
|
|
||||||
fn get_lines<'a>(
|
fn get_lines<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
snippet: &'a DiagnosticSnippet,
|
snippet: &'a DiagnosticSnippet<'_>,
|
||||||
) -> Result<(Box<dyn SpanContents + 'a>, Vec<Line>), fmt::Error> {
|
) -> Result<(Box<dyn SpanContents + 'a>, Vec<Line>), fmt::Error> {
|
||||||
let context_data = snippet
|
let context_data = snippet
|
||||||
.source
|
.source
|
||||||
|
|
@ -463,7 +481,7 @@ impl DefaultReportPrinter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiagnosticReportPrinter for DefaultReportPrinter {
|
impl DiagnosticReportPrinter for GraphicalReportPrinter {
|
||||||
fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
return fmt::Debug::fmt(diagnostic, f);
|
return fmt::Debug::fmt(diagnostic, f);
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
/*!
|
/*!
|
||||||
Basic reporter for Diagnostics. Probably good enough for most use-cases,
|
Reporters included with `miette`.
|
||||||
but largely meant to be an example.
|
|
||||||
*/
|
*/
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
|
@ -10,11 +9,11 @@ use once_cell::sync::OnceCell;
|
||||||
use crate::protocol::{Diagnostic, DiagnosticReportPrinter, Severity};
|
use crate::protocol::{Diagnostic, DiagnosticReportPrinter, Severity};
|
||||||
use crate::MietteError;
|
use crate::MietteError;
|
||||||
|
|
||||||
pub use default_printer::*;
|
pub use graphical_printer::*;
|
||||||
pub use narratable_printer::*;
|
pub use narratable_printer::*;
|
||||||
pub use theme::*;
|
pub use theme::*;
|
||||||
|
|
||||||
mod default_printer;
|
mod graphical_printer;
|
||||||
mod narratable_printer;
|
mod narratable_printer;
|
||||||
mod theme;
|
mod theme;
|
||||||
|
|
||||||
|
|
@ -22,8 +21,8 @@ static REPORTER: OnceCell<Box<dyn DiagnosticReportPrinter + Send + Sync + 'stati
|
||||||
OnceCell::new();
|
OnceCell::new();
|
||||||
|
|
||||||
/// Set the global [DiagnosticReportPrinter] that will be used when you report
|
/// Set the global [DiagnosticReportPrinter] that will be used when you report
|
||||||
/// using [DiagnosticReport].
|
/// using [crate::DiagnosticReport].
|
||||||
pub fn set_reporter(
|
pub fn set_printer(
|
||||||
reporter: impl DiagnosticReportPrinter + Send + Sync + 'static,
|
reporter: impl DiagnosticReportPrinter + Send + Sync + 'static,
|
||||||
) -> Result<(), MietteError> {
|
) -> Result<(), MietteError> {
|
||||||
REPORTER
|
REPORTER
|
||||||
|
|
@ -31,9 +30,9 @@ pub fn set_reporter(
|
||||||
.map_err(|_| MietteError::SetPrinterFailure)
|
.map_err(|_| MietteError::SetPrinterFailure)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used by [DiagnosticReport] to fetch the reporter that will be used to
|
/// Used by [crate::DiagnosticReport] to fetch the reporter that will be used to
|
||||||
/// print stuff out.
|
/// print stuff out.
|
||||||
pub fn get_reporter() -> &'static (dyn DiagnosticReportPrinter + Send + Sync + 'static) {
|
pub(crate) fn get_printer() -> &'static (dyn DiagnosticReportPrinter + Send + Sync + 'static) {
|
||||||
&**REPORTER.get_or_init(get_default_printer)
|
&**REPORTER.get_or_init(get_default_printer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,8 +45,8 @@ fn get_default_printer() -> Box<dyn DiagnosticReportPrinter + Send + Sync + 'sta
|
||||||
atty::is(Stream::Stdout) && atty::is(Stream::Stderr) && !ci_info::is_ci()
|
atty::is(Stream::Stdout) && atty::is(Stream::Stderr) && !ci_info::is_ci()
|
||||||
};
|
};
|
||||||
if fancy {
|
if fancy {
|
||||||
Box::new(DefaultReportPrinter {
|
Box::new(GraphicalReportPrinter {
|
||||||
theme: MietteTheme::default(),
|
theme: GraphicalTheme::default(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Box::new(NarratableReportPrinter)
|
Box::new(NarratableReportPrinter)
|
||||||
|
|
@ -55,9 +54,9 @@ fn get_default_printer() -> Box<dyn DiagnosticReportPrinter + Send + Sync + 'sta
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Literally what it says on the tin.
|
/// Literally what it says on the tin.
|
||||||
pub struct JokeReporter;
|
pub struct JokePrinter;
|
||||||
|
|
||||||
impl DiagnosticReportPrinter for JokeReporter {
|
impl DiagnosticReportPrinter for JokePrinter {
|
||||||
fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn debug(&self, diagnostic: &(dyn Diagnostic), f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
return fmt::Debug::fmt(diagnostic, f);
|
return fmt::Debug::fmt(diagnostic, f);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ good enough for simple use-cases, and is the default one installed with `miette`
|
||||||
but you might want to implement your own if you want custom reporting for your
|
but you might want to implement your own if you want custom reporting for your
|
||||||
tool or app.
|
tool or app.
|
||||||
*/
|
*/
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct NarratableReportPrinter;
|
pub struct NarratableReportPrinter;
|
||||||
|
|
||||||
impl NarratableReportPrinter {
|
impl NarratableReportPrinter {
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,91 @@
|
||||||
use atty::Stream;
|
use atty::Stream;
|
||||||
use owo_colors::Style;
|
use owo_colors::Style;
|
||||||
|
|
||||||
pub struct MietteTheme {
|
/**
|
||||||
pub characters: MietteCharacters,
|
Theme used by [crate::GraphicalReportPrinter] to render fancy [crate::Diagnostic] reports.
|
||||||
pub styles: MietteStyles,
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
You can create your own custom graphical theme using this type, or you can use
|
||||||
|
one of the predefined ones using the methods below.
|
||||||
|
*/
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct GraphicalTheme {
|
||||||
|
/// Characters to be used for drawing.
|
||||||
|
pub characters: ThemeCharacters,
|
||||||
|
/// Styles to be used for painting.
|
||||||
|
pub styles: ThemeStyles,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MietteTheme {
|
impl GraphicalTheme {
|
||||||
pub fn basic() -> Self {
|
/// ASCII-art-based graphical drawing, with ANSI styling.
|
||||||
|
pub fn ascii() -> Self {
|
||||||
Self {
|
Self {
|
||||||
characters: MietteCharacters::ascii(),
|
characters: ThemeCharacters::ascii(),
|
||||||
styles: MietteStyles::ansi(),
|
styles: ThemeStyles::ansi(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Graphical theme that draws using both ansi colors and unicode characters.
|
||||||
pub fn unicode() -> Self {
|
pub fn unicode() -> Self {
|
||||||
Self {
|
Self {
|
||||||
characters: MietteCharacters::unicode(),
|
characters: ThemeCharacters::unicode(),
|
||||||
styles: MietteStyles::ansi(),
|
styles: ThemeStyles::ansi(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Graphical theme that draws in monochrome, while still using unicode
|
||||||
|
/// characters.
|
||||||
pub fn unicode_nocolor() -> Self {
|
pub fn unicode_nocolor() -> Self {
|
||||||
Self {
|
Self {
|
||||||
characters: MietteCharacters::unicode(),
|
characters: ThemeCharacters::unicode(),
|
||||||
styles: MietteStyles::none(),
|
styles: ThemeStyles::none(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A "basic" graphical theme that skips colors and unicode characters and
|
||||||
|
/// just does monochrome ascii art. If you want a completely non-graphical
|
||||||
|
/// rendering of your `Diagnostic`s, check out
|
||||||
|
/// [crate::NarratableReportPrinter], or write your own
|
||||||
|
/// [crate::DiagnosticReportPrinter]!
|
||||||
pub fn none() -> Self {
|
pub fn none() -> Self {
|
||||||
Self {
|
Self {
|
||||||
characters: MietteCharacters::ascii(),
|
characters: ThemeCharacters::ascii(),
|
||||||
styles: MietteStyles::none(),
|
styles: ThemeStyles::none(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MietteTheme {
|
impl Default for GraphicalTheme {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
match std::env::var("NO_COLOR") {
|
match std::env::var("NO_COLOR") {
|
||||||
_ if !atty::is(Stream::Stdout) || !atty::is(Stream::Stderr) => Self::basic(),
|
_ if !atty::is(Stream::Stdout) || !atty::is(Stream::Stderr) => Self::ascii(),
|
||||||
Ok(string) if string != "0" => Self::unicode_nocolor(),
|
Ok(string) if string != "0" => Self::unicode_nocolor(),
|
||||||
_ => Self::unicode(),
|
_ => Self::unicode(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MietteStyles {
|
/**
|
||||||
|
Styles for various parts of graphical rendering for the [crate::GraphicalReportPrinter].
|
||||||
|
*/
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ThemeStyles {
|
||||||
|
/// Style to apply to things highlighted as "error".
|
||||||
pub error: Style,
|
pub error: Style,
|
||||||
|
/// Style to apply to things highlighted as "warning".
|
||||||
pub warning: Style,
|
pub warning: Style,
|
||||||
|
/// Style to apply to things highlighted as "advice".
|
||||||
pub advice: Style,
|
pub advice: Style,
|
||||||
|
/// Style to apply to the diagnostic code.
|
||||||
pub code: Style,
|
pub code: Style,
|
||||||
|
/// Style to apply to the help text.
|
||||||
pub help: Style,
|
pub help: Style,
|
||||||
|
/// Style to apply to the filename/source name.
|
||||||
pub filename: Style,
|
pub filename: Style,
|
||||||
|
/// Styles to cycle through (using `.iter().cycle()`), to render the lines
|
||||||
|
/// and text for diagnostic highlights.
|
||||||
pub highlights: Vec<Style>,
|
pub highlights: Vec<Style>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,7 +93,8 @@ fn style() -> Style {
|
||||||
Style::new()
|
Style::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MietteStyles {
|
impl ThemeStyles {
|
||||||
|
/// ANSI color-based styles.
|
||||||
pub fn ansi() -> Self {
|
pub fn ansi() -> Self {
|
||||||
Self {
|
Self {
|
||||||
error: style().red(),
|
error: style().red(),
|
||||||
|
|
@ -74,6 +111,7 @@ impl MietteStyles {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// No styling. Just regular ol' monochrome.
|
||||||
pub fn none() -> Self {
|
pub fn none() -> Self {
|
||||||
Self {
|
Self {
|
||||||
error: style(),
|
error: style(),
|
||||||
|
|
@ -88,9 +126,13 @@ impl MietteStyles {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
// All code below here was taken from ariadne here:
|
// Most of these characters were taken from
|
||||||
// https://github.com/zesterer/ariadne/blob/e3cb394cb56ecda116a0a1caecd385a49e7f6662/src/draw.rs
|
// https://github.com/zesterer/ariadne/blob/e3cb394cb56ecda116a0a1caecd385a49e7f6662/src/draw.rs
|
||||||
pub struct MietteCharacters {
|
|
||||||
|
/// Characters to be used when drawing when using [crate::GraphicalReportPrinter].
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct ThemeCharacters {
|
||||||
pub hbar: char,
|
pub hbar: char,
|
||||||
pub vbar: char,
|
pub vbar: char,
|
||||||
pub xbar: char,
|
pub xbar: char,
|
||||||
|
|
@ -121,7 +163,8 @@ pub struct MietteCharacters {
|
||||||
pub point_right: char,
|
pub point_right: char,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MietteCharacters {
|
impl ThemeCharacters {
|
||||||
|
/// Fancy unicode-based graphical elements.
|
||||||
pub fn unicode() -> Self {
|
pub fn unicode() -> Self {
|
||||||
Self {
|
Self {
|
||||||
hbar: '─',
|
hbar: '─',
|
||||||
|
|
@ -149,6 +192,7 @@ impl MietteCharacters {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ASCII-art-based graphical elements. Works well on older terminals.
|
||||||
pub fn ascii() -> Self {
|
pub fn ascii() -> Self {
|
||||||
Self {
|
Self {
|
||||||
hbar: '-',
|
hbar: '-',
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use miette::{
|
use miette::{
|
||||||
DefaultReportPrinter, Diagnostic, DiagnosticReport, MietteError, MietteTheme,
|
GraphicalReportPrinter, Diagnostic, DiagnosticReport, MietteError, GraphicalTheme,
|
||||||
NarratableReportPrinter, SourceSpan,
|
NarratableReportPrinter, SourceSpan,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
@ -8,7 +8,7 @@ fn fmt_report(diag: DiagnosticReport) -> String {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
// Mostly for dev purposes.
|
// Mostly for dev purposes.
|
||||||
if std::env::var("STYLE").is_ok() {
|
if std::env::var("STYLE").is_ok() {
|
||||||
DefaultReportPrinter::new_themed(MietteTheme::unicode())
|
GraphicalReportPrinter::new_themed(GraphicalTheme::unicode())
|
||||||
.render_report(&mut out, diag.inner())
|
.render_report(&mut out, diag.inner())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use miette::{
|
use miette::{
|
||||||
DefaultReportPrinter, Diagnostic, DiagnosticReport, MietteError, MietteTheme,
|
GraphicalReportPrinter, Diagnostic, DiagnosticReport, MietteError, GraphicalTheme,
|
||||||
NarratableReportPrinter, SourceSpan,
|
NarratableReportPrinter, SourceSpan,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
@ -8,7 +8,7 @@ fn fmt_report(diag: DiagnosticReport) -> String {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
// Mostly for dev purposes.
|
// Mostly for dev purposes.
|
||||||
if std::env::var("STYLE").is_ok() {
|
if std::env::var("STYLE").is_ok() {
|
||||||
DefaultReportPrinter::new_themed(MietteTheme::unicode())
|
GraphicalReportPrinter::new_themed(GraphicalTheme::unicode())
|
||||||
.render_report(&mut out, diag.inner())
|
.render_report(&mut out, diag.inner())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else if std::env::var("NARRATED").is_ok() {
|
} else if std::env::var("NARRATED").is_ok() {
|
||||||
|
|
@ -16,7 +16,7 @@ fn fmt_report(diag: DiagnosticReport) -> String {
|
||||||
.render_report(&mut out, diag.inner())
|
.render_report(&mut out, diag.inner())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
DefaultReportPrinter::new_themed(MietteTheme::unicode_nocolor())
|
GraphicalReportPrinter::new_themed(GraphicalTheme::unicode_nocolor())
|
||||||
.render_report(&mut out, diag.inner())
|
.render_report(&mut out, diag.inner())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue