From 103a2f0d9b4dd8bb9202de49bc8d7bd641cda149 Mon Sep 17 00:00:00 2001 From: Peter Hebden Date: Sun, 9 Jul 2023 01:08:14 +0100 Subject: [PATCH 1/6] Add `OutputHandle` enum to use instead of `&mut dyn io::Write` --- src/controller.rs | 36 +++++++++---- src/error.rs | 2 + src/pretty_printer.rs | 2 +- src/printer.rs | 119 ++++++++++++++++++++++++++++-------------- 4 files changed, 107 insertions(+), 52 deletions(-) diff --git a/src/controller.rs b/src/controller.rs index ecef81eb4b..5158167786 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -12,7 +12,7 @@ use crate::line_range::{LineRanges, RangeCheckResult}; use crate::output::OutputType; #[cfg(feature = "paging")] use crate::paging::PagingMode; -use crate::printer::{InteractivePrinter, Printer, SimplePrinter}; +use crate::printer::{InteractivePrinter, OutputHandle, Printer, SimplePrinter}; use clircle::{Clircle, Identifier}; @@ -26,13 +26,18 @@ impl<'b> Controller<'b> { Controller { config, assets } } - pub fn run(&self, inputs: Vec) -> Result { - self.run_with_error_handler(inputs, default_error_handler) + pub fn run( + &self, + inputs: Vec, + output_buffer: Option<&mut dyn std::fmt::Write>, + ) -> Result { + self.run_with_error_handler(inputs, output_buffer, default_error_handler) } pub fn run_with_error_handler( &self, inputs: Vec, + output_buffer: Option<&mut dyn std::fmt::Write>, handle_error: impl Fn(&Error, &mut dyn Write), ) -> Result { let mut output_type; @@ -74,7 +79,11 @@ impl<'b> Controller<'b> { clircle::Identifier::stdout() }; - let writer = output_type.handle()?; + //let writer = output_type.handle()?; + let writer = output_buffer.map_or_else( + || OutputHandle::IoWrite(output_type.handle().unwrap()), + |buf| OutputHandle::FmtWrite(buf), + ); let mut no_errors: bool = true; let stderr = io::stderr(); @@ -88,10 +97,15 @@ impl<'b> Controller<'b> { self.print_input(input, writer, io::empty(), identifier, is_first) }; if let Err(error) = result { - if attached_to_pager { - handle_error(&error, writer); - } else { - handle_error(&error, &mut stderr.lock()); + match writer { + OutputHandle::FmtWrite(writer) => todo!(), + OutputHandle::IoWrite(writer) => { + if attached_to_pager { + handle_error(&error, writer); + } else { + handle_error(&error, &mut stderr.lock()); + } + } } no_errors = false; } @@ -103,7 +117,7 @@ impl<'b> Controller<'b> { fn print_input( &self, input: Input, - writer: &mut dyn Write, + writer: OutputHandle, stdin: R, stdout_identifier: Option<&Identifier>, is_first: bool, @@ -164,7 +178,7 @@ impl<'b> Controller<'b> { fn print_file( &self, printer: &mut dyn Printer, - writer: &mut dyn Write, + writer: OutputHandle, input: &mut OpenedInput, add_header_padding: bool, #[cfg(feature = "git")] line_changes: &Option, @@ -202,7 +216,7 @@ impl<'b> Controller<'b> { fn print_file_ranges( &self, printer: &mut dyn Printer, - writer: &mut dyn Write, + writer: OutputHandle, reader: &mut InputReader, line_ranges: &LineRanges, ) -> Result<()> { diff --git a/src/error.rs b/src/error.rs index af0b9121f5..3579d4ff57 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,6 +7,8 @@ pub enum Error { #[error(transparent)] Io(#[from] ::std::io::Error), #[error(transparent)] + Fmt(#[from] ::std::fmt::Error), + #[error(transparent)] SyntectError(#[from] ::syntect::Error), #[error(transparent)] SyntectLoadingError(#[from] ::syntect::LoadingError), diff --git a/src/pretty_printer.rs b/src/pretty_printer.rs index 02a7a519f5..121637f1f0 100644 --- a/src/pretty_printer.rs +++ b/src/pretty_printer.rs @@ -300,7 +300,7 @@ impl<'a> PrettyPrinter<'a> { // Run the controller let controller = Controller::new(&self.config, &self.assets); - controller.run(inputs.into_iter().map(|i| i.into()).collect()) + controller.run(inputs.into_iter().map(|i| i.into()).collect(), None) } } diff --git a/src/printer.rs b/src/printer.rs index d46b23d115..328b993ce4 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -1,4 +1,5 @@ -use std::io::Write; +use std::fmt; +use std::io; use std::vec::Vec; use nu_ansi_term::Color::{Fixed, Green, Red, Yellow}; @@ -36,21 +37,52 @@ use crate::terminal::{as_terminal_escaped, to_ansi_color}; use crate::vscreen::AnsiStyle; use crate::wrapping::WrappingMode; +pub enum OutputHandle<'a> { + IoWrite(&'a mut dyn io::Write), + FmtWrite(&'a mut dyn fmt::Write), +} + +macro_rules! write_handle { + ($dst:expr, $($arg:tt)*) => { + match $dst { + OutputHandle::IoWrite(ref mut handle) => { + write!(handle, $($arg)*).map_err(|e| Error::from(e)) + } + OutputHandle::FmtWrite(ref mut handle) => { + write!(handle, $($arg)*).map_err(|e| Error::from(e)) + } + } + } +} + +macro_rules! writeln_handle { + ($dst:expr, $($arg:tt)*) => { + match $dst { + OutputHandle::IoWrite(ref mut handle) => { + writeln!(handle, $($arg)*).map_err(|e| Error::from(e)) + } + OutputHandle::FmtWrite(ref mut handle) => { + writeln!(handle, $($arg)*).map_err(|e| Error::from(e)) + } + } + } +} + pub(crate) trait Printer { fn print_header( &mut self, - handle: &mut dyn Write, + handle: OutputHandle, input: &OpenedInput, add_header_padding: bool, ) -> Result<()>; - fn print_footer(&mut self, handle: &mut dyn Write, input: &OpenedInput) -> Result<()>; + fn print_footer(&mut self, handle: OutputHandle, input: &OpenedInput) -> Result<()>; - fn print_snip(&mut self, handle: &mut dyn Write) -> Result<()>; + fn print_snip(&mut self, handle: OutputHandle) -> Result<()>; fn print_line( &mut self, out_of_range: bool, - handle: &mut dyn Write, + handle: OutputHandle, line_number: usize, line_buffer: &[u8], ) -> Result<()>; @@ -69,25 +101,25 @@ impl<'a> SimplePrinter<'a> { impl<'a> Printer for SimplePrinter<'a> { fn print_header( &mut self, - _handle: &mut dyn Write, + _handle: OutputHandle, _input: &OpenedInput, _add_header_padding: bool, ) -> Result<()> { Ok(()) } - fn print_footer(&mut self, _handle: &mut dyn Write, _input: &OpenedInput) -> Result<()> { + fn print_footer(&mut self, _handle: OutputHandle, _input: &OpenedInput) -> Result<()> { Ok(()) } - fn print_snip(&mut self, _handle: &mut dyn Write) -> Result<()> { + fn print_snip(&mut self, _handle: OutputHandle) -> Result<()> { Ok(()) } fn print_line( &mut self, out_of_range: bool, - handle: &mut dyn Write, + handle: OutputHandle, _line_number: usize, line_buffer: &[u8], ) -> Result<()> { @@ -98,9 +130,12 @@ impl<'a> Printer for SimplePrinter<'a> { self.config.tab_width, self.config.nonprintable_notation, ); - write!(handle, "{}", line)?; + write_handle!(handle, "{}", line)?; } else { - handle.write_all(line_buffer)? + match handle { + OutputHandle::IoWrite(handle) => handle.write_all(line_buffer)?, + OutputHandle::FmtWrite(handle) => todo!(), + } }; } Ok(()) @@ -218,8 +253,8 @@ impl<'a> InteractivePrinter<'a> { }) } - fn print_horizontal_line_term(&mut self, handle: &mut dyn Write, style: Style) -> Result<()> { - writeln!( + fn print_horizontal_line_term(&mut self, handle: OutputHandle, style: Style) -> Result<()> { + writeln_handle!( handle, "{}", style.paint("─".repeat(self.config.term_width)) @@ -227,13 +262,13 @@ impl<'a> InteractivePrinter<'a> { Ok(()) } - fn print_horizontal_line(&mut self, handle: &mut dyn Write, grid_char: char) -> Result<()> { + fn print_horizontal_line(&mut self, handle: OutputHandle, grid_char: char) -> Result<()> { if self.panel_width == 0 { self.print_horizontal_line_term(handle, self.colors.grid)?; } else { let hline = "─".repeat(self.config.term_width - (self.panel_width + 1)); let hline = format!("{}{}{}", "─".repeat(self.panel_width), grid_char, hline); - writeln!(handle, "{}", self.colors.grid.paint(hline))?; + writeln_handle!(handle, "{}", self.colors.grid.paint(hline))?; } Ok(()) @@ -257,9 +292,9 @@ impl<'a> InteractivePrinter<'a> { } } - fn print_header_component_indent(&mut self, handle: &mut dyn Write) -> std::io::Result<()> { + fn print_header_component_indent(&mut self, handle: OutputHandle) -> Result<()> { if self.config.style_components.grid() { - write!( + write_handle!( handle, "{}{}", " ".repeat(self.panel_width), @@ -268,7 +303,7 @@ impl<'a> InteractivePrinter<'a> { .paint(if self.panel_width > 0 { "│ " } else { "" }), ) } else { - write!(handle, "{}", " ".repeat(self.panel_width)) + write_handle!(handle, "{}", " ".repeat(self.panel_width)) } } @@ -285,7 +320,7 @@ impl<'a> InteractivePrinter<'a> { impl<'a> Printer for InteractivePrinter<'a> { fn print_header( &mut self, - handle: &mut dyn Write, + handle: OutputHandle, input: &OpenedInput, add_header_padding: bool, ) -> Result<()> { @@ -295,7 +330,7 @@ impl<'a> Printer for InteractivePrinter<'a> { if !self.config.style_components.header() { if Some(ContentType::BINARY) == self.content_type && !self.config.show_nonprintable { - writeln!( + writeln_handle!( handle, "{}: Binary content from {} will not be printed to the terminal \ (but will be present if the output of 'bat' is piped). You can use 'bat -A' \ @@ -343,7 +378,7 @@ impl<'a> Printer for InteractivePrinter<'a> { } else { // Only pad space between files, if we haven't already drawn a horizontal rule if add_header_padding && !self.config.style_components.rule() { - writeln!(handle)?; + writeln_handle!(handle,)?; } } @@ -351,7 +386,7 @@ impl<'a> Printer for InteractivePrinter<'a> { self.print_header_component_indent(handle)?; match component { - StyleComponent::HeaderFilename => writeln!( + StyleComponent::HeaderFilename => writeln_handle!( handle, "{}{}{}", description @@ -367,7 +402,7 @@ impl<'a> Printer for InteractivePrinter<'a> { .size .map(|s| format!("{}", ByteSize(s))) .unwrap_or_else(|| "-".into()); - writeln!(handle, "Size: {}", self.colors.header_value.paint(bsize)) + writeln_handle!(handle, "Size: {}", self.colors.header_value.paint(bsize)) } _ => Ok(()), } @@ -384,7 +419,7 @@ impl<'a> Printer for InteractivePrinter<'a> { Ok(()) } - fn print_footer(&mut self, handle: &mut dyn Write, _input: &OpenedInput) -> Result<()> { + fn print_footer(&mut self, handle: OutputHandle, _input: &OpenedInput) -> Result<()> { if self.config.style_components.grid() && (self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable) { @@ -394,7 +429,7 @@ impl<'a> Printer for InteractivePrinter<'a> { } } - fn print_snip(&mut self, handle: &mut dyn Write) -> Result<()> { + fn print_snip(&mut self, handle: OutputHandle) -> Result<()> { let panel = self.create_fake_panel(" ..."); let panel_count = panel.chars().count(); @@ -407,13 +442,13 @@ impl<'a> Printer for InteractivePrinter<'a> { let snip_right = " ─".repeat((self.config.term_width - panel_count - snip_left_count - title_count) / 2); - writeln!( + writeln_handle!( handle, "{}", self.colors .grid .paint(format!("{}{}{}{}", panel, snip_left, title, snip_right)) - )?; + ); Ok(()) } @@ -421,7 +456,7 @@ impl<'a> Printer for InteractivePrinter<'a> { fn print_line( &mut self, out_of_range: bool, - handle: &mut dyn Write, + handle: OutputHandle, line_number: usize, line_buffer: &[u8], ) -> Result<()> { @@ -508,7 +543,7 @@ impl<'a> Printer for InteractivePrinter<'a> { .map(|d| d.generate(line_number, false, self)); for deco in decorations { - write!(handle, "{} ", deco.text)?; + write_handle!(handle, "{} ", deco.text)?; cursor_max -= deco.width + 1; } } @@ -526,7 +561,7 @@ impl<'a> Printer for InteractivePrinter<'a> { // ANSI escape passthrough. (ansi, true) => { self.ansi_style.update(ansi); - write!(handle, "{}", ansi)?; + write_handle!(handle, "{}", ansi)?; } // Regular text. @@ -534,7 +569,7 @@ impl<'a> Printer for InteractivePrinter<'a> { let text = &*self.preprocess(text, &mut cursor_total); let text_trimmed = text.trim_end_matches(|c| c == '\r' || c == '\n'); - write!( + write_handle!( handle, "{}", as_terminal_escaped( @@ -559,9 +594,13 @@ impl<'a> Printer for InteractivePrinter<'a> { } else { 0 }; - write!(handle, "{}", ansi_style.paint(" ".repeat(width)))?; + write_handle!( + handle, + "{}", + ansi_style.paint(" ".repeat(width)) + )?; } - write!(handle, "{}", &text[text_trimmed.len()..])?; + write_handle!(handle, "{}", &text[text_trimmed.len()..])?; } } } @@ -569,7 +608,7 @@ impl<'a> Printer for InteractivePrinter<'a> { } if !self.config.style_components.plain() && line.bytes().next_back() != Some(b'\n') { - writeln!(handle)?; + writeln_handle!(handle,)?; } } else { for &(style, region) in ®ions { @@ -579,7 +618,7 @@ impl<'a> Printer for InteractivePrinter<'a> { // ANSI escape passthrough. (ansi, true) => { self.ansi_style.update(ansi); - write!(handle, "{}", ansi)?; + write_handle!(handle, "{}", ansi)?; } // Regular text. @@ -624,7 +663,7 @@ impl<'a> Printer for InteractivePrinter<'a> { } // It wraps. - write!( + write_handle!( handle, "{}\n{}", as_terminal_escaped( @@ -650,7 +689,7 @@ impl<'a> Printer for InteractivePrinter<'a> { // flush the buffer cursor += current_width; - write!( + write_handle!( handle, "{}", as_terminal_escaped( @@ -673,18 +712,18 @@ impl<'a> Printer for InteractivePrinter<'a> { ..Default::default() }; - write!( + write_handle!( handle, "{}", ansi_style.paint(" ".repeat(cursor_max - cursor)) )?; } - writeln!(handle)?; + writeln_handle!(handle,)?; } if highlight_this_line && self.config.theme == "ansi" { self.ansi_style.update("^[24m"); - write!(handle, "\x1B[24m")?; + write_handle!(handle, "\x1B[24m")?; } Ok(()) From d929becefcdc528706ab0d6d4407e64999c6ad45 Mon Sep 17 00:00:00 2001 From: Peter Hebden Date: Sun, 9 Jul 2023 01:20:58 +0100 Subject: [PATCH 2/6] Fix signatures --- src/bin/bat/main.rs | 4 ++-- src/controller.rs | 14 +++++++------- src/printer.rs | 34 +++++++++++++++++++--------------- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/bin/bat/main.rs b/src/bin/bat/main.rs index 385140e6d1..43e9d28856 100644 --- a/src/bin/bat/main.rs +++ b/src/bin/bat/main.rs @@ -206,7 +206,7 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result< )?; config.theme = theme.to_string(); Controller::new(&config, &assets) - .run(vec![theme_preview_file()]) + .run(vec![theme_preview_file()], None) .ok(); writeln!(stdout)?; } @@ -230,7 +230,7 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result< fn run_controller(inputs: Vec, config: &Config, cache_dir: &Path) -> Result { let assets = assets_from_cache_or_binary(config.use_custom_assets, cache_dir)?; let controller = Controller::new(config, &assets); - controller.run(inputs) + controller.run(inputs, None) } #[cfg(feature = "bugreport")] diff --git a/src/controller.rs b/src/controller.rs index 5158167786..259a8a6f5f 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -80,7 +80,7 @@ impl<'b> Controller<'b> { }; //let writer = output_type.handle()?; - let writer = output_buffer.map_or_else( + let mut writer = output_buffer.map_or_else( || OutputHandle::IoWrite(output_type.handle().unwrap()), |buf| OutputHandle::FmtWrite(buf), ); @@ -91,15 +91,15 @@ impl<'b> Controller<'b> { let identifier = stdout_identifier.as_ref(); let is_first = index == 0; let result = if input.is_stdin() { - self.print_input(input, writer, io::stdin().lock(), identifier, is_first) + self.print_input(input, &mut writer, io::stdin().lock(), identifier, is_first) } else { // Use dummy stdin since stdin is actually not used (#1902) - self.print_input(input, writer, io::empty(), identifier, is_first) + self.print_input(input, &mut writer, io::empty(), identifier, is_first) }; if let Err(error) = result { match writer { OutputHandle::FmtWrite(writer) => todo!(), - OutputHandle::IoWrite(writer) => { + OutputHandle::IoWrite(ref mut writer) => { if attached_to_pager { handle_error(&error, writer); } else { @@ -117,7 +117,7 @@ impl<'b> Controller<'b> { fn print_input( &self, input: Input, - writer: OutputHandle, + writer: &mut OutputHandle, stdin: R, stdout_identifier: Option<&Identifier>, is_first: bool, @@ -178,7 +178,7 @@ impl<'b> Controller<'b> { fn print_file( &self, printer: &mut dyn Printer, - writer: OutputHandle, + writer: &mut OutputHandle, input: &mut OpenedInput, add_header_padding: bool, #[cfg(feature = "git")] line_changes: &Option, @@ -216,7 +216,7 @@ impl<'b> Controller<'b> { fn print_file_ranges( &self, printer: &mut dyn Printer, - writer: OutputHandle, + writer: &mut OutputHandle, reader: &mut InputReader, line_ranges: &LineRanges, ) -> Result<()> { diff --git a/src/printer.rs b/src/printer.rs index 328b993ce4..deeebe49f5 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -71,18 +71,18 @@ macro_rules! writeln_handle { pub(crate) trait Printer { fn print_header( &mut self, - handle: OutputHandle, + handle: &mut OutputHandle, input: &OpenedInput, add_header_padding: bool, ) -> Result<()>; - fn print_footer(&mut self, handle: OutputHandle, input: &OpenedInput) -> Result<()>; + fn print_footer(&mut self, handle: &mut OutputHandle, input: &OpenedInput) -> Result<()>; - fn print_snip(&mut self, handle: OutputHandle) -> Result<()>; + fn print_snip(&mut self, handle: &mut OutputHandle) -> Result<()>; fn print_line( &mut self, out_of_range: bool, - handle: OutputHandle, + handle: &mut OutputHandle, line_number: usize, line_buffer: &[u8], ) -> Result<()>; @@ -101,25 +101,25 @@ impl<'a> SimplePrinter<'a> { impl<'a> Printer for SimplePrinter<'a> { fn print_header( &mut self, - _handle: OutputHandle, + _handle: &mut OutputHandle, _input: &OpenedInput, _add_header_padding: bool, ) -> Result<()> { Ok(()) } - fn print_footer(&mut self, _handle: OutputHandle, _input: &OpenedInput) -> Result<()> { + fn print_footer(&mut self, _handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> { Ok(()) } - fn print_snip(&mut self, _handle: OutputHandle) -> Result<()> { + fn print_snip(&mut self, _handle: &mut OutputHandle) -> Result<()> { Ok(()) } fn print_line( &mut self, out_of_range: bool, - handle: OutputHandle, + handle: &mut OutputHandle, _line_number: usize, line_buffer: &[u8], ) -> Result<()> { @@ -253,7 +253,11 @@ impl<'a> InteractivePrinter<'a> { }) } - fn print_horizontal_line_term(&mut self, handle: OutputHandle, style: Style) -> Result<()> { + fn print_horizontal_line_term( + &mut self, + handle: &mut OutputHandle, + style: Style, + ) -> Result<()> { writeln_handle!( handle, "{}", @@ -262,7 +266,7 @@ impl<'a> InteractivePrinter<'a> { Ok(()) } - fn print_horizontal_line(&mut self, handle: OutputHandle, grid_char: char) -> Result<()> { + fn print_horizontal_line(&mut self, handle: &mut OutputHandle, grid_char: char) -> Result<()> { if self.panel_width == 0 { self.print_horizontal_line_term(handle, self.colors.grid)?; } else { @@ -292,7 +296,7 @@ impl<'a> InteractivePrinter<'a> { } } - fn print_header_component_indent(&mut self, handle: OutputHandle) -> Result<()> { + fn print_header_component_indent(&mut self, handle: &mut OutputHandle) -> Result<()> { if self.config.style_components.grid() { write_handle!( handle, @@ -320,7 +324,7 @@ impl<'a> InteractivePrinter<'a> { impl<'a> Printer for InteractivePrinter<'a> { fn print_header( &mut self, - handle: OutputHandle, + handle: &mut OutputHandle, input: &OpenedInput, add_header_padding: bool, ) -> Result<()> { @@ -419,7 +423,7 @@ impl<'a> Printer for InteractivePrinter<'a> { Ok(()) } - fn print_footer(&mut self, handle: OutputHandle, _input: &OpenedInput) -> Result<()> { + fn print_footer(&mut self, handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> { if self.config.style_components.grid() && (self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable) { @@ -429,7 +433,7 @@ impl<'a> Printer for InteractivePrinter<'a> { } } - fn print_snip(&mut self, handle: OutputHandle) -> Result<()> { + fn print_snip(&mut self, handle: &mut OutputHandle) -> Result<()> { let panel = self.create_fake_panel(" ..."); let panel_count = panel.chars().count(); @@ -456,7 +460,7 @@ impl<'a> Printer for InteractivePrinter<'a> { fn print_line( &mut self, out_of_range: bool, - handle: OutputHandle, + handle: &mut OutputHandle, line_number: usize, line_buffer: &[u8], ) -> Result<()> { From 906e77437248da09e904431de31ff5b677db6a43 Mon Sep 17 00:00:00 2001 From: Peter Hebden Date: Sun, 9 Jul 2023 01:33:48 +0100 Subject: [PATCH 3/6] Handle todos --- src/controller.rs | 4 +++- src/printer.rs | 11 ++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/controller.rs b/src/controller.rs index 259a8a6f5f..e8b32bc852 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -98,7 +98,9 @@ impl<'b> Controller<'b> { }; if let Err(error) = result { match writer { - OutputHandle::FmtWrite(writer) => todo!(), + // It doesn't make much sense to send errors straight to stderr if the user + // provided their own buffer, so we just return it. + OutputHandle::FmtWrite(_) => return Err(error), OutputHandle::IoWrite(ref mut writer) => { if attached_to_pager { handle_error(&error, writer); diff --git a/src/printer.rs b/src/printer.rs index deeebe49f5..a317bdcc4c 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -134,7 +134,16 @@ impl<'a> Printer for SimplePrinter<'a> { } else { match handle { OutputHandle::IoWrite(handle) => handle.write_all(line_buffer)?, - OutputHandle::FmtWrite(handle) => todo!(), + OutputHandle::FmtWrite(handle) => { + write!( + handle, + "{}", + std::str::from_utf8(line_buffer).map_err(|_| Error::Msg( + "encountered invalid utf8 while printing to non-io buffer" + .to_string() + ))? + )?; + } } }; } From b2c28cdddb29bc27ff30029ec4a41ab1f507c059 Mon Sep 17 00:00:00 2001 From: Peter Hebden Date: Sun, 9 Jul 2023 01:34:35 +0100 Subject: [PATCH 4/6] Clippy lints --- src/printer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/printer.rs b/src/printer.rs index a317bdcc4c..256adbf095 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -461,7 +461,7 @@ impl<'a> Printer for InteractivePrinter<'a> { self.colors .grid .paint(format!("{}{}{}{}", panel, snip_left, title, snip_right)) - ); + )?; Ok(()) } From 33a89410d4ef4fbe567c9ebfe80ad93296652f4a Mon Sep 17 00:00:00 2001 From: Peter Hebden Date: Sun, 9 Jul 2023 01:49:45 +0100 Subject: [PATCH 5/6] Add example to show new feature --- examples/buffer.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 examples/buffer.rs diff --git a/examples/buffer.rs b/examples/buffer.rs new file mode 100644 index 0000000000..839689d406 --- /dev/null +++ b/examples/buffer.rs @@ -0,0 +1,17 @@ +use bat::{assets::HighlightingAssets, config::Config, controller::Controller, Input}; + +fn main() { + let mut buffer = String::new(); + let config = Config { + colored_output: true, + ..Default::default() + }; + let assets = HighlightingAssets::from_binary(); + let controller = Controller::new(&config, &assets); + let input = Input::from_file(file!()); + controller + .run(vec![input.into()], Some(&mut buffer)) + .unwrap(); + + println!("{buffer}"); +} From 72e1a40babf4bd4cdad4630b996d6f7c4d32681d Mon Sep 17 00:00:00 2001 From: Peter Hebden Date: Sun, 9 Jul 2023 02:00:01 +0100 Subject: [PATCH 6/6] Remove leftover unwrap --- src/controller.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/controller.rs b/src/controller.rs index e8b32bc852..42c139363e 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -79,11 +79,10 @@ impl<'b> Controller<'b> { clircle::Identifier::stdout() }; - //let writer = output_type.handle()?; - let mut writer = output_buffer.map_or_else( - || OutputHandle::IoWrite(output_type.handle().unwrap()), - |buf| OutputHandle::FmtWrite(buf), - ); + let mut writer = match output_buffer { + Some(buf) => OutputHandle::FmtWrite(buf), + None => OutputHandle::IoWrite(output_type.handle()?), + }; let mut no_errors: bool = true; let stderr = io::stderr();