Skip to content

Commit

Permalink
Merge pull request #2618 from Piturnah/feat/write-to-buffer
Browse files Browse the repository at this point in the history
feat: Optionally write to a buffer instead of stdout
  • Loading branch information
sharkdp authored Sep 1, 2023
2 parents 1e52785 + 72e1a40 commit b06f13f
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 55 deletions.
17 changes: 17 additions & 0 deletions examples/buffer.rs
Original file line number Diff line number Diff line change
@@ -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}");
}
4 changes: 2 additions & 2 deletions src/bin/bat/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
}
Expand All @@ -230,7 +230,7 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result<
fn run_controller(inputs: Vec<Input>, config: &Config, cache_dir: &Path) -> Result<bool> {
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")]
Expand Down
41 changes: 28 additions & 13 deletions src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -26,13 +26,18 @@ impl<'b> Controller<'b> {
Controller { config, assets }
}

pub fn run(&self, inputs: Vec<Input>) -> Result<bool> {
self.run_with_error_handler(inputs, default_error_handler)
pub fn run(
&self,
inputs: Vec<Input>,
output_buffer: Option<&mut dyn std::fmt::Write>,
) -> Result<bool> {
self.run_with_error_handler(inputs, output_buffer, default_error_handler)
}

pub fn run_with_error_handler(
&self,
inputs: Vec<Input>,
output_buffer: Option<&mut dyn std::fmt::Write>,
handle_error: impl Fn(&Error, &mut dyn Write),
) -> Result<bool> {
let mut output_type;
Expand Down Expand Up @@ -74,24 +79,34 @@ impl<'b> Controller<'b> {
clircle::Identifier::stdout()
};

let writer = output_type.handle()?;
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();

for (index, input) in inputs.into_iter().enumerate() {
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 {
if attached_to_pager {
handle_error(&error, writer);
} else {
handle_error(&error, &mut stderr.lock());
match writer {
// 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);
} else {
handle_error(&error, &mut stderr.lock());
}
}
}
no_errors = false;
}
Expand All @@ -103,7 +118,7 @@ impl<'b> Controller<'b> {
fn print_input<R: BufRead>(
&self,
input: Input,
writer: &mut dyn Write,
writer: &mut OutputHandle,
stdin: R,
stdout_identifier: Option<&Identifier>,
is_first: bool,
Expand Down Expand Up @@ -164,7 +179,7 @@ impl<'b> Controller<'b> {
fn print_file(
&self,
printer: &mut dyn Printer,
writer: &mut dyn Write,
writer: &mut OutputHandle,
input: &mut OpenedInput,
add_header_padding: bool,
#[cfg(feature = "git")] line_changes: &Option<LineChanges>,
Expand Down Expand Up @@ -202,7 +217,7 @@ impl<'b> Controller<'b> {
fn print_file_ranges(
&self,
printer: &mut dyn Printer,
writer: &mut dyn Write,
writer: &mut OutputHandle,
reader: &mut InputReader,
line_ranges: &LineRanges,
) -> Result<()> {
Expand Down
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion src/pretty_printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
Loading

0 comments on commit b06f13f

Please sign in to comment.