diff --git a/src/handler.rs b/src/handler.rs index 8165bdb..ea2551c 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -24,6 +24,7 @@ pub struct MietteHandlerOpts { pub(crate) rgb_colors: Option, pub(crate) color: Option, pub(crate) unicode: Option, + pub(crate) footer: Option, } impl MietteHandlerOpts { @@ -92,13 +93,23 @@ impl MietteHandlerOpts { self } + /// Set a footer to be displayed at the bottom of the report. + pub fn footer(mut self, footer: String) -> Self { + self.footer = Some(footer); + self + } + /// Builds a [MietteHandler] from this builder. pub fn build(self) -> MietteHandler { let graphical = self.is_graphical(); let width = self.get_width(); if !graphical { + let mut handler = NarratableReportHandler::new(); + if let Some(footer) = self.footer { + handler = handler.with_footer(footer); + } MietteHandler { - inner: Box::new(NarratableReportHandler::new()), + inner: Box::new(handler), } } else { let linkify = self.use_links(); @@ -123,13 +134,15 @@ impl MietteHandlerOpts { } else { ThemeStyles::none() }; + let mut handler = GraphicalReportHandler::new() + .with_width(width) + .with_links(linkify) + .with_theme(GraphicalTheme { characters, styles }); + if let Some(footer) = self.footer { + handler = handler.with_footer(footer); + } MietteHandler { - inner: Box::new( - GraphicalReportHandler::new() - .with_width(width) - .with_links(linkify) - .with_theme(GraphicalTheme { characters, styles }), - ), + inner: Box::new(handler), } } } diff --git a/src/handlers/graphical.rs b/src/handlers/graphical.rs index 92bf89b..522bf9e 100644 --- a/src/handlers/graphical.rs +++ b/src/handlers/graphical.rs @@ -24,6 +24,7 @@ pub struct GraphicalReportHandler { pub(crate) linkify_code: bool, pub(crate) termwidth: usize, pub(crate) theme: GraphicalTheme, + pub(crate) footer: Option, } impl GraphicalReportHandler { @@ -34,6 +35,7 @@ impl GraphicalReportHandler { linkify_code: true, termwidth: 200, theme: GraphicalTheme::default(), + footer: None, } } @@ -43,6 +45,7 @@ impl GraphicalReportHandler { linkify_code: true, termwidth: 200, theme, + footer: None, } } @@ -63,6 +66,12 @@ impl GraphicalReportHandler { self.termwidth = width; self } + + /// Sets the "global" footer for this handler. + pub fn with_footer(mut self, footer: String) -> Self { + self.footer = Some(footer); + self + } } impl Default for GraphicalReportHandler { @@ -204,6 +213,14 @@ impl GraphicalReportHandler { .subsequent_indent(" "); writeln!(f, "{}", textwrap::fill(&help.to_string(), opts))?; } + if let Some(footer) = &self.footer { + writeln!(f)?; + let width = self.termwidth.saturating_sub(4); + let opts = textwrap::Options::new(width) + .initial_indent(" ") + .subsequent_indent(" "); + writeln!(f, "{}", textwrap::fill(footer, opts))?; + } Ok(()) } diff --git a/src/handlers/narratable.rs b/src/handlers/narratable.rs index 6603f35..8482330 100644 --- a/src/handlers/narratable.rs +++ b/src/handlers/narratable.rs @@ -10,13 +10,21 @@ It's optimized for screen readers and braille users, but is also used in any non-graphical environments, such as non-TTY output. */ #[derive(Debug, Clone)] -pub struct NarratableReportHandler; +pub struct NarratableReportHandler { + footer: Option, +} impl NarratableReportHandler { /// Create a new [NarratableReportHandler]. There are no customization /// options. pub fn new() -> Self { - Self + Self { footer: None} + } + + /// Set the footer to be displayed at the end of the report. + pub fn with_footer(mut self, footer: String) -> Self { + self.footer = Some(footer); + self } } diff --git a/tests/narrated.rs b/tests/narrated.rs index e63fa8e..041f0f6 100644 --- a/tests/narrated.rs +++ b/tests/narrated.rs @@ -17,7 +17,7 @@ fn fmt_report(diag: Report) -> String { .render_report(&mut out, diag.as_ref()) .unwrap(); } else { - NarratableReportHandler + NarratableReportHandler::new() .render_report(&mut out, diag.as_ref()) .unwrap(); }; diff --git a/tests/printer.rs b/tests/printer.rs index 76590a0..08ed84b 100644 --- a/tests/printer.rs +++ b/tests/printer.rs @@ -12,10 +12,11 @@ fn fmt_report(diag: Report) -> String { if std::env::var("STYLE").is_ok() { GraphicalReportHandler::new_themed(GraphicalTheme::unicode()) .with_width(80) + .with_footer("this is a footer".into()) .render_report(&mut out, diag.as_ref()) .unwrap(); } else if std::env::var("NARRATED").is_ok() { - NarratableReportHandler + NarratableReportHandler::new() .render_report(&mut out, diag.as_ref()) .unwrap(); } else {