mirror of
https://github.com/sharkdp/bat.git
synced 2024-11-30 03:33:54 +01:00
Add InputDescription
This commit is contained in:
parent
3bacfc5184
commit
f3b90ddb38
@ -188,11 +188,11 @@ impl HighlightingAssets {
|
|||||||
pub(crate) fn get_syntax(
|
pub(crate) fn get_syntax(
|
||||||
&self,
|
&self,
|
||||||
language: Option<&str>,
|
language: Option<&str>,
|
||||||
file: &Input,
|
input: &Input,
|
||||||
reader: &mut InputReader,
|
reader: &mut InputReader,
|
||||||
mapping: &SyntaxMapping,
|
mapping: &SyntaxMapping,
|
||||||
) -> &SyntaxReference {
|
) -> &SyntaxReference {
|
||||||
let syntax = match (language, file) {
|
let syntax = match (language, input) {
|
||||||
(Some(language), _) => self.syntax_set.find_syntax_by_token(language),
|
(Some(language), _) => self.syntax_set.find_syntax_by_token(language),
|
||||||
(None, Input::Ordinary(ofile)) => {
|
(None, Input::Ordinary(ofile)) => {
|
||||||
let path = Path::new(ofile.provided_path());
|
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 input = Input::Ordinary(OrdinaryFile::from_path(file_path.as_os_str()));
|
||||||
let syntax = self.assets.get_syntax(
|
let stdin = io::stdin();
|
||||||
None,
|
let mut reader = input.get_reader(stdin.lock()).unwrap();
|
||||||
&input,
|
let syntax = self
|
||||||
&mut input.get_reader(io::stdin().lock()).unwrap(),
|
.assets
|
||||||
&self.syntax_mapping,
|
.get_syntax(None, &input, &mut reader, &self.syntax_mapping);
|
||||||
);
|
|
||||||
|
|
||||||
syntax.name.clone()
|
syntax.name.clone()
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use crate::config::Config;
|
|||||||
#[cfg(feature = "paging")]
|
#[cfg(feature = "paging")]
|
||||||
use crate::config::PagingMode;
|
use crate::config::PagingMode;
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::input::{Input, InputReader};
|
use crate::input::{Input, InputDescription, InputReader};
|
||||||
use crate::line_range::{LineRanges, RangeCheckResult};
|
use crate::line_range::{LineRanges, RangeCheckResult};
|
||||||
use crate::output::OutputType;
|
use crate::output::OutputType;
|
||||||
use crate::printer::{InteractivePrinter, Printer, SimplePrinter};
|
use crate::printer::{InteractivePrinter, Printer, SimplePrinter};
|
||||||
@ -61,6 +61,8 @@ impl<'b> Controller<'b> {
|
|||||||
let mut no_errors: bool = true;
|
let mut no_errors: bool = true;
|
||||||
|
|
||||||
for input in inputs.into_iter() {
|
for input in inputs.into_iter() {
|
||||||
|
let description = input.description();
|
||||||
|
|
||||||
match input.get_reader(io::stdin().lock()) {
|
match input.get_reader(io::stdin().lock()) {
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
handle_error(&error);
|
handle_error(&error);
|
||||||
@ -69,7 +71,7 @@ impl<'b> Controller<'b> {
|
|||||||
Ok(mut reader) => {
|
Ok(mut reader) => {
|
||||||
let result = if self.config.loop_through {
|
let result = if self.config.loop_through {
|
||||||
let mut printer = SimplePrinter::new();
|
let mut printer = SimplePrinter::new();
|
||||||
self.print_file(reader, &mut printer, writer, &input)
|
self.print_file(reader, &mut printer, writer, &description)
|
||||||
} else {
|
} else {
|
||||||
let mut printer = InteractivePrinter::new(
|
let mut printer = InteractivePrinter::new(
|
||||||
&self.config,
|
&self.config,
|
||||||
@ -77,7 +79,7 @@ impl<'b> Controller<'b> {
|
|||||||
&input,
|
&input,
|
||||||
&mut reader,
|
&mut reader,
|
||||||
);
|
);
|
||||||
self.print_file(reader, &mut printer, writer, &input)
|
self.print_file(reader, &mut printer, writer, &description)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(error) = result {
|
if let Err(error) = result {
|
||||||
@ -96,10 +98,10 @@ impl<'b> Controller<'b> {
|
|||||||
reader: InputReader,
|
reader: InputReader,
|
||||||
printer: &mut P,
|
printer: &mut P,
|
||||||
writer: &mut dyn Write,
|
writer: &mut dyn Write,
|
||||||
input: &Input,
|
input_description: &InputDescription,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if !reader.first_line.is_empty() || self.config.style_components.header() {
|
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() {
|
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::*;
|
use crate::errors::*;
|
||||||
|
|
||||||
const THEME_PREVIEW_FILE: &[u8] = include_bytes!("../assets/theme_preview.rs");
|
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> {
|
pub struct InputReader<'a> {
|
||||||
inner: Box<dyn BufRead + '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]
|
#[test]
|
||||||
fn basic() {
|
fn basic() {
|
||||||
let content = b"#!/bin/bash\necho hello";
|
let content = b"#!/bin/bash\necho hello";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
config::{
|
||||||
@ -52,6 +53,18 @@ impl<'a> PrettyPrinter<'a> {
|
|||||||
self
|
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)
|
/// Specify the syntax file which should be used (default: auto-detect)
|
||||||
pub fn language(&mut self, language: &'a str) -> &mut Self {
|
pub fn language(&mut self, language: &'a str) -> &mut Self {
|
||||||
self.config.language = Some(language);
|
self.config.language = Some(language);
|
||||||
|
@ -27,14 +27,14 @@ use crate::decorations::{Decoration, GridBorderDecoration, LineNumberDecoration}
|
|||||||
#[cfg(feature = "git")]
|
#[cfg(feature = "git")]
|
||||||
use crate::diff::{get_git_diff, LineChanges};
|
use crate::diff::{get_git_diff, LineChanges};
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::input::{Input, InputReader};
|
use crate::input::{Input, InputDescription, InputReader};
|
||||||
use crate::line_range::RangeCheckResult;
|
use crate::line_range::RangeCheckResult;
|
||||||
use crate::preprocessor::{expand_tabs, replace_nonprintable};
|
use crate::preprocessor::{expand_tabs, replace_nonprintable};
|
||||||
use crate::terminal::{as_terminal_escaped, to_ansi_color};
|
use crate::terminal::{as_terminal_escaped, to_ansi_color};
|
||||||
use crate::wrap::WrappingMode;
|
use crate::wrap::WrappingMode;
|
||||||
|
|
||||||
pub trait Printer {
|
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_footer(&mut self, handle: &mut dyn Write) -> Result<()>;
|
||||||
|
|
||||||
fn print_snip(&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 {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ impl<'a> InteractivePrinter<'a> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
assets: &'a HighlightingAssets,
|
assets: &'a HighlightingAssets,
|
||||||
file: &Input,
|
input: &Input,
|
||||||
reader: &mut InputReader,
|
reader: &mut InputReader,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let theme = assets.get_theme(&config.theme);
|
let theme = assets.get_theme(&config.theme);
|
||||||
@ -160,14 +160,14 @@ impl<'a> InteractivePrinter<'a> {
|
|||||||
#[cfg(feature = "git")]
|
#[cfg(feature = "git")]
|
||||||
{
|
{
|
||||||
if config.style_components.changes() {
|
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());
|
line_changes = get_git_diff(ofile.provided_path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the type of syntax for highlighting
|
// 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))
|
Some(HighlightLines::new(syntax, theme))
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -230,32 +230,20 @@ impl<'a> InteractivePrinter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Printer for 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 !self.config.style_components.header() {
|
||||||
if Some(ContentType::BINARY) == self.content_type && !self.config.show_nonprintable {
|
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!(
|
writeln!(
|
||||||
handle,
|
handle,
|
||||||
"{}: Binary content from {} will not be printed to the terminal \
|
"{}: 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' \
|
(but will be present if the output of 'bat' is piped). You can use 'bat -A' \
|
||||||
to show the binary file contents.",
|
to show the binary file contents.",
|
||||||
Yellow.paint("[bat warning]"),
|
Yellow.paint("[bat warning]"),
|
||||||
input
|
description.full,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
if self.config.style_components.grid() {
|
if self.config.style_components.grid() {
|
||||||
@ -280,20 +268,6 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
|||||||
write!(handle, "{}", " ".repeat(self.panel_width))?;
|
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 {
|
let mode = match self.content_type {
|
||||||
Some(ContentType::BINARY) => " <BINARY>",
|
Some(ContentType::BINARY) => " <BINARY>",
|
||||||
Some(ContentType::UTF_16LE) => " <UTF-16LE>",
|
Some(ContentType::UTF_16LE) => " <UTF-16LE>",
|
||||||
@ -305,8 +279,8 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
|||||||
writeln!(
|
writeln!(
|
||||||
handle,
|
handle,
|
||||||
"{}{}{}",
|
"{}{}{}",
|
||||||
prefix,
|
description.prefix,
|
||||||
self.colors.filename.paint(name),
|
self.colors.filename.paint(&description.name),
|
||||||
mode
|
mode
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user