From b65e8397de2dcefaf824d912714f0d2190dbf316 Mon Sep 17 00:00:00 2001 From: Boshen Date: Sun, 26 Mar 2023 21:20:54 +0800 Subject: [PATCH] feat(diagnostics): change color displays related #203 --- Cargo.lock | 1 + crates/oxc_cli/src/main.rs | 6 - crates/oxc_diagnostics/Cargo.toml | 1 + .../oxc_diagnostics/src/graphic_reporter.rs | 36 +-- crates/oxc_diagnostics/src/graphical_theme.rs | 258 ++++++++++++++++++ crates/oxc_diagnostics/src/lib.rs | 1 + 6 files changed, 275 insertions(+), 28 deletions(-) create mode 100644 crates/oxc_diagnostics/src/graphical_theme.rs diff --git a/Cargo.lock b/Cargo.lock index 4a9badc60..c21933d3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -910,6 +910,7 @@ dependencies = [ name = "oxc_diagnostics" version = "0.0.0" dependencies = [ + "is-terminal", "miette", "owo-colors", "oxc_ast", diff --git a/crates/oxc_cli/src/main.rs b/crates/oxc_cli/src/main.rs index fc4474dcd..bdfd9bacc 100644 --- a/crates/oxc_cli/src/main.rs +++ b/crates/oxc_cli/src/main.rs @@ -9,14 +9,8 @@ static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc; static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use oxc_cli::{command, CliRunResult, LintOptions, LintRunner}; -use oxc_diagnostics::miette; fn main() -> CliRunResult { - // convert source code with hard tabs into 4 spaces, - // otherwise error label spans will have a wrong offset. - miette::set_hook(Box::new(|_| Box::new(miette::MietteHandlerOpts::new().tab_width(4).build()))) - .unwrap(); - let matches = command().get_matches(); let Some((subcommand, matches)) = matches.subcommand() else { return CliRunResult::None diff --git a/crates/oxc_diagnostics/Cargo.toml b/crates/oxc_diagnostics/Cargo.toml index 4a23203f7..702cdd933 100644 --- a/crates/oxc_diagnostics/Cargo.toml +++ b/crates/oxc_diagnostics/Cargo.toml @@ -18,3 +18,4 @@ miette = { workspace = true } unicode-width = "0.1.10" owo-colors = { version = "3.5.0" } textwrap = { version = "0.16.0" } +is-terminal = { version = "0.4.0" } diff --git a/crates/oxc_diagnostics/src/graphic_reporter.rs b/crates/oxc_diagnostics/src/graphic_reporter.rs index 8b952e6e2..2d259c23e 100644 --- a/crates/oxc_diagnostics/src/graphic_reporter.rs +++ b/crates/oxc_diagnostics/src/graphic_reporter.rs @@ -3,19 +3,19 @@ #![allow(clippy::nursery)] #![allow(dead_code)] -/** - * origin file: https://github.com/zkat/miette/blob/78fe18e6990feacc8bdaeeb10e1439a12c111e6e/src/handlers/graphical.rs - */ +/// origin file: https://github.com/zkat/miette/blob/78fe18e6990feacc8bdaeeb10e1439a12c111e6e/src/handlers/graphical.rs use std::fmt::{self, Write}; // use miette::diagnostic_chain::DiagnosticChain; use miette::{ - Diagnostic, GraphicalTheme, LabeledSpan, MietteError, ReportHandler, Severity, SourceCode, - SourceSpan, SpanContents, + Diagnostic, LabeledSpan, MietteError, ReportHandler, Severity, SourceCode, SourceSpan, + SpanContents, }; use owo_colors::{OwoColorize, Style}; use unicode_width::UnicodeWidthChar; +use crate::graphical_theme::GraphicalTheme; + /** A [`ReportHandler`] that displays a given [`Report`](crate::Report) in a quasi-graphical way, using terminal colors, unicode drawing characters, and @@ -43,6 +43,9 @@ pub(crate) enum LinkStyle { Link, Text, } +fn style() -> Style { + Style::new() +} impl GraphicalReportHandler { /// Create a new `GraphicalReportHandler` with the default @@ -50,7 +53,7 @@ impl GraphicalReportHandler { pub fn new() -> Self { Self { links: LinkStyle::Link, - termwidth: 200, + termwidth: 600, // Changed: origin: 200 theme: GraphicalTheme::default(), footer: None, context_lines: 1, @@ -59,19 +62,6 @@ impl GraphicalReportHandler { } } - ///Create a new `GraphicalReportHandler` with a given [`GraphicalTheme`]. - pub fn new_themed(theme: GraphicalTheme) -> Self { - Self { - links: LinkStyle::Link, - termwidth: 200, - theme, - footer: None, - context_lines: 1, - tab_width: 4, - with_cause_chain: true, - } - } - /// Set the displayed tab width in spaces. pub fn tab_width(mut self, width: usize) -> Self { self.tab_width = width; @@ -214,7 +204,9 @@ impl GraphicalReportHandler { .initial_indent(&initial_indent) .subsequent_indent(&rest_indent); - writeln!(f, "{}", textwrap::fill(&diagnostic.to_string(), opts))?; + let title = format!("{}", diagnostic.to_string().style(severity_style)); + let title = textwrap::fill(&title, opts); + writeln!(f, "{}", title)?; // CHANGED: REMOVED // if !self.with_cause_chain { @@ -361,10 +353,10 @@ impl GraphicalReportHandler { Ok(()) } - fn render_context<'a>( + fn render_context( &self, f: &mut impl fmt::Write, - source: &'a dyn SourceCode, + source: &dyn SourceCode, context: &LabeledSpan, labels: &[LabeledSpan], ) -> fmt::Result { diff --git a/crates/oxc_diagnostics/src/graphical_theme.rs b/crates/oxc_diagnostics/src/graphical_theme.rs new file mode 100644 index 000000000..9338825a6 --- /dev/null +++ b/crates/oxc_diagnostics/src/graphical_theme.rs @@ -0,0 +1,258 @@ +#![allow(clippy::must_use_candidate)] +#![allow(clippy::pedantic)] +#![allow(clippy::nursery)] +#![allow(dead_code)] + +/// origin file: https://github.com/zkat/miette/blob/78fe18e6990feacc8bdaeeb10e1439a12c111e6e/src/handlers/theme.rs +use is_terminal::IsTerminal; +use owo_colors::{style, Style}; + +/** +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`](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. +*/ +#[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 GraphicalTheme { + /// ASCII-art-based graphical drawing, with ANSI styling. + pub fn ascii() -> Self { + Self { characters: ThemeCharacters::ascii(), styles: ThemeStyles::ansi() } + } + + /// Graphical theme that draws using both ansi colors and unicode + /// characters. + pub fn unicode() -> Self { + Self { characters: ThemeCharacters::unicode(), styles: ThemeStyles::rgb() } + } + + /// Graphical theme that draws in monochrome, while still using unicode + /// characters. + pub fn unicode_nocolor() -> Self { + Self { characters: ThemeCharacters::unicode(), 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::NarratableReportHandler], or write your own + /// [crate::ReportHandler]! + pub fn none() -> Self { + Self { characters: ThemeCharacters::ascii(), styles: ThemeStyles::none() } + } +} + +impl Default for GraphicalTheme { + fn default() -> Self { + match std::env::var("NO_COLOR") { + _ if !std::io::stdout().is_terminal() || !std::io::stderr().is_terminal() => { + Self::ascii() + } + Ok(string) if string != "0" => Self::unicode_nocolor(), + _ => Self::unicode(), + } + } +} + +/** +Styles for various parts of graphical rendering for the [crate::GraphicalReportHandler]. +*/ +#[derive(Debug, Clone)] +pub struct ThemeStyles { + /// Style to apply to things highlighted as "error". + pub error: Style, + /// Style to apply to things highlighted as "warning". + pub warning: Style, + /// Style to apply to things highlighted as "advice". + pub advice: Style, + /// Style to apply to the help text. + pub help: Style, + /// Style to apply to filenames/links/URLs. + pub link: Style, + /// Style to apply to line numbers. + pub linum: Style, + /// Styles to cycle through (using `.iter().cycle()`), to render the lines + /// and text for diagnostic highlights. + pub highlights: Vec