mirror of
https://github.com/sharkdp/bat.git
synced 2024-11-23 00:03:27 +01:00
Add InputDescription
This commit is contained in:
parent
3bacfc5184
commit
f3b90ddb38
@ -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()
|
||||
}
|
||||
|
@ -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() {
|
||||
|
152
src/input.rs
152
src/input.rs
@ -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";
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
)?;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user