From 33c8edf47bb4a6cbb91ead2e9781b30123be2c74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20J=2E=20S=C3=A1nchez?= Date: Sat, 27 Jul 2024 01:57:02 +0200 Subject: [PATCH 1/8] swap ariadne for codesnake --- Cargo.lock | 23 ++++---- Cargo.toml | 3 +- src/error.rs | 148 ++++++++++++++++++++++++--------------------------- src/span.rs | 45 +--------------- 4 files changed, 84 insertions(+), 135 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 17ccc57..7eb3edd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,16 +45,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" -[[package]] -name = "ariadne" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd002a6223f12c7a95cdd4b1cb3a0149d22d37f7a9ecdb2cb691a071fe236c29" -dependencies = [ - "unicode-width", - "yansi", -] - [[package]] name = "askama" version = "0.12.1" @@ -256,12 +246,18 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +[[package]] +name = "codesnake" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdbcda08384319005fd4b79b08aa04728dbafa702d304d737b5ccbd556df331" + [[package]] name = "cooklang" version = "0.13.2" dependencies = [ - "ariadne", "bitflags", + "codesnake", "criterion", "either", "emojis", @@ -284,6 +280,7 @@ dependencies = [ "tracing", "unicase", "url", + "yansi", ] [[package]] @@ -1702,6 +1699,6 @@ dependencies = [ [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/Cargo.toml b/Cargo.toml index 2affd22..9fbfa6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,11 +25,12 @@ toml = { version = "0.8", optional = true } once_cell = "1" enum-map = { version = "2", features = ["serde"] } tracing = "0.1" -ariadne = "0.4" +codesnake = "0.1.0" either = "1.8" finl_unicode = { version = "1.2", features = ["categories"], default-features = false } smallvec = { version = "1" } unicase = "2.7.0" +yansi = "1.0.1" [dev-dependencies] serde_json = "1" diff --git a/src/error.rs b/src/error.rs index 6048c46..d55941e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -308,13 +308,13 @@ impl SourceReport { color: bool, w: &mut impl std::io::Write, ) -> std::io::Result<()> { - let mut cache = DummyCache::new(file_name, source_code); + let lidx = codesnake::LineIndex::new(source_code); for err in self.warnings() { - build_report(err, file_name, source_code, color).write(&mut cache, &mut *w)?; + write_report(&mut *w, err, &lidx, file_name, color)?; } for err in self.errors() { - build_report(err, file_name, source_code, color).write(&mut cache, &mut *w)?; + write_report(&mut *w, err, &lidx, file_name, color)?; } Ok(()) } @@ -454,107 +454,101 @@ pub fn write_rich_error( color: bool, w: impl std::io::Write, ) -> std::io::Result<()> { - let mut cache = DummyCache::new(file_name, source_code); - let report = build_report(error, file_name, source_code, color); - report.write(&mut cache, w) + let lidx = codesnake::LineIndex::new(source_code); + write_report(w, error, &lidx, file_name, color) } -fn build_report<'a>( +#[derive(Default)] +struct ColorGenerator(usize); + +impl ColorGenerator { + const COLORS: &'static [yansi::Color] = &[ + yansi::Color::BrightMagenta, + yansi::Color::BrightGreen, + yansi::Color::BrightCyan, + yansi::Color::BrightBlue, + yansi::Color::BrightGreen, + yansi::Color::BrightYellow, + yansi::Color::BrightRed, + ]; + + fn next(&mut self) -> yansi::Color { + let c = Self::COLORS[self.0]; + if self.0 == Self::COLORS.len() - 1 { + self.0 = 0; + } else { + self.0 += 1; + } + c + } +} + +fn write_report<'a>( + mut w: impl std::io::Write, err: &'a dyn RichError, + lidx: &codesnake::LineIndex, file_name: &str, - src_code: &str, - color: bool, -) -> ariadne::Report<'a> { - use ariadne::{Color, ColorGenerator, Fmt, Label, Report}; + _color: bool, +) -> std::io::Result<()> { + use yansi::Paint; + + let mut cg = ColorGenerator::default(); let labels = err.labels(); - let labels = labels - .iter() - .map(|(s, t)| (s.to_chars_span(src_code, file_name).range(), t)) - .collect::>(); + let mut colored_labels = Vec::with_capacity(labels.len()); + for (s, t) in labels.iter() { + let color = cg.next(); + let l = codesnake::Label::new(s.range(), t.clone().unwrap_or("".into())) + .with_style(move |s| s.paint(color).to_string()); + colored_labels.push(l); + } - // The start of the first span - let offset = labels.first().map(|l| l.0.start).unwrap_or_default(); + let block = codesnake::Block::new(&lidx, colored_labels).expect("invalid report spans"); - let kind = match err.severity() { - Severity::Error => ariadne::ReportKind::Error, - Severity::Warning => ariadne::ReportKind::Warning, + let sev_color = match err.severity() { + Severity::Error => yansi::Color::Red, + Severity::Warning => yansi::Color::Yellow, }; + match err.severity() { + Severity::Error => writeln!(w, "{} {err}", "Error:".paint(sev_color))?, + Severity::Warning => writeln!(w, "{} {err}", "Warning: ".paint(sev_color))?, + } + if let Some(source) = err.source() { + writeln!(w, " {} {source}", "╰▶ ".paint(sev_color))?; + } - let mut r = - Report::build(kind, (), offset).with_config(ariadne::Config::default().with_color(color)); + let block = block.map_code(|c| codesnake::CodeWidth::new(c, c.len())); - if let Some(source) = err.source() { - let arrow_color = if color { - match kind { - ariadne::ReportKind::Error => Color::Red, - ariadne::ReportKind::Warning => Color::Yellow, - ariadne::ReportKind::Advice => Color::Fixed(147), - ariadne::ReportKind::Custom(_, c) => c, - } - } else { - Color::Default - }; - let message = format!("{err}\n {} {source}", "╰▶ ".fg(arrow_color)); - r.set_message(message); - } else { - r.set_message(err); - } - - let mut c = ColorGenerator::new(); - r.add_labels(labels.into_iter().enumerate().map(|(order, (span, text))| { - let mut l = Label::new(span) - .with_order(order as i32) - .with_color(c.next()); - if let Some(text) = text { - l = l.with_message(text); - } - l - })); + writeln!( + w, + "{}{}{}{}", + block.prologue(), + "[".dim(), + file_name, + "]".dim() + )?; + write!(w, "{block}")?; + writeln!(w, "{}", block.epilogue())?; let hints = err.hints(); let mut hints = hints.iter(); if let Some(help) = hints.next() { - r.set_help(help); + writeln!(w, "{} {}", "Help:".green(), help)?; } if let Some(note) = hints.next() { - r.set_note(note); + writeln!(w, "{} {}", "Note:".green(), note)?; } #[cfg(debug_assertions)] if hints.next().is_some() { tracing::warn!( hints = ?err.hints(), - "this function only supports 2 hints, more will be ignored", + "the report builder only supports 2 hints, more will be ignored", ); } - - r.finish() -} - -// This is a ariadne cache that only supports one file. -// If needed it can be expanded to a full cache as the source id is already -// stored in CharsSpan (the ariadne::Span) -struct DummyCache<'a>(String, ariadne::Source<&'a str>); -impl<'a> DummyCache<'a> { - fn new(file_name: &str, src_code: &'a str) -> Self { - Self(file_name.into(), ariadne::Source::from(src_code)) - } -} -impl<'s> ariadne::Cache<()> for DummyCache<'s> { - type Storage = &'s str; - fn fetch( - &mut self, - _id: &(), - ) -> Result<&ariadne::Source, Box> { - Ok(&self.1) - } - - fn display<'a>(&self, _id: &'a ()) -> Option> { - Some(Box::new(self.0.clone())) - } + Ok(()) } /// Like [`Default`] but for situations where a default value does not make sense diff --git a/src/span.rs b/src/span.rs index 5519e23..831e333 100644 --- a/src/span.rs +++ b/src/span.rs @@ -1,6 +1,6 @@ //! Utility to represent a location in the source code -use std::ops::{Deref, Range}; +use std::ops::Range; /// Location in the source code /// @@ -56,30 +56,6 @@ impl std::fmt::Debug for Span { } } -impl Span { - pub(crate) fn to_chars_span(self, all_source: &str, source_id: Id) -> CharsSpan { - let start = all_source[..self.start].chars().count(); - let len = all_source[self.range()].chars().count(); - CharsSpan { - span: Span::new(start, start + len), - source_id, - } - } -} - -pub(crate) struct CharsSpan { - span: Span, - source_id: Id, -} - -impl Deref for CharsSpan { - type Target = Span; - - fn deref(&self) -> &Self::Target { - &self.span - } -} - impl From> for Span { fn from(value: Range) -> Self { Self::new(value.start, value.end) @@ -103,22 +79,3 @@ impl crate::error::Recover for Span { Self::new(0, 0) } } - -impl ariadne::Span for CharsSpan -where - Id: ToOwned + PartialEq, -{ - type SourceId = Id; - - fn source(&self) -> &Self::SourceId { - &self.source_id - } - - fn start(&self) -> usize { - self.span.start - } - - fn end(&self) -> usize { - self.span.end - } -} From 8611d53a110b49e35e0ba2275204f7c4d9879cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20J=2E=20S=C3=A1nchez?= Date: Thu, 1 Aug 2024 00:27:53 +0200 Subject: [PATCH 2/8] update example for internal use --- examples/cook.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/cook.rs b/examples/cook.rs index 4613894..798bf0e 100644 --- a/examples/cook.rs +++ b/examples/cook.rs @@ -1,9 +1,11 @@ +use std::io::Read; + fn main() -> Result<(), Box> { let mut args = std::env::args(); let bin = args.next().unwrap(); let in_file = match args.next() { Some(path) => path, - None => panic!("Usage: {bin} [output_file|STDOUT]"), + None => panic!("Usage: {bin} [|STDIN] [output_file|STDOUT]"), }; let out_file: Option> = match args.next().as_deref() { Some("STDOUT") => Some(Box::new(std::io::stdout().lock())), @@ -11,13 +13,20 @@ fn main() -> Result<(), Box> { None => None, }; - let input = std::fs::read_to_string(&in_file)?; + let input = match in_file.as_ref() { + "STDIN" => { + let mut buf = String::new(); + std::io::stdin().lock().read_to_string(&mut buf)?; + buf + } + path => std::fs::read_to_string(path)?, + }; match cooklang::parse(&input).into_result() { Ok((recipe, warnings)) => { warnings.eprint(&in_file, &input, true)?; if let Some(mut out) = out_file { - write!(out, "{:#?}", recipe)?; + writeln!(out, "{:#?}", recipe)?; } } Err(e) => { From 82c87c7131cce4d443f59cd2fdac4c149d84d2cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20J=2E=20S=C3=A1nchez?= Date: Thu, 1 Aug 2024 00:28:42 +0200 Subject: [PATCH 3/8] update codesnake --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- src/error.rs | 12 +++++++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7eb3edd..1dfb13e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,9 +248,9 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "codesnake" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdbcda08384319005fd4b79b08aa04728dbafa702d304d737b5ccbd556df331" +checksum = "458099206fe27887fff34f2f4bfdf482dbe874dd287aba1f068436babb4cac27" [[package]] name = "cooklang" diff --git a/Cargo.toml b/Cargo.toml index 9fbfa6e..91f1d5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ toml = { version = "0.8", optional = true } once_cell = "1" enum-map = { version = "2", features = ["serde"] } tracing = "0.1" -codesnake = "0.1.0" +codesnake = "0.2.0" either = "1.8" finl_unicode = { version = "1.2", features = ["categories"], default-features = false } smallvec = { version = "1" } diff --git a/src/error.rs b/src/error.rs index d55941e..eac9dfa 100644 --- a/src/error.rs +++ b/src/error.rs @@ -494,12 +494,18 @@ fn write_report<'a>( let mut cg = ColorGenerator::default(); - let labels = err.labels(); + let mut labels = err.labels(); + // codesnake requires the labels to be sorted + labels.to_mut().sort_unstable_by_key(|l| l.0); + let mut colored_labels = Vec::with_capacity(labels.len()); for (s, t) in labels.iter() { let color = cg.next(); - let l = codesnake::Label::new(s.range(), t.clone().unwrap_or("".into())) - .with_style(move |s| s.paint(color).to_string()); + let mut l = + codesnake::Label::new(s.range()).with_style(move |s| s.paint(color).to_string()); + if let Some(text) = t { + l = l.with_text(text) + } colored_labels.push(l); } From 8a939ba30525a56a997104035a4d3bbdd7426788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20J=2E=20S=C3=A1nchez?= Date: Thu, 1 Aug 2024 00:29:45 +0200 Subject: [PATCH 4/8] remove/change overlapping spans --- src/parser/section.rs | 3 +-- src/parser/step.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/parser/section.rs b/src/parser/section.rs index a30c34c..a003879 100644 --- a/src/parser/section.rs +++ b/src/parser/section.rs @@ -19,9 +19,8 @@ pub(crate) fn section<'i>(block: &mut BlockParser<'_, 'i>) -> Option> block.warn( warning!( "A section block is invalid and it will be a step", - label!(block.span()), + label!(tokens_span(block.rest()), "remove this"), ) - .label(label!(tokens_span(block.rest()), "remove this")) .hint("After the ending `=` the line must end for it to be a valid section"), ); return None; diff --git a/src/parser/step.rs b/src/parser/step.rs index 739e70d..fa8ba34 100644 --- a/src/parser/step.rs +++ b/src/parser/step.rs @@ -591,7 +591,7 @@ fn check_note(bp: &mut BlockParser, container: &'static str) { format!("A {container} cannot have a note, it will be text"), label!(Span::new(start, end)), ) - .label(label!(Span::pos(start), "add a space here")) + .label(label!(Span::pos(start - 1), "add a space here")) // this at least will be the marker character .hint("Notes are only available in ingredients and cookware items"), ); None::<()> // always backtrack From fc3b2f6d22142583f5aa7e4bc3b0cda8de9a0d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20J=2E=20S=C3=A1nchez?= Date: Thu, 1 Aug 2024 00:33:22 +0200 Subject: [PATCH 5/8] remove expect and add error message just in case --- src/error.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index eac9dfa..a17f6ac 100644 --- a/src/error.rs +++ b/src/error.rs @@ -509,8 +509,6 @@ fn write_report<'a>( colored_labels.push(l); } - let block = codesnake::Block::new(&lidx, colored_labels).expect("invalid report spans"); - let sev_color = match err.severity() { Severity::Error => yansi::Color::Red, Severity::Warning => yansi::Color::Yellow, @@ -523,6 +521,11 @@ fn write_report<'a>( writeln!(w, " {} {source}", "╰▶ ".paint(sev_color))?; } + let Some(block) = codesnake::Block::new(&lidx, colored_labels) else { + tracing::error!("Failed to format code span, this is a bug."); + return Ok(()); + }; + let block = block.map_code(|c| codesnake::CodeWidth::new(c, c.len())); writeln!( From 951d7cb874787a75adca7f94b1da31cc92940f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20J=2E=20S=C3=A1nchez?= Date: Thu, 8 Aug 2024 17:11:49 +0200 Subject: [PATCH 6/8] update codenake and fix map_code width calculation --- Cargo.lock | 9 +++++---- Cargo.toml | 3 ++- src/error.rs | 8 +++++++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1dfb13e..2cffe77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,9 +248,9 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "codesnake" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458099206fe27887fff34f2f4bfdf482dbe874dd287aba1f068436babb4cac27" +checksum = "2205f7f6d3de68ecf4c291c789b3edf07b6569268abd0188819086f71ae42225" [[package]] name = "cooklang" @@ -279,6 +279,7 @@ dependencies = [ "toml 0.8.12", "tracing", "unicase", + "unicode-width", "url", "yansi", ] @@ -1354,9 +1355,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "uniffi" diff --git a/Cargo.toml b/Cargo.toml index 91f1d5c..a1c9ccf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,8 @@ toml = { version = "0.8", optional = true } once_cell = "1" enum-map = { version = "2", features = ["serde"] } tracing = "0.1" -codesnake = "0.2.0" +codesnake = "0.2.1" +unicode-width = "0.1.13" either = "1.8" finl_unicode = { version = "1.2", features = ["categories"], default-features = false } smallvec = { version = "1" } diff --git a/src/error.rs b/src/error.rs index a17f6ac..9a79d84 100644 --- a/src/error.rs +++ b/src/error.rs @@ -526,7 +526,13 @@ fn write_report<'a>( return Ok(()); }; - let block = block.map_code(|c| codesnake::CodeWidth::new(c, c.len())); + let mut prev_empty = false; + let block = block.map_code(|s| { + let sub = usize::from(core::mem::replace(&mut prev_empty, s.is_empty())); + let s = s.replace('\t', " "); + let w = unicode_width::UnicodeWidthStr::width(&*s); + codesnake::CodeWidth::new(s, core::cmp::max(w, 1) - sub) + }); writeln!( w, From 32dd7aeb39adb0abc0e2d2caaa2034147db74be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20J=2E=20S=C3=A1nchez?= Date: Mon, 12 Aug 2024 18:29:29 +0200 Subject: [PATCH 7/8] tweaks to various error messages --- src/analysis/event_consumer.rs | 31 +++++++++++++++---------------- src/error.rs | 2 +- src/parser/quantity.rs | 5 ++--- src/parser/step.rs | 6 +++--- src/quantity.rs | 2 ++ 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/analysis/event_consumer.rs b/src/analysis/event_consumer.rs index e5c077a..288d0ea 100644 --- a/src/analysis/event_consumer.rs +++ b/src/analysis/event_consumer.rs @@ -217,9 +217,9 @@ impl<'i, 'c> RecipeCollector<'i, 'c> { let invalid_value = |possible| { error!( format!("Invalid value for config key '{key_t}': {value_t}"), - label!(value.span(), "this value is not supported") + label!(value.span(), "this value") ) - .label(label!(key.span(), "by this key")) + .label(label!(key.span(), "this key does not support")) .hint(format!("Possible values are: {possible:?}")) }; @@ -309,7 +309,7 @@ impl<'i, 'c> RecipeCollector<'i, 'c> { ), label!(value.span(), "this value"), ) - .label(label!(key.span(), "is not supported by this key")) + .label(label!(key.span(), "this key does not support")) .hint("It will be a regular metadata entry") .set_source(err), ); @@ -534,12 +534,14 @@ impl<'i, 'c> RecipeCollector<'i, 'c> { .map(|l| l.span()) .unwrap_or(new_q_loc.span()); - let (new_label, old_label) = match &e { + let (main_label, support_label) = match &e { crate::quantity::IncompatibleUnits::MissingUnit { found } => { - let m = "this is missing a unit"; - let f = "matching this one"; + let m = "value missing unit"; + let f = "found unit"; match found { + // new is mising either::Either::Left(_) => (label!(new, m), label!(old, f)), + // old is missing either::Either::Right(_) => (label!(new, f), label!(old, m)), } } @@ -550,16 +552,16 @@ impl<'i, 'c> RecipeCollector<'i, 'c> { (label!(new, b_q.to_string()), label!(old, a_q.to_string())) } crate::quantity::IncompatibleUnits::UnknownDifferentUnits { .. } => { - (label!(new, "this unit"), label!(old, "differs from this")) + (label!(new), label!(old)) } }; self.ctx.warn( warning!( "Incompatible units prevent calculating total amount", - new_label + main_label ) - .label(old_label) + .label(support_label) .set_source(e), ) } @@ -1283,11 +1285,11 @@ fn conflicting_reference_quantity_error( ) -> SourceDiag { let mut e = error!( "Conflicting component reference quantities", - label!(ref_quantity_span, "reference with quantity here") + label!(ref_quantity_span, "reference with quantity") ) .label(label!( def_span, - "definition with quantity outside a step here" + "definition with quantity outside a step" )) .hint("If the component is not defined in a step and has a quantity, its references cannot have a quantity"); if implicit { @@ -1303,12 +1305,9 @@ fn text_val_in_ref_warn( ) -> SourceDiag { let mut w = warning!( "Text value may prevent calculating total amount", - label!(text_quantity_span, "this text") + label!(text_quantity_span, "can't operate with text value") ) - .label(label!( - number_quantity_span, - "cannot be added to this value" - )) + .label(label!(number_quantity_span, "numeric value")) .hint("Use numeric values so they can be added together"); if implicit { w.add_hint(IMPLICIT_REF_WARN); diff --git a/src/error.rs b/src/error.rs index 9a79d84..9a238e4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -515,7 +515,7 @@ fn write_report<'a>( }; match err.severity() { Severity::Error => writeln!(w, "{} {err}", "Error:".paint(sev_color))?, - Severity::Warning => writeln!(w, "{} {err}", "Warning: ".paint(sev_color))?, + Severity::Warning => writeln!(w, "{} {err}", "Warning:".paint(sev_color))?, } if let Some(source) = err.source() { writeln!(w, " {} {source}", "╰▶ ".paint(sev_color))?; diff --git a/src/parser/quantity.rs b/src/parser/quantity.rs index 4c4d1ec..d92b493 100644 --- a/src/parser/quantity.rs +++ b/src/parser/quantity.rs @@ -72,10 +72,9 @@ fn parse_regular_quantity<'i>(bp: &mut BlockParser<'_, 'i>) -> ParsedQuantity<'i bp.warn( warning!( "Empty quantity unit", - label!(unit_text.span(), "add unit here") + label!(unit_separator.unwrap(), "remove this") ) - .label(label!(unit_separator.unwrap(), "or remove this")) - .hint("It will be as if the quantity has no unit"), + .hint("Add a unit or remove the separator"), ); unit = None; } diff --git a/src/parser/step.rs b/src/parser/step.rs index fa8ba34..d10b0a0 100644 --- a/src/parser/step.rs +++ b/src/parser/step.rs @@ -303,16 +303,16 @@ fn parse_alias<'i>( format!("Invalid {container}: multiple aliases"), label!(bad_bit, "more than one alias defined here"), ) - .hint("A component can only have one alias. Remove the extra '|'"), + .hint("A component can only have one alias"), ); None } else if alias_text.is_text_empty() { bp.error( error!( format!("Invalid {container}: empty alias"), - label!(alias_text.span(), "add alias here"), + label!(alias_sep.span, "remove this"), ) - .label(label!(alias_sep.span, "or remove this")), + .hint("Either remove the `|` or add an alias"), ); None } else { diff --git a/src/quantity.rs b/src/quantity.rs index 654010a..25f670d 100644 --- a/src/quantity.rs +++ b/src/quantity.rs @@ -393,6 +393,8 @@ pub enum QuantityAddError { pub enum IncompatibleUnits { #[error("Missing unit: one unit is '{found}' but the other quantity is missing an unit")] MissingUnit { + /// `Left`: Missing on the left hand side quantity + /// `Right`: Missing on the right hand side quantity found: either::Either, }, #[error("Different physical quantity: '{a}' '{b}'")] From b63f4c7bfc19953814fd92a4b01579adc9684930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20J=2E=20S=C3=A1nchez?= Date: Mon, 12 Aug 2024 18:54:30 +0200 Subject: [PATCH 8/8] fix unused color parameter --- src/error.rs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/error.rs b/src/error.rs index 9a238e4..1fa7de8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -483,15 +483,17 @@ impl ColorGenerator { } } -fn write_report<'a>( +fn write_report( mut w: impl std::io::Write, - err: &'a dyn RichError, + err: &dyn RichError, lidx: &codesnake::LineIndex, file_name: &str, - _color: bool, + color: bool, ) -> std::io::Result<()> { use yansi::Paint; + let cond = yansi::Condition::cached(color); + let mut cg = ColorGenerator::default(); let mut labels = err.labels(); @@ -500,9 +502,9 @@ fn write_report<'a>( let mut colored_labels = Vec::with_capacity(labels.len()); for (s, t) in labels.iter() { - let color = cg.next(); - let mut l = - codesnake::Label::new(s.range()).with_style(move |s| s.paint(color).to_string()); + let c = cg.next(); + let mut l = codesnake::Label::new(s.range()) + .with_style(move |s| s.paint(c).whenever(cond).to_string()); if let Some(text) = t { l = l.with_text(text) } @@ -514,14 +516,14 @@ fn write_report<'a>( Severity::Warning => yansi::Color::Yellow, }; match err.severity() { - Severity::Error => writeln!(w, "{} {err}", "Error:".paint(sev_color))?, - Severity::Warning => writeln!(w, "{} {err}", "Warning:".paint(sev_color))?, + Severity::Error => writeln!(w, "{} {err}", "Error:".paint(sev_color).whenever(cond))?, + Severity::Warning => writeln!(w, "{} {err}", "Warning:".paint(sev_color).whenever(cond))?, } if let Some(source) = err.source() { - writeln!(w, " {} {source}", "╰▶ ".paint(sev_color))?; + writeln!(w, " {} {source}", "╰▶ ".paint(sev_color).whenever(cond))?; } - let Some(block) = codesnake::Block::new(&lidx, colored_labels) else { + let Some(block) = codesnake::Block::new(lidx, colored_labels) else { tracing::error!("Failed to format code span, this is a bug."); return Ok(()); }; @@ -538,9 +540,9 @@ fn write_report<'a>( w, "{}{}{}{}", block.prologue(), - "[".dim(), + "[".dim().whenever(cond), file_name, - "]".dim() + "]".dim().whenever(cond) )?; write!(w, "{block}")?; writeln!(w, "{}", block.epilogue())?; @@ -549,11 +551,11 @@ fn write_report<'a>( let mut hints = hints.iter(); if let Some(help) = hints.next() { - writeln!(w, "{} {}", "Help:".green(), help)?; + writeln!(w, "{} {}", "Help:".green().whenever(cond), help)?; } if let Some(note) = hints.next() { - writeln!(w, "{} {}", "Note:".green(), note)?; + writeln!(w, "{} {}", "Note:".green().whenever(cond), note)?; } #[cfg(debug_assertions)]