summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Peter <sharkdp@users.noreply.github.com>2020-03-26 09:35:01 +0100
committerGitHub <noreply@github.com>2020-03-26 09:35:01 +0100
commit37b3b8730d313cef0fc9faa1e1ecc98406c62ed7 (patch)
tree73a877580e4fe5cdce42bc99a35c555750e07918
parent7c50fe5fecf94199a43a07db3d329135fb012cea (diff)
parent83772bd2cfd2603fd4185ee26cdd883383ad46cb (diff)
Merge pull request #871 from neuronull/fix_654_stdin_filename
Implement --file-name<name> option
-rw-r--r--src/bin/bat/app.rs11
-rw-r--r--src/bin/bat/clap_app.rs12
-rw-r--r--src/config.rs3
-rw-r--r--src/controller.rs14
-rw-r--r--src/printer.rs37
-rw-r--r--tests/examples/test.binarybin0 -> 4 bytes
-rw-r--r--tests/integration_tests.rs86
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
new file mode 100644
index 00000000..593f4708
--- /dev/null
+++ b/tests/examples/test.binary
Binary files differ
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();
+}