Add InputDescription

This commit is contained in:
sharkdp 2020-04-21 22:24:47 +02:00 committed by David Peter
parent 3bacfc5184
commit f3b90ddb38
5 changed files with 139 additions and 107 deletions

View File

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

View File

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

View File

@ -7,6 +7,104 @@ use content_inspector::{self, ContentType};
use crate::errors::*;
const THEME_PREVIEW_FILE: &[u8] = include_bytes!("../assets/theme_preview.rs");
#[derive(Debug, Clone, PartialEq)]
pub struct OrdinaryFile {
path: OsString,
user_provided_path: Option<OsString>,
}
impl OrdinaryFile {
pub fn from_path(path: &OsStr) -> OrdinaryFile {
OrdinaryFile {
path: path.to_os_string(),
user_provided_path: None,
}
}
pub fn set_provided_path(&mut self, user_provided_path: &OsStr) {
self.user_provided_path = Some(user_provided_path.to_os_string());
}
pub(crate) fn provided_path<'a>(&'a self) -> &'a OsStr {
self.user_provided_path
.as_ref()
.unwrap_or_else(|| &self.path)
}
}
#[derive(Debug, Clone)]
pub struct InputDescription {
pub full: String,
pub prefix: String,
pub name: String,
}
pub enum Input {
StdIn(Option<OsString>),
Ordinary(OrdinaryFile),
FromReader(Box<dyn Read>, Option<OsString>),
ThemePreviewFile,
}
impl Input {
pub(crate) fn get_reader<'a, R: BufRead + 'a>(&self, stdin: R) -> Result<InputReader<'a>> {
match self {
Input::StdIn(_) => Ok(InputReader::new(stdin)),
Input::Ordinary(ofile) => {
let file = File::open(&ofile.path)
.map_err(|e| format!("'{}': {}", ofile.path.to_string_lossy(), e))?;
if file.metadata()?.is_dir() {
return Err(
format!("'{}' is a directory.", ofile.path.to_string_lossy()).into(),
);
}
Ok(InputReader::new(BufReader::new(file)))
}
Input::ThemePreviewFile => Ok(InputReader::new(THEME_PREVIEW_FILE)),
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>,
@ -52,60 +150,6 @@ impl<'a> InputReader<'a> {
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct OrdinaryFile {
path: OsString,
user_provided_path: Option<OsString>,
}
impl OrdinaryFile {
pub fn from_path(path: &OsStr) -> OrdinaryFile {
OrdinaryFile {
path: path.to_os_string(),
user_provided_path: None,
}
}
pub fn set_provided_path(&mut self, user_provided_path: &OsStr) {
self.user_provided_path = Some(user_provided_path.to_os_string());
}
pub(crate) fn provided_path<'a>(&'a self) -> &'a OsStr {
self.user_provided_path
.as_ref()
.unwrap_or_else(|| &self.path)
}
}
pub enum Input {
StdIn(Option<OsString>),
Ordinary(OrdinaryFile),
FromReader(Box<dyn Read>, Option<OsString>),
ThemePreviewFile,
}
impl Input {
pub(crate) fn get_reader<'a, R: BufRead + 'a>(&self, stdin: R) -> Result<InputReader<'a>> {
match self {
Input::StdIn(_) => Ok(InputReader::new(stdin)),
Input::Ordinary(ofile) => {
let file = File::open(&ofile.path)
.map_err(|e| format!("'{}': {}", ofile.path.to_string_lossy(), e))?;
if file.metadata()?.is_dir() {
return Err(
format!("'{}' is a directory.", ofile.path.to_string_lossy()).into(),
);
}
Ok(InputReader::new(BufReader::new(file)))
}
Input::ThemePreviewFile => Ok(InputReader::new(THEME_PREVIEW_FILE)),
Input::FromReader(_, _) => unimplemented!(), //Ok(InputReader::new(BufReader::new(reader))),
}
}
}
#[test]
fn basic() {
let content = b"#!/bin/bash\necho hello";

View File

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

View File

@ -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
)?;