From 34b716e04371e7929b98d687225ac78222986c44 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Thu, 27 Feb 2025 10:38:23 +0800 Subject: [PATCH 1/2] feat: add multiple and multiline help support --- src/lib.rs | 22 ++++++++++++++---- src/write.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ededa5f..ffeb124 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -203,7 +203,7 @@ pub struct Report<'a, S: Span = Range> { code: Option, msg: Option, notes: Vec, - help: Option, + help: Vec, span: S, labels: Vec>, config: Config, @@ -219,7 +219,7 @@ impl Report<'_, S> { code: None, msg: None, notes: vec![], - help: None, + help: vec![], span, labels: Vec::new(), config: Config::default(), @@ -284,7 +284,7 @@ pub struct ReportBuilder<'a, S: Span> { code: Option, msg: Option, notes: Vec, - help: Option, + help: Vec, span: S, labels: Vec>, config: Config, @@ -333,12 +333,24 @@ impl<'a, S: Span> ReportBuilder<'a, S> { /// Set the help message of this report. pub fn set_help(&mut self, note: N) { - self.help = Some(note.to_string()); + self.help = vec![note.to_string()]; + } + + /// Add a help message to this report. + pub fn add_help(&mut self, note: N) { + self.help.push(note.to_string()); + } + + /// Set the help messages of this report. + pub fn with_helps>(&mut self, helps: N) { + for help in helps { + self.add_help(help) + } } /// Set the help message of this report. pub fn with_help(mut self, note: N) -> Self { - self.set_help(note); + self.add_help(note); self } diff --git a/src/write.rs b/src/write.rs index ee7b1d7..8028e90 100644 --- a/src/write.rs +++ b/src/write.rs @@ -856,13 +856,37 @@ impl Report<'_, S> { let is_final_group = group_idx + 1 == groups_len; // Help - if let (Some(note), true) = (&self.help, is_final_group) { - if !self.config.compact { - write_margin(&mut w, 0, false, false, true, Some((0, false)), &[], &None)?; - writeln!(w)?; + if is_final_group { + for (i, help) in self.help.iter().enumerate() { + if !self.config.compact { + write_margin(&mut w, 0, false, false, true, Some((0, false)), &[], &None)?; + writeln!(w)?; + } + let help_prefix = format!("{} {}", "Help", i + 1); + let help_prefix_len = if self.help.len() > 1 { + help_prefix.len() + } else { + 4 + }; + let mut lines = help.lines(); + if let Some(line) = lines.next() { + write_margin(&mut w, 0, false, false, true, Some((0, false)), &[], &None)?; + if self.help.len() > 1 { + writeln!( + w, + "{}: {}", + help_prefix.fg(self.config.note_color(), s), + line + )?; + } else { + writeln!(w, "{}: {}", "Help".fg(self.config.note_color(), s), line)?; + } + } + for line in lines { + write_margin(&mut w, 0, false, false, true, Some((0, false)), &[], &None)?; + writeln!(w, "{:>pad$}{}", "", line, pad = help_prefix_len + 2)?; + } } - write_margin(&mut w, 0, false, false, true, Some((0, false)), &[], &None)?; - writeln!(w, "{}: {}", "Help".fg(self.config.note_color(), s), note)?; } // Note @@ -1522,4 +1546,33 @@ mod tests { ---' "###) } + + #[test] + fn multi_helps_multi_lines() { + let source = "apple == orange;"; + let msg = remove_trailing( + Report::build(ReportKind::Error, 0..0) + .with_config(no_color_and_ascii()) + .with_message("can't compare apples with oranges") + .with_label(Label::new(0..15).with_message("This is a strange comparison")) + .with_help("No need to try, they can't be compared.") + .with_help("Yeah, really, please stop.\nIt has no resemblance.") + .finish() + .write_to_string(Source::from(source)), + ); + assert_snapshot!(msg, @r###" + Error: can't compare apples with oranges + ,-[ :1:1 ] + | + 1 | apple == orange; + | ^^^^^^^|^^^^^^^ + | `--------- This is a strange comparison + | + | Help 1: No need to try, they can't be compared. + | + | Help 2: Yeah, really, please stop. + | It has no resemblance. + ---' + "###) + } } From 1da9b4d0eb583cca2c315187a6d19b391e35bbd0 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Thu, 27 Feb 2025 10:38:30 +0800 Subject: [PATCH 2/2] minor: cargo fmt --- src/source.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/source.rs b/src/source.rs index acae6a7..4e48629 100644 --- a/src/source.rs +++ b/src/source.rs @@ -1,11 +1,11 @@ use super::*; +use std::io::Error; use std::{ collections::{hash_map::Entry, HashMap}, fs, path::{Path, PathBuf}, }; -use std::io::Error; /// A trait implemented by [`Source`] caches. pub trait Cache { @@ -332,9 +332,7 @@ impl Cache for FileCache { Ok::<_, Error>(match self.files.entry(path.to_path_buf()) { // TODO: Don't allocate here Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(entry) => entry.insert(Source::from( - fs::read_to_string(path)?, - )), + Entry::Vacant(entry) => entry.insert(Source::from(fs::read_to_string(path)?)), }) } fn display<'a>(&self, path: &'a Path) -> Option { @@ -403,14 +401,12 @@ where I: IntoIterator, S: AsRef, { - FnCache::new( - (move |id| Err(format!("Failed to fetch source '{}'", id))) as fn(&_) -> _, - ) - .with_sources( - iter.into_iter() - .map(|(id, s)| (id, Source::from(s))) - .collect(), - ) + FnCache::new((move |id| Err(format!("Failed to fetch source '{}'", id))) as fn(&_) -> _) + .with_sources( + iter.into_iter() + .map(|(id, s)| (id, Source::from(s))) + .collect(), + ) } #[cfg(test)]