Skip to content

Commit b06f13f

Browse files
authored
Merge pull request #2618 from Piturnah/feat/write-to-buffer
feat: Optionally write to a buffer instead of stdout
2 parents 1e52785 + 72e1a40 commit b06f13f

File tree

6 files changed

+141
-55
lines changed

6 files changed

+141
-55
lines changed

examples/buffer.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use bat::{assets::HighlightingAssets, config::Config, controller::Controller, Input};
2+
3+
fn main() {
4+
let mut buffer = String::new();
5+
let config = Config {
6+
colored_output: true,
7+
..Default::default()
8+
};
9+
let assets = HighlightingAssets::from_binary();
10+
let controller = Controller::new(&config, &assets);
11+
let input = Input::from_file(file!());
12+
controller
13+
.run(vec![input.into()], Some(&mut buffer))
14+
.unwrap();
15+
16+
println!("{buffer}");
17+
}

src/bin/bat/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result<
206206
)?;
207207
config.theme = theme.to_string();
208208
Controller::new(&config, &assets)
209-
.run(vec![theme_preview_file()])
209+
.run(vec![theme_preview_file()], None)
210210
.ok();
211211
writeln!(stdout)?;
212212
}
@@ -230,7 +230,7 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result<
230230
fn run_controller(inputs: Vec<Input>, config: &Config, cache_dir: &Path) -> Result<bool> {
231231
let assets = assets_from_cache_or_binary(config.use_custom_assets, cache_dir)?;
232232
let controller = Controller::new(config, &assets);
233-
controller.run(inputs)
233+
controller.run(inputs, None)
234234
}
235235

236236
#[cfg(feature = "bugreport")]

src/controller.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::line_range::{LineRanges, RangeCheckResult};
1212
use crate::output::OutputType;
1313
#[cfg(feature = "paging")]
1414
use crate::paging::PagingMode;
15-
use crate::printer::{InteractivePrinter, Printer, SimplePrinter};
15+
use crate::printer::{InteractivePrinter, OutputHandle, Printer, SimplePrinter};
1616

1717
use clircle::{Clircle, Identifier};
1818

@@ -26,13 +26,18 @@ impl<'b> Controller<'b> {
2626
Controller { config, assets }
2727
}
2828

29-
pub fn run(&self, inputs: Vec<Input>) -> Result<bool> {
30-
self.run_with_error_handler(inputs, default_error_handler)
29+
pub fn run(
30+
&self,
31+
inputs: Vec<Input>,
32+
output_buffer: Option<&mut dyn std::fmt::Write>,
33+
) -> Result<bool> {
34+
self.run_with_error_handler(inputs, output_buffer, default_error_handler)
3135
}
3236

3337
pub fn run_with_error_handler(
3438
&self,
3539
inputs: Vec<Input>,
40+
output_buffer: Option<&mut dyn std::fmt::Write>,
3641
handle_error: impl Fn(&Error, &mut dyn Write),
3742
) -> Result<bool> {
3843
let mut output_type;
@@ -74,24 +79,34 @@ impl<'b> Controller<'b> {
7479
clircle::Identifier::stdout()
7580
};
7681

77-
let writer = output_type.handle()?;
82+
let mut writer = match output_buffer {
83+
Some(buf) => OutputHandle::FmtWrite(buf),
84+
None => OutputHandle::IoWrite(output_type.handle()?),
85+
};
7886
let mut no_errors: bool = true;
7987
let stderr = io::stderr();
8088

8189
for (index, input) in inputs.into_iter().enumerate() {
8290
let identifier = stdout_identifier.as_ref();
8391
let is_first = index == 0;
8492
let result = if input.is_stdin() {
85-
self.print_input(input, writer, io::stdin().lock(), identifier, is_first)
93+
self.print_input(input, &mut writer, io::stdin().lock(), identifier, is_first)
8694
} else {
8795
// Use dummy stdin since stdin is actually not used (#1902)
88-
self.print_input(input, writer, io::empty(), identifier, is_first)
96+
self.print_input(input, &mut writer, io::empty(), identifier, is_first)
8997
};
9098
if let Err(error) = result {
91-
if attached_to_pager {
92-
handle_error(&error, writer);
93-
} else {
94-
handle_error(&error, &mut stderr.lock());
99+
match writer {
100+
// It doesn't make much sense to send errors straight to stderr if the user
101+
// provided their own buffer, so we just return it.
102+
OutputHandle::FmtWrite(_) => return Err(error),
103+
OutputHandle::IoWrite(ref mut writer) => {
104+
if attached_to_pager {
105+
handle_error(&error, writer);
106+
} else {
107+
handle_error(&error, &mut stderr.lock());
108+
}
109+
}
95110
}
96111
no_errors = false;
97112
}
@@ -103,7 +118,7 @@ impl<'b> Controller<'b> {
103118
fn print_input<R: BufRead>(
104119
&self,
105120
input: Input,
106-
writer: &mut dyn Write,
121+
writer: &mut OutputHandle,
107122
stdin: R,
108123
stdout_identifier: Option<&Identifier>,
109124
is_first: bool,
@@ -164,7 +179,7 @@ impl<'b> Controller<'b> {
164179
fn print_file(
165180
&self,
166181
printer: &mut dyn Printer,
167-
writer: &mut dyn Write,
182+
writer: &mut OutputHandle,
168183
input: &mut OpenedInput,
169184
add_header_padding: bool,
170185
#[cfg(feature = "git")] line_changes: &Option<LineChanges>,
@@ -202,7 +217,7 @@ impl<'b> Controller<'b> {
202217
fn print_file_ranges(
203218
&self,
204219
printer: &mut dyn Printer,
205-
writer: &mut dyn Write,
220+
writer: &mut OutputHandle,
206221
reader: &mut InputReader,
207222
line_ranges: &LineRanges,
208223
) -> Result<()> {

src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ pub enum Error {
77
#[error(transparent)]
88
Io(#[from] ::std::io::Error),
99
#[error(transparent)]
10+
Fmt(#[from] ::std::fmt::Error),
11+
#[error(transparent)]
1012
SyntectError(#[from] ::syntect::Error),
1113
#[error(transparent)]
1214
SyntectLoadingError(#[from] ::syntect::LoadingError),

src/pretty_printer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ impl<'a> PrettyPrinter<'a> {
300300

301301
// Run the controller
302302
let controller = Controller::new(&self.config, &self.assets);
303-
controller.run(inputs.into_iter().map(|i| i.into()).collect())
303+
controller.run(inputs.into_iter().map(|i| i.into()).collect(), None)
304304
}
305305
}
306306

0 commit comments

Comments
 (0)