Separate inputs from config

This commit is contained in:
sharkdp 2020-04-21 21:14:44 +02:00 committed by David Peter
parent 5e5cb89da6
commit 1dc328ad49
10 changed files with 61 additions and 41 deletions

View File

@ -4,14 +4,16 @@ use bat::{PrettyPrinter, StyleComponent, StyleComponents};
use console::Term; use console::Term;
fn main() { fn main() {
PrettyPrinter::new() let mut printer = PrettyPrinter::new();
printer
.term_width(Term::stdout().size().1 as usize) .term_width(Term::stdout().size().1 as usize)
.style_components(StyleComponents::new(&[ .style_components(StyleComponents::new(&[
StyleComponent::Header, StyleComponent::Header,
StyleComponent::Grid, StyleComponent::Grid,
StyleComponent::Numbers, StyleComponent::Numbers,
])) ]))
.files(std::env::args_os().skip(1)) .files(std::env::args_os().skip(1));
.run()
.expect("no errors"); printer.run().expect("no errors");
} }

View File

@ -5,8 +5,9 @@ use std::ffi::OsStr;
fn main() { fn main() {
let path_to_this_file = OsStr::new(file!()); let path_to_this_file = OsStr::new(file!());
PrettyPrinter::new() let mut printer = PrettyPrinter::new();
.file(path_to_this_file)
.run() printer.file(path_to_this_file);
.expect("no errors");
printer.run().expect("no errors");
} }

View File

@ -219,6 +219,7 @@ impl HighlightingAssets {
.get_extension_syntax(&file_name) .get_extension_syntax(&file_name)
.or(self.get_first_line_syntax(reader)), .or(self.get_first_line_syntax(reader)),
(_, InputFile::ThemePreviewFile) => self.syntax_set.find_syntax_by_name("Rust"), (_, InputFile::ThemePreviewFile) => self.syntax_set.find_syntax_by_name("Rust"),
(None, InputFile::FromReader(s, _)) => None,
}; };
syntax.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text()) syntax.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text())

View File

@ -73,8 +73,7 @@ impl App {
Ok(clap_app::build_app(interactive_output).get_matches_from(args)) Ok(clap_app::build_app(interactive_output).get_matches_from(args))
} }
pub fn config(&self) -> Result<Config> { pub fn config(&self, inputs: &[InputFile]) -> Result<Config> {
let files = self.files()?;
let style_components = self.style_components()?; let style_components = self.style_components()?;
let paging_mode = match self.matches.value_of("paging") { let paging_mode = match self.matches.value_of("paging") {
@ -84,7 +83,13 @@ impl App {
if self.matches.occurrences_of("plain") > 1 { if self.matches.occurrences_of("plain") > 1 {
// If we have -pp as an option when in auto mode, the pager should be disabled. // If we have -pp as an option when in auto mode, the pager should be disabled.
PagingMode::Never PagingMode::Never
} else if files.contains(&InputFile::StdIn(None)) { } else if inputs.iter().any(|f| {
if let InputFile::StdIn(None) = f {
true
} else {
false
}
}) {
// If we are reading from stdin, only enable paging if we write to an // If we are reading from stdin, only enable paging if we write to an
// interactive terminal and if we do not *read* from an interactive // interactive terminal and if we do not *read* from an interactive
// terminal. // terminal.
@ -170,7 +175,6 @@ impl App {
loop_through: !(self.interactive_output loop_through: !(self.interactive_output
|| self.matches.value_of("color") == Some("always") || self.matches.value_of("color") == Some("always")
|| self.matches.value_of("decorations") == Some("always")), || self.matches.value_of("decorations") == Some("always")),
files,
tab_width: self tab_width: self
.matches .matches
.value_of("tabs") .value_of("tabs")
@ -222,7 +226,7 @@ impl App {
}) })
} }
fn files(&self) -> Result<Vec<InputFile>> { pub fn inputs(&self) -> Result<Vec<InputFile>> {
// verify equal length of file-names and input FILEs // verify equal length of file-names and input FILEs
match self.matches.values_of("file-name") { match self.matches.values_of("file-name") {
Some(ref filenames) Some(ref filenames)

View File

@ -120,7 +120,6 @@ pub fn list_themes(cfg: &Config) -> Result<()> {
let mut config = cfg.clone(); let mut config = cfg.clone();
let mut style = HashSet::new(); let mut style = HashSet::new();
style.insert(StyleComponent::Plain); style.insert(StyleComponent::Plain);
config.files = vec![InputFile::ThemePreviewFile];
config.style_components = StyleComponents(style); config.style_components = StyleComponents(style);
let stdout = io::stdout(); let stdout = io::stdout();
@ -134,7 +133,9 @@ pub fn list_themes(cfg: &Config) -> Result<()> {
Style::new().bold().paint(theme.to_string()) Style::new().bold().paint(theme.to_string())
)?; )?;
config.theme = theme.to_string(); config.theme = theme.to_string();
let _controller = Controller::new(&config, &assets).run(); Controller::new(&config, &assets)
.run(vec![InputFile::ThemePreviewFile])
.ok();
writeln!(stdout)?; writeln!(stdout)?;
} }
} else { } else {
@ -146,10 +147,10 @@ pub fn list_themes(cfg: &Config) -> Result<()> {
Ok(()) Ok(())
} }
fn run_controller(config: &Config) -> Result<bool> { fn run_controller(inputs: Vec<InputFile>, config: &Config) -> Result<bool> {
let assets = assets_from_cache_or_binary()?; let assets = assets_from_cache_or_binary()?;
let controller = Controller::new(&config, &assets); let controller = Controller::new(&config, &assets);
controller.run() controller.run(inputs)
} }
/// Returns `Err(..)` upon fatal errors. Otherwise, returns `Ok(true)` on full success and /// Returns `Err(..)` upon fatal errors. Otherwise, returns `Ok(true)` on full success and
@ -166,16 +167,17 @@ fn run() -> Result<bool> {
run_cache_subcommand(cache_matches)?; run_cache_subcommand(cache_matches)?;
Ok(true) Ok(true)
} else { } else {
let mut config = app.config()?; let inputs = vec![InputFile::Ordinary(OrdinaryFile::from_path(OsStr::new(
config.files = vec![InputFile::Ordinary(OrdinaryFile::from_path(OsStr::new(
"cache", "cache",
)))]; )))];
let mut config = app.config(&inputs)?;
run_controller(&config) run_controller(inputs, &config)
} }
} }
_ => { _ => {
let config = app.config()?; let inputs = app.inputs()?;
let config = app.config(&inputs)?;
if app.matches.is_present("list-languages") { if app.matches.is_present("list-languages") {
list_languages(&config)?; list_languages(&config)?;
@ -196,7 +198,7 @@ fn run() -> Result<bool> {
writeln!(io::stdout(), "{}", cache_dir())?; writeln!(io::stdout(), "{}", cache_dir())?;
Ok(true) Ok(true)
} else { } else {
run_controller(&config) run_controller(inputs, &config)
} }
} }
} }

