bat/src/controller.rs

144 lines
4.7 KiB
Rust
Raw Normal View History

use std::io::{self, Write};
use std::path::Path;
2018-08-23 22:37:27 +02:00
use crate::assets::HighlightingAssets;
2020-03-21 19:40:43 +01:00
use crate::config::{Config, PagingMode};
use crate::errors::*;
use crate::inputfile::{InputFile, InputFileReader};
use crate::line_range::{LineRanges, RangeCheckResult};
use crate::output::OutputType;
use crate::printer::{InteractivePrinter, Printer, SimplePrinter};
2018-08-23 22:37:27 +02:00
pub struct Controller<'a> {
config: &'a Config<'a>,
assets: &'a HighlightingAssets,
}
impl<'b> Controller<'b> {
pub fn new<'a>(config: &'a Config, assets: &'a HighlightingAssets) -> Controller<'a> {
Controller { config, assets }
}
pub fn run(&self) -> Result<bool> {
2020-03-21 19:51:59 +01:00
self.run_with_error_handler(default_error_handler)
}
pub fn run_with_error_handler(&self, handle_error: impl Fn(&Error)) -> Result<bool> {
// 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| {
if let InputFile::Ordinary(path) = file {
return Path::new(path).exists();
} else {
return true;
}
});
if !call_pager {
paging_mode = PagingMode::Never;
}
}
let mut output_type = OutputType::from_mode(paging_mode, self.config.pager)?;
2018-08-23 22:37:27 +02:00
let writer = output_type.handle()?;
let mut no_errors: bool = true;
let stdin = io::stdin();
2018-10-07 11:54:01 +02:00
for input_file in &self.config.files {
match input_file.get_reader(&stdin) {
Err(error) => {
handle_error(&error);
no_errors = false;
}
Ok(mut reader) => {
let result = if self.config.loop_through {
let mut printer = SimplePrinter::new();
self.print_file(reader, &mut printer, writer, *input_file)
} else {
let mut printer = InteractivePrinter::new(
&self.config,
&self.assets,
*input_file,
&mut reader,
);
self.print_file(reader, &mut printer, writer, *input_file)
};
if let Err(error) = result {
handle_error(&error);
no_errors = false;
}
}
2018-08-23 22:37:27 +02:00
}
}
Ok(no_errors)
}
2018-08-28 20:12:45 +02:00
fn print_file<'a, P: Printer>(
&self,
reader: InputFileReader,
printer: &mut P,
writer: &mut dyn Write,
2018-10-07 11:54:01 +02:00
input_file: InputFile<'a>,
) -> Result<()> {
2020-02-26 20:53:58 +01:00
if !reader.first_line.is_empty() || self.config.output_components.header() {
printer.print_header(writer, input_file)?;
}
if !reader.first_line.is_empty() {
self.print_file_ranges(printer, writer, reader, &self.config.line_ranges)?;
}
2018-10-07 11:54:01 +02:00
printer.print_footer(writer)?;
2018-08-23 22:37:27 +02:00
Ok(())
}
2019-03-08 11:46:49 +01:00
fn print_file_ranges<P: Printer>(
2018-08-23 22:37:27 +02:00
&self,
printer: &mut P,
writer: &mut dyn Write,
mut reader: InputFileReader,
2018-10-20 00:10:10 +02:00
line_ranges: &LineRanges,
2018-08-23 22:37:27 +02:00
) -> Result<()> {
let mut line_buffer = Vec::new();
2018-08-23 22:37:27 +02:00
let mut line_number: usize = 1;
let mut first_range: bool = true;
let mut mid_range: bool = false;
while reader.read_line(&mut line_buffer)? {
2018-10-20 00:10:10 +02:00
match line_ranges.check(line_number) {
2020-03-21 16:51:38 +01:00
RangeCheckResult::BeforeOrBetweenRanges => {
2018-10-20 00:10:10 +02:00
// Call the printer in case we need to call the syntax highlighter
// for this line. However, set `out_of_range` to `true`.
printer.print_line(true, writer, line_number, &line_buffer)?;
mid_range = false;
2018-08-23 22:37:27 +02:00
}
2018-10-20 00:10:10 +02:00
RangeCheckResult::InRange => {
if self.config.output_components.snip() {
if first_range {
first_range = false;
mid_range = true;
} else if !mid_range {
mid_range = true;
printer.print_snip(writer)?;
}
}
2018-10-07 10:09:10 +02:00
printer.print_line(false, writer, line_number, &line_buffer)?;
}
2018-10-20 00:10:10 +02:00
RangeCheckResult::AfterLastRange => {
break;
}
2018-08-23 22:37:27 +02:00
}
2018-10-07 10:09:10 +02:00
line_number += 1;
line_buffer.clear();
2018-08-23 22:37:27 +02:00
}
Ok(())
}
}