diff options
author | David Peter <sharkdp@users.noreply.github.com> | 2020-03-26 09:35:01 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-26 09:35:01 +0100 |
commit | 37b3b8730d313cef0fc9faa1e1ecc98406c62ed7 (patch) | |
tree | 73a877580e4fe5cdce42bc99a35c555750e07918 | |
parent | 7c50fe5fecf94199a43a07db3d329135fb012cea (diff) | |
parent | 83772bd2cfd2603fd4185ee26cdd883383ad46cb (diff) |
Merge pull request #871 from neuronull/fix_654_stdin_filename
Implement --file-name<name> option
-rw-r--r-- | src/bin/bat/app.rs | 11 | ||||
-rw-r--r-- | src/bin/bat/clap_app.rs | 12 | ||||
-rw-r--r-- | src/config.rs | 3 | ||||
-rw-r--r-- | src/controller.rs | 14 | ||||
-rw-r--r-- | src/printer.rs | 37 | ||||
-rw-r--r-- | tests/examples/test.binary | bin | 0 -> 4 bytes | |||
-rw-r--r-- | tests/integration_tests.rs | 86 |
7 files changed, 150 insertions, 13 deletions
diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index ae889453..542e5d99 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -136,6 +136,13 @@ impl App { } }); + match self.matches.values_of("file-name") { + Some(filenames) if filenames.len() != files.len() => { + return Err(format!("{} {}", filenames.len(), files.len()).into()); + } + _ => {} + } + Ok(Config { true_color: is_truecolor_terminal(), language: self.matches.value_of("language").or_else(|| { @@ -222,6 +229,10 @@ impl App { .map(LineRanges::from) .map(|lr| HighlightedLineRanges(lr)) .unwrap_or_default(), + filenames: self + .matches + .values_of("file-name") + .map(|values| values.collect()), }) } diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs index 2f7c0a5a..c2505ca9 100644 --- a/src/bin/bat/clap_app.rs +++ b/src/bin/bat/clap_app.rs @@ -94,6 +94,18 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> { ), ) .arg( + Arg::with_name("file-name") + .long("file-name") + .takes_value(true) + .number_of_values(1) + .multiple(true) + .value_name("name") + .help("Specify the name to display for a file.") + .long_help("Specify the name to display for a file. Useful when piping \ + data to bat from STDIN when bat does not otherwise know \ + the filename."), + ) + .arg( Arg::with_name("tabs") .long("tabs") .overrides_with("tabs") diff --git a/src/config.rs b/src/config.rs index 19e91484..6a0c2530 100644 --- a/src/config.rs +++ b/src/config.rs @@ -70,6 +70,9 @@ pub struct Config<'a> { /// Ranges of lines which should be highlighted with a special background color pub highlighted_lines: HighlightedLineRanges, + + /// Names of files to display when printing + pub filenames: Option<Vec<&'a str>>, } #[test] diff --git a/src/controller.rs b/src/controller.rs index ee1a1be3..90e465bd 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -45,7 +45,12 @@ impl<'b> Controller<'b> { let stdin = io::stdin(); - for input_file in &self.config.files { + let filenames: Box<dyn Iterator<Item = _>> = match self.config.filenames { + Some(ref filenames) => Box::new(filenames.into_iter().map(|name| Some(*name))), + None => Box::new(std::iter::repeat(None)), + }; + + for (input_file, file_name) in self.config.files.iter().zip(filenames) { match input_file.get_reader(&stdin) { Err(error) => { handle_error(&error); @@ -54,7 +59,7 @@ impl<'b> Controller<'b> { Ok(mut reader) => { let result = if self.config.loop_through { let mut printer = SimplePrinter::new(); - self.print_file(reader, &mut printer, writer, *input_file) + self.print_file(reader, &mut printer, writer, *input_file, file_name) } else { let mut printer = InteractivePrinter::new( &self.config, @@ -62,7 +67,7 @@ impl<'b> Controller<'b> { *input_file, &mut reader, ); - self.print_file(reader, &mut printer, writer, *input_file) + self.print_file(reader, &mut printer, writer, *input_file, file_name) }; if let Err(error) = result { @@ -82,9 +87,10 @@ impl<'b> Controller<'b> { printer: &mut P, writer: &mut dyn Write, input_file: InputFile<'a>, + file_name: Option<&str>, ) -> Result<()> { if !reader.first_line.is_empty() || self.config.style_components.header() { - printer.print_header(writer, input_file)?; + printer.print_header(writer, input_file, file_name)?; } if !reader.first_line.is_empty() { diff --git a/src/printer.rs b/src/printer.rs index 629b11da..3924cd62 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -34,7 +34,12 @@ use crate::terminal::{as_terminal_escaped, to_ansi_color}; use crate::wrap::OutputWrap; pub trait Printer { - fn print_header(&mut self, handle: &mut dyn Write, file: InputFile) -> Result<()>; + fn print_header( + &mut self, + handle: &mut dyn Write, + file: InputFile, + file_name: Option<&str>, + ) -> Result<()>; fn print_footer(&mut self, handle: &mut dyn Write) -> Result<()>; fn print_snip(&mut self, handle: &mut dyn Write) -> Result<()>; @@ -57,7 +62,12 @@ impl SimplePrinter { } impl Printer for SimplePrinter { - fn print_header(&mut self, _handle: &mut dyn Write, _file: InputFile) -> Result<()> { + fn print_header( + &mut self, + _handle: &mut dyn Write, + _file: InputFile, + _file_name: Option<&str>, + ) -> Result<()> { Ok(()) } @@ -224,14 +234,20 @@ impl<'a> InteractivePrinter<'a> { } impl<'a> Printer for InteractivePrinter<'a> { - fn print_header(&mut self, handle: &mut dyn Write, file: InputFile) -> Result<()> { + fn print_header( + &mut self, + handle: &mut dyn Write, + file: InputFile, + file_name: Option<&str>, + ) -> Result<()> { if !self.config.style_components.header() { if Some(ContentType::BINARY) == self.content_type && !self.config.show_nonprintable { let input = match file { - InputFile::Ordinary(filename) => { - format!("file '{}'", filename.to_string_lossy()) - } - _ => "STDIN".into(), + InputFile::Ordinary(filename) => format!( + "file '{}'", + file_name.unwrap_or(&filename.to_string_lossy()) + ), + _ => file_name.unwrap_or("STDIN").to_owned(), }; writeln!( @@ -266,8 +282,11 @@ impl<'a> Printer for InteractivePrinter<'a> { } let (prefix, name) = match file { - InputFile::Ordinary(filename) => ("File: ", filename.to_string_lossy()), - _ => ("", Cow::from("STDIN")), + InputFile::Ordinary(filename) => ( + "File: ", + Cow::from(file_name.unwrap_or(&filename.to_string_lossy()).to_owned()), + ), + _ => ("File: ", Cow::from(file_name.unwrap_or("STDIN").to_owned())), }; let mode = match self.content_type { diff --git a/tests/examples/test.binary b/tests/examples/test.binary Binary files differnew file mode 100644 index 00000000..593f4708 --- /dev/null +++ b/tests/examples/test.binary diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 0d5f4a3c..7750f6cd 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -541,3 +541,89 @@ fn empty_file_leads_to_empty_output_with_grid_enabled() { .success() .stdout(""); } + +#[test] +fn filename_basic() { + bat() + .arg("test.txt") + .arg("--decorations=always") + .arg("--style=header") + .arg("-r=0:0") + .arg("--file-name=foo") + .assert() + .success() + .stdout("File: foo\n") + .stderr(""); +} + +#[test] +fn filename_binary() { + bat() + .arg("test.binary") + .arg("--decorations=always") + .arg("--style=header") + .arg("-r=0:0") + .arg("--file-name=foo") + .assert() + .success() + .stdout("File: foo <BINARY>\n") + .stderr(""); +} + +#[test] +fn filename_stdin() { + bat() + .arg("--decorations=always") + .arg("--style=header") + .arg("-r=0:0") + .arg("-") + .write_stdin("stdin\n") + .arg("--file-name=foo") + .assert() + .success() + .stdout("File: foo\n") + .stderr(""); +} + +#[test] +fn filename_stdin_binary() { + let vec = vec![0; 1]; + bat_with_config() + .arg("--decorations=always") + .arg("--style=header") + .write_stdin(vec) + .arg("--file-name=foo") + .assert() + .success() + .stdout("File: foo <BINARY>\n") + .stderr(""); +} + +#[test] +fn filename_multiple_ok() { + bat() + .arg("--decorations=always") + .arg("--style=header") + .arg("-r=0:0") + .arg("test.txt") + .arg("--file-name=foo") + .arg("single-line.txt") + .arg("--file-name=bar") + .assert() + .success() + .stdout("File: foo\nFile: bar\n") + .stderr(""); +} + +#[test] +fn filename_multiple_err() { + bat() + .arg("--decorations=always") + .arg("--style=header") + .arg("-r=0:0") + .arg("test.txt") + .arg("--file-name=foo") + .arg("single-line.txt") + .assert() + .failure(); +} |