View File

@ -22,9 +22,6 @@ impl Default for PagingMode {
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct Config<'a> { pub struct Config<'a> {
/// List of files to print
pub files: Vec<InputFile>,
/// The explicitly configured language, if any /// The explicitly configured language, if any
pub language: Option<&'a str>, pub language: Option<&'a str>,

View File

@ -20,11 +20,15 @@ impl<'b> Controller<'b> {
Controller { config, assets } Controller { config, assets }
} }
pub fn run(&self) -> Result<bool> { pub fn run(&self, inputs: Vec<InputFile>) -> Result<bool> {
self.run_with_error_handler(default_error_handler) self.run_with_error_handler(inputs, default_error_handler)
} }
pub fn run_with_error_handler(&self, handle_error: impl Fn(&Error)) -> Result<bool> { pub fn run_with_error_handler(
&self,
inputs: Vec<InputFile>,
handle_error: impl Fn(&Error),
) -> Result<bool> {
let mut output_type; let mut output_type;
#[cfg(feature = "paging")] #[cfg(feature = "paging")]
@ -34,7 +38,7 @@ impl<'b> Controller<'b> {
// Do not launch the pager if NONE of the input files exist // Do not launch the pager if NONE of the input files exist
let mut paging_mode = self.config.paging_mode; let mut paging_mode = self.config.paging_mode;
if self.config.paging_mode != PagingMode::Never { if self.config.paging_mode != PagingMode::Never {
let call_pager = self.config.files.iter().any(|file| { let call_pager = inputs.iter().any(|file| {
if let InputFile::Ordinary(ofile) = file { if let InputFile::Ordinary(ofile) = file {
return Path::new(ofile.provided_path()).exists(); return Path::new(ofile.provided_path()).exists();
} else { } else {
@ -56,7 +60,7 @@ impl<'b> Controller<'b> {
let writer = output_type.handle()?; let writer = output_type.handle()?;
let mut no_errors: bool = true; let mut no_errors: bool = true;
for input_file in self.config.files.iter() { for input_file in inputs.into_iter() {
match input_file.get_reader(io::stdin().lock()) { match input_file.get_reader(io::stdin().lock()) {
Err(error) => { Err(error) => {
handle_error(&error); handle_error(&error);
@ -65,15 +69,15 @@ 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_file) self.print_file(reader, &mut printer, writer, &input_file)
} else { } else {
let mut printer = InteractivePrinter::new( let mut printer = InteractivePrinter::new(
&self.config, &self.config,
&self.assets, &self.assets,
input_file, &input_file,
&mut reader, &mut reader,
); );
self.print_file(reader, &mut printer, writer, input_file) self.print_file(reader, &mut printer, writer, &input_file)
}; };
if let Err(error) = result { if let Err(error) = result {

View File

@ -1,6 +1,6 @@
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::fs::File; use std::fs::File;
use std::io::{self, BufRead, BufReader}; use std::io::{self, BufRead, BufReader, Read};
use content_inspector::{self, ContentType}; use content_inspector::{self, ContentType};
@ -77,10 +77,10 @@ impl OrdinaryFile {
} }
} }
#[derive(Debug, Clone, PartialEq)]
pub enum InputFile { pub enum InputFile {
StdIn(Option<OsString>), StdIn(Option<OsString>),
Ordinary(OrdinaryFile), Ordinary(OrdinaryFile),
FromReader(Box<dyn Read>, Option<OsString>),
ThemePreviewFile, ThemePreviewFile,
} }
@ -101,6 +101,7 @@ impl InputFile {
Ok(InputFileReader::new(BufReader::new(file))) Ok(InputFileReader::new(BufReader::new(file)))
} }
InputFile::ThemePreviewFile => Ok(InputFileReader::new(THEME_PREVIEW_FILE)), InputFile::ThemePreviewFile => Ok(InputFileReader::new(THEME_PREVIEW_FILE)),
InputFile::FromReader(reader, _) => unimplemented!(), //Ok(InputFileReader::new(BufReader::new(reader))),
} }
} }
} }

View File

@ -13,6 +13,7 @@ use crate::{
use crate::config::PagingMode; use crate::config::PagingMode;
pub struct PrettyPrinter<'a> { pub struct PrettyPrinter<'a> {
inputs: Vec<InputFile>,
config: Config<'a>, config: Config<'a>,
assets: HighlightingAssets, assets: HighlightingAssets,
} }
@ -25,6 +26,7 @@ impl<'a> PrettyPrinter<'a> {
config.true_color = true; config.true_color = true;
PrettyPrinter { PrettyPrinter {
inputs: vec![],
config, config,
assets: HighlightingAssets::from_binary(), assets: HighlightingAssets::from_binary(),
} }
@ -32,8 +34,7 @@ impl<'a> PrettyPrinter<'a> {
/// Add a file which should be pretty-printed /// Add a file which should be pretty-printed
pub fn file(&mut self, path: &OsStr) -> &mut Self { pub fn file(&mut self, path: &OsStr) -> &mut Self {
self.config self.inputs
.files
.push(InputFile::Ordinary(OrdinaryFile::from_path(path))); .push(InputFile::Ordinary(OrdinaryFile::from_path(path)));
self self
} }
@ -45,8 +46,7 @@ impl<'a> PrettyPrinter<'a> {
P: AsRef<OsStr>, P: AsRef<OsStr>,
{ {
for path in paths { for path in paths {
self.config self.inputs
.files
.push(InputFile::Ordinary(OrdinaryFile::from_path(path.as_ref()))); .push(InputFile::Ordinary(OrdinaryFile::from_path(path.as_ref())));
} }
self self
@ -137,8 +137,8 @@ impl<'a> PrettyPrinter<'a> {
self self
} }
pub fn run(&'a self) -> Result<bool> { pub fn run(self) -> Result<bool> {
let controller = Controller::new(&self.config, &self.assets); let controller = Controller::new(&self.config, &self.assets);
controller.run() controller.run(self.inputs)
} }
} }

View File

@ -243,6 +243,10 @@ impl<'a> Printer for InteractivePrinter<'a> {
), ),
InputFile::StdIn(None) => "STDIN".to_owned(), InputFile::StdIn(None) => "STDIN".to_owned(),
InputFile::ThemePreviewFile => "".to_owned(), InputFile::ThemePreviewFile => "".to_owned(),
InputFile::FromReader(_, Some(name)) => {
format!("file '{}'", name.to_string_lossy())
}
InputFile::FromReader(_, None) => "READER".to_owned(),
}; };
writeln!( writeln!(
@ -286,6 +290,10 @@ impl<'a> Printer for InteractivePrinter<'a> {
} }
InputFile::StdIn(None) => ("File: ", Cow::from("STDIN".to_owned())), InputFile::StdIn(None) => ("File: ", Cow::from("STDIN".to_owned())),
InputFile::ThemePreviewFile => ("", Cow::from("")), InputFile::ThemePreviewFile => ("", Cow::from("")),
InputFile::FromReader(_, Some(name)) => {
("File: ", Cow::from(name.to_string_lossy().to_owned()))
}
InputFile::FromReader(_, None) => ("File: ", Cow::from("READER".to_owned())),
}; };
let mode = match self.content_type { let mode = match self.content_type {