diff options
author | sharkdp <davidpeter@web.de> | 2020-04-21 22:24:47 +0200 |
---|---|---|
committer | David Peter <sharkdp@users.noreply.github.com> | 2020-04-22 23:55:28 +0200 |
commit | f3b90ddb383cfcbd575f24785a5a9400870d162e (patch) | |
tree | 9c81e6f1d1fa50b0e9df37d9c2a9a3c6a7feb150 | |
parent | 3bacfc5184184c4a845d56f9e7226e87eae6d172 (diff) |
Add InputDescription
-rw-r--r-- | src/assets.rs | 15 | ||||
-rw-r--r-- | src/controller.rs | 12 | ||||
-rw-r--r-- | src/input.rs | 134 | ||||
-rw-r--r-- | src/pretty_printer.rs | 13 | ||||
-rw-r--r-- | src/printer.rs | 54 |
5 files changed, 130 insertions, 98 deletions
diff --git a/src/assets.rs b/src/assets.rs index 55bf3ef0..f6b10b3a 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -188,11 +188,11 @@ impl HighlightingAssets { pub(crate) fn get_syntax( &self, language: Option<&str>, - file: &Input, + input: &Input, reader: &mut InputReader, mapping: &SyntaxMapping, ) -> &SyntaxReference { - let syntax = match (language, file) { + let syntax = match (language, input) { (Some(language), _) => self.syntax_set.find_syntax_by_token(language), (None, Input::Ordinary(ofile)) => { let path = Path::new(ofile.provided_path()); @@ -282,12 +282,11 @@ mod tests { } let input = Input::Ordinary(OrdinaryFile::from_path(file_path.as_os_str())); - let syntax = self.assets.get_syntax( - None, - &input, - &mut input.get_reader(io::stdin().lock()).unwrap(), - &self.syntax_mapping, - ); + let stdin = io::stdin(); + let mut reader = input.get_reader(stdin.lock()).unwrap(); + let syntax = self + .assets + .get_syntax(None, &input, &mut reader, &self.syntax_mapping); syntax.name.clone() } diff --git a/src/controller.rs b/src/controller.rs index f9cf78ac..8d6b7fe0 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -5,7 +5,7 @@ use crate::config::Config; #[cfg(feature = "paging")] use crate::config::PagingMode; use crate::errors::*; -use crate::input::{Input, InputReader}; +use crate::input::{Input, InputDescription, InputReader}; use crate::line_range::{LineRanges, RangeCheckResult}; use crate::output::OutputType; use crate::printer::{InteractivePrinter, Printer, SimplePrinter}; @@ -61,6 +61,8 @@ impl<'b> Controller<'b> { let mut no_errors: bool = true; for input in inputs.into_iter() { + let description = input.description(); + match input.get_reader(io::stdin().lock()) { Err(error) => { handle_error(&error); @@ -69,7 +71,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) + self.print_file(reader, &mut printer, writer, &description) } else { let mut printer = InteractivePrinter::new( &self.config, @@ -77,7 +79,7 @@ impl<'b> Controller<'b> { &input, &mut reader, ); - self.print_file(reader, &mut printer, writer, &input) + self.print_file(reader, &mut printer, writer, &description) }; if let Err(error) = result { @@ -96,10 +98,10 @@ impl<'b> Controller<'b> { reader: InputReader, printer: &mut P, writer: &mut dyn Write, - input: &Input, + input_description: &InputDescription, ) -> Result<()> { if !reader.first_line.is_empty() || self.config.style_components.header() { - printer.print_header(writer, input)?; + printer.print_header(writer, input_description)?; } if !reader.first_line.is_empty() { diff --git a/src/input.rs b/src/input.rs index 7b2c371f..7b464824 100644 --- a/src/input.rs +++ b/src/input.rs @@ -7,51 +7,6 @@ use content_inspector::{self, ContentType}; use crate::errors::*; const THEME_PREVIEW_FILE: &[u8] = include_bytes!("../assets/theme_preview.rs"); - -pub struct InputReader<'a> { - inner: Box<dyn BufRead + 'a>, - pub(crate) first_line: Vec<u8>, - pub(crate) content_type: Option<ContentType>, -} - -impl<'a> InputReader<'a> { - fn new<R: BufRead + 'a>(mut reader: R) -> InputReader<'a> { - let mut first_line = vec![]; - reader.read_until(b'\n', &mut first_line).ok(); - - let content_type = if first_line.is_empty() { - None - } else { - Some(content_inspector::inspect(&first_line[..])) - }; - - if content_type == Some(ContentType::UTF_16LE) { - reader.read_until(0x00, &mut first_line).ok(); - } - - InputReader { - inner: Box::new(reader), - first_line, - content_type, - } - } - - pub(crate) fn read_line(&mut self, buf: &mut Vec<u8>) -> io::Result<bool> { - if self.first_line.is_empty() { - let res = self.inner.read_until(b'\n', buf).map(|size| size > 0)?; - - if self.content_type == Some(ContentType::UTF_16LE) { - self.inner.read_until(0x00, buf).ok(); - } - - Ok(res) - } else { - buf.append(&mut self.first_line); - Ok(true) - } - } -} - #[derive(Debug, Clone, PartialEq)] pub struct OrdinaryFile { path: OsString, @@ -77,6 +32,13 @@ impl OrdinaryFile { } } +#[derive(Debug, Clone)] +pub struct InputDescription { + pub full: String, + pub prefix: String, + pub name: String, +} + pub enum Input { StdIn(Option<OsString>), Ordinary(OrdinaryFile), @@ -104,6 +66,88 @@ impl Input { Input::FromReader(_, _) => unimplemented!(), //Ok(InputReader::new(BufReader::new(reader))), } } + + pub(crate) fn description(&self) -> InputDescription { + match self { + Input::Ordinary(ofile) => InputDescription { + full: format!("file '{}'", &ofile.provided_path().to_string_lossy()), + prefix: "File: ".to_owned(), + name: ofile.provided_path().to_string_lossy().into_owned(), + }, + Input::StdIn(Some(name)) => InputDescription { + full: format!( + "STDIN (with name '{}')", + name.to_string_lossy().into_owned() + ), + prefix: "File: ".to_owned(), + name: name.to_string_lossy().into_owned(), + }, + Input::StdIn(None) => InputDescription { + full: "STDIN".to_owned(), + prefix: "".to_owned(), + name: "STDIN".to_owned(), + }, + Input::ThemePreviewFile => InputDescription { + full: "".to_owned(), + prefix: "".to_owned(), + name: "".to_owned(), + }, + Input::FromReader(_, Some(name)) => InputDescription { + full: format!("file '{}'", name.to_string_lossy()), + prefix: "File: ".to_owned(), + name: name.to_string_lossy().into_owned(), + }, + Input::FromReader(_, None) => InputDescription { + full: "reader".to_owned(), + prefix: "".to_owned(), + name: "READER".into(), + }, + } + } +} + +pub struct InputReader<'a> { + inner: Box<dyn BufRead + 'a>, + pub(crate) first_line: Vec<u8>, + pub(crate) content_type: Option<ContentType>, +} + +impl<'a> InputReader<'a> { + fn new<R: BufRead + 'a>(mut reader: R) -> InputReader<'a> { + let mut first_line = vec![]; + reader.read_until(b'\n', &mut first_line).ok(); + + let content_type = if first_line.is_empty() { + None + } else { + Some(content_inspector::inspect(&first_line[..])) + }; + + if content_type == Some(ContentType::UTF_16LE) { + reader.read_until(0x00, &mut first_line).ok(); + } + + InputReader { + inner: Box::new(reader), + first_line, + content_type, + } + } + + pub(crate) fn read_line(&mut self, buf: &mut Vec<u8>) -> io::Result<bool> { + if self.first_line.is_empty() { + let res = self.inner.read_until(b'\n', buf).map(|size| size > 0)?; + + if self.content_type == Some(ContentType::UTF_16LE) { + self.inner.read_until(0x00, buf).ok(); + } + + Ok(res) + } else { + buf.append(&mut self.first_line); + Ok(true) + } + } } #[test] diff --git a/src/pretty_printer.rs b/src/pretty_printer.rs index a03b0e3b..5b58526f 100644 --- a/src/pretty_printer.rs +++ b/src/pretty_printer.rs @@ -1,4 +1,5 @@ use std::ffi::OsStr; +use std::io::Read; use crate::{ config::{ @@ -52,6 +53,18 @@ impl<'a> PrettyPrinter<'a> { self } + /// Add STDIN as an input + pub fn input_stdin(&mut self) -> &mut Self { + self.inputs.push(Input::StdIn(None)); + self + } + + /// Add STDIN as an input + pub fn input_reader(&mut self, reader: impl Read) -> &mut Self { + //self.inputs.push(Input::FromReader(Box::new(reader), None)); + self + } + /// Specify the syntax file which should be used (default: auto-detect) pub fn language(&mut self, language: &'a str) -> &mut Self { self.config.language = Some(language); diff --git a/src/printer.rs b/src/printer.rs index b61c8063..0fc914f2 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -27,14 +27,14 @@ use crate::decorations::{Decoration, GridBorderDecoration, LineNumberDecoration} #[cfg(feature = "git")] use crate::diff::{get_git_diff, LineChanges}; use crate::errors::*; -use crate::input::{Input, InputReader}; +use crate::input::{Input, InputDescription, InputReader}; use crate::line_range::RangeCheckResult; use crate::preprocessor::{expand_tabs, replace_nonprintable}; use crate::terminal::{as_terminal_escaped, to_ansi_color}; use crate::wrap::WrappingMode; pub trait Printer { - fn print_header(&mut self, handle: &mut dyn Write, file: &Input) -> Result<()>; + fn print_header(&mut self, handle: &mut dyn Write, input: &InputDescription) -> Result<()>; fn print_footer(&mut self, handle: &mut dyn Write) -> Result<()>; fn print_snip(&mut self, handle: &mut dyn Write) -> Result<()>; @@ -57,7 +57,7 @@ impl SimplePrinter { } impl Printer for SimplePrinter { - fn print_header(&mut self, _handle: &mut dyn Write, _file: &Input) -> Result<()> { + fn print_header(&mut self, _handle: &mut dyn Write, input: &InputDescription) -> Result<()> { Ok(()) } @@ -101,7 +101,7 @@ impl<'a> InteractivePrinter<'a> { pub fn new( config: &'a Config, assets: &'a HighlightingAssets, - file: &Input, + input: &Input, reader: &mut InputReader, ) -> Self { let theme = assets.get_theme(&config.theme); @@ -160,14 +160,14 @@ impl<'a> InteractivePrinter<'a> { #[cfg(feature = "git")] { if config.style_components.changes() { - if let Input::Ordinary(ofile) = file { + if let Input::Ordinary(ofile) = input { line_changes = get_git_diff(ofile.provided_path()); } } } // Determine the type of syntax for highlighting - let syntax = assets.get_syntax(config.language, file, reader, &config.syntax_mapping); + let syntax = assets.get_syntax(config.language, input, reader, &config.syntax_mapping); Some(HighlightLines::new(syntax, theme)) }; @@ -230,32 +230,20 @@ impl<'a> InteractivePrinter<'a> { } impl<'a> Printer for InteractivePrinter<'a> { - fn print_header(&mut self, handle: &mut dyn Write, file: &Input) -> Result<()> { + fn print_header( + &mut self, + handle: &mut dyn Write, + description: &InputDescription, + ) -> Result<()> { if !self.config.style_components.header() { if Some(ContentType::BINARY) == self.content_type && !self.config.show_nonprintable { - let input = match file { - Input::Ordinary(ofile) => { - format!("file '{}'", &ofile.provided_path().to_string_lossy()) - } - Input::StdIn(Some(name)) => format!( - "STDIN (with name '{}')", - name.to_string_lossy().into_owned() - ), - Input::StdIn(None) => "STDIN".to_owned(), - Input::ThemePreviewFile => "".to_owned(), - Input::FromReader(_, Some(name)) => { - format!("file '{}'", name.to_string_lossy()) - } - Input::FromReader(_, None) => "READER".to_owned(), - }; - writeln!( handle, "{}: Binary content from {} will not be printed to the terminal \ (but will be present if the output of 'bat' is piped). You can use 'bat -A' \ to show the binary file contents.", Yellow.paint("[bat warning]"), - input + description.full, )?; } else { if self.config.style_components.grid() { @@ -280,20 +268,6 @@ impl<'a> Printer for InteractivePrinter<'a> { write!(handle, "{}", " ".repeat(self.panel_width))?; } - let (prefix, name) = match file { - Input::Ordinary(ofile) => ( - "File: ", - Cow::from(ofile.provided_path().to_string_lossy().to_owned()), - ), - Input::StdIn(Some(name)) => ("File: ", Cow::from(name.to_string_lossy().to_owned())), - Input::StdIn(None) => ("File: ", Cow::from("STDIN".to_owned())), - Input::ThemePreviewFile => ("", Cow::from("")), - Input::FromReader(_, Some(name)) => { - ("File: ", Cow::from(name.to_string_lossy().to_owned())) - } - Input::FromReader(_, None) => ("File: ", Cow::from("READER".to_owned())), - }; - let mode = match self.content_type { Some(ContentType::BINARY) => " <BINARY>", Some(ContentType::UTF_16LE) => " <UTF-16LE>", @@ -305,8 +279,8 @@ impl<'a> Printer for InteractivePrinter<'a> { writeln!( handle, "{}{}{}", - prefix, - self.colors.filename.paint(name), + description.prefix, + self.colors.filename.paint(&description.name), mode )?; |