Merge pull request #871 from neuronull/fix_654_stdin_filename

Implement --file-name<name> option
This commit is contained in:
David Peter 2020-03-26 09:35:01 +01:00 committed by GitHub
commit 37b3b8730d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 150 additions and 13 deletions

View File

@ -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()),
})
}

View File

@ -93,6 +93,18 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
'--highlight-line 40:' highlights lines 40 to the end of the file"
),
)
.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")

View File

@ -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]

View File

@ -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() {

View File

@ -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 {

BIN
tests/examples/test.binary vendored Normal file

Binary file not shown.

View File

@ -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();
}