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;
fn main() {
PrettyPrinter::new()
let mut printer = PrettyPrinter::new();
printer
.term_width(Term::stdout().size().1 as usize)
.style_components(StyleComponents::new(&[
StyleComponent::Header,
StyleComponent::Grid,
StyleComponent::Numbers,
]))
.files(std::env::args_os().skip(1))
.run()
.expect("no errors");
.files(std::env::args_os().skip(1));
printer.run().expect("no errors");
}

View File

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

View File

@ -219,6 +219,7 @@ impl HighlightingAssets {
.get_extension_syntax(&file_name)
.or(self.get_first_line_syntax(reader)),
(_, 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())

View File

@ -73,8 +73,7 @@ impl App {
Ok(clap_app::build_app(interactive_output).get_matches_from(args))
}
pub fn config(&self) -> Result<Config> {
let files = self.files()?;
pub fn config(&self, inputs: &[InputFile]) -> Result<Config> {
let style_components = self.style_components()?;
let paging_mode = match self.matches.value_of("paging") {
@ -84,7 +83,13 @@ impl App {
if self.matches.occurrences_of("plain") > 1 {
// If we have -pp as an option when in auto mode, the pager should be disabled.
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
// interactive terminal and if we do not *read* from an interactive
// terminal.
@ -170,7 +175,6 @@ impl App {
loop_through: !(self.interactive_output
|| self.matches.value_of("color") == Some("always")
|| self.matches.value_of("decorations") == Some("always")),
files,
tab_width: self
.matches
.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
match self.matches.values_of("file-name") {
Some(ref filenames)

View File

@ -120,7 +120,6 @@ pub fn list_themes(cfg: &Config) -> Result<()> {
let mut config = cfg.clone();
let mut style = HashSet::new();
style.insert(StyleComponent::Plain);
config.files = vec![InputFile::ThemePreviewFile];
config.style_components = StyleComponents(style);
let stdout = io::stdout();
@ -134,7 +133,9 @@ pub fn list_themes(cfg: &Config) -> Result<()> {
Style::new().bold().paint(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)?;
}
} else {
@ -146,10 +147,10 @@ pub fn list_themes(cfg: &Config) -> Result<()> {
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 controller = Controller::new(&config, &assets);
controller.run()
controller.run(inputs)
}
/// 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)?;
Ok(true)
} else {
let mut config = app.config()?;
config.files = vec![InputFile::Ordinary(OrdinaryFile::from_path(OsStr::new(
let inputs = vec![InputFile::Ordinary(OrdinaryFile::from_path(OsStr::new(
"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") {
list_languages(&config)?;
@ -196,7 +198,7 @@ fn run() -> Result<bool> {
writeln!(io::stdout(), "{}", cache_dir())?;
Ok(true)
} else {
run_controller(&config)
run_controller(inputs, &config)
}
}
}

View File

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

View File

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

View File

@ -1,6 +1,6 @@
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io::{self, BufRead, BufReader};
use std::io::{self, BufRead, BufReader, Read};
use content_inspector::{self, ContentType};
@ -77,10 +77,10 @@ impl OrdinaryFile {
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum InputFile {
StdIn(Option<OsString>),
Ordinary(OrdinaryFile),
FromReader(Box<dyn Read>, Option<OsString>),
ThemePreviewFile,
}
@ -101,6 +101,7 @@ impl InputFile {
Ok(InputFileReader::new(BufReader::new(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;
pub struct PrettyPrinter<'a> {
inputs: Vec<InputFile>,
config: Config<'a>,
assets: HighlightingAssets,
}
@ -25,6 +26,7 @@ impl<'a> PrettyPrinter<'a> {
config.true_color = true;
PrettyPrinter {
inputs: vec![],
config,
assets: HighlightingAssets::from_binary(),
}
@ -32,8 +34,7 @@ impl<'a> PrettyPrinter<'a> {
/// Add a file which should be pretty-printed
pub fn file(&mut self, path: &OsStr) -> &mut Self {
self.config
.files
self.inputs
.push(InputFile::Ordinary(OrdinaryFile::from_path(path)));
self
}
@ -45,8 +46,7 @@ impl<'a> PrettyPrinter<'a> {
P: AsRef<OsStr>,
{
for path in paths {
self.config
.files
self.inputs
.push(InputFile::Ordinary(OrdinaryFile::from_path(path.as_ref())));
}
self
@ -137,8 +137,8 @@ impl<'a> PrettyPrinter<'a> {
self
}
pub fn run(&'a self) -> Result<bool> {
pub fn run(self) -> Result<bool> {
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::ThemePreviewFile => "".to_owned(),
InputFile::FromReader(_, Some(name)) => {
format!("file '{}'", name.to_string_lossy())
}
InputFile::FromReader(_, None) => "READER".to_owned(),
};
writeln!(
@ -286,6 +290,10 @@ impl<'a> Printer for InteractivePrinter<'a> {
}
InputFile::StdIn(None) => ("File: ", Cow::from("STDIN".to_owned())),
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 {