on ad42b27 help sign in
bat/src/controller.rs
139 lines 4.6 kB history raw
1use std::io::{self, Write};
2use std::path::Path;
4use crate::assets::HighlightingAssets;
5use crate::errors::*;
6use crate::inputfile::{InputFile, InputFileReader};
7use crate::line_range::{LineRanges, RangeCheckResult};
8use crate::output::OutputType;
9use crate::printer::{InteractivePrinter, Printer, SimplePrinter};
10use crate::{Config, PagingMode};
12pub struct Controller<'a> {
13 config: &'a Config<'a>,
14 assets: &'a HighlightingAssets,
17impl<'b> Controller<'b> {
18 pub fn new<'a>(config: &'a Config, assets: &'a HighlightingAssets) -> Controller<'a> {
19 Controller { config, assets }
20 }
22 pub fn run(&self) -> Result<bool> {
23 // Do not launch the pager if NONE of the input files exist
24 let mut paging_mode = self.config.paging_mode;
25 if self.config.paging_mode != PagingMode::Never {
26 let call_pager = self.config.files.iter().any(|file| {
27 if let InputFile::Ordinary(path) = file {
28 return Path::new(path).exists();
29 } else {
30 return true;
31 }
32 });
33 if !call_pager {
34 paging_mode = PagingMode::Never;
35 }
36 }
38 let mut output_type = OutputType::from_mode(paging_mode, self.config.pager)?;
39 let writer = output_type.handle()?;
40 let mut no_errors: bool = true;
42 let stdin = io::stdin();
44 for input_file in &self.config.files {
45 match input_file.get_reader(&stdin) {
46 Err(error) => {
47 handle_error(&error);
48 no_errors = false;
49 }
50 Ok(mut reader) => {
51 let result = if self.config.loop_through {
52 let mut printer = SimplePrinter::new();
53 self.print_file(reader, &mut printer, writer, *input_file)
54 } else {
55 let mut printer = InteractivePrinter::new(
56 &self.config,
57 &self.assets,
58 *input_file,
59 &mut reader,
60 );
61 self.print_file(reader, &mut printer, writer, *input_file)
62 };
64 if let Err(error) = result {
65 handle_error(&error);
66 no_errors = false;
67 }
68 }
69 }
70 }
72 Ok(no_errors)
73 }
75 fn print_file<'a, P: Printer>(
76 &self,
77 reader: InputFileReader,
78 printer: &mut P,
79 writer: &mut dyn Write,
80 input_file: InputFile<'a>,
81 ) -> Result<()> {
82 if !reader.first_line.is_empty() || self.config.output_components.header() {
83 printer.print_header(writer, input_file)?;
84 }
86 if !reader.first_line.is_empty() {
87 self.print_file_ranges(printer, writer, reader, &self.config.line_ranges)?;
88 }
89 printer.print_footer(writer)?;
91 Ok(())
92 }
94 fn print_file_ranges<P: Printer>(
95 &self,
96 printer: &mut P,
97 writer: &mut dyn Write,
98 mut reader: InputFileReader,
99 line_ranges: &LineRanges,
100 ) -> Result<()> {
101 let mut line_buffer = Vec::new();
102 let mut line_number: usize = 1;
104 let mut first_range: bool = true;
105 let mut mid_range: bool = false;
107 while reader.read_line(&mut line_buffer)? {
108 match line_ranges.check(line_number) {
109 RangeCheckResult::OutsideRange => {
110 // Call the printer in case we need to call the syntax highlighter
111 // for this line. However, set `out_of_range` to `true`.
112 printer.print_line(true, writer, line_number, &line_buffer)?;
113 mid_range = false;
114 }
116 RangeCheckResult::InRange => {
117 if self.config.output_components.snip() {
118 if first_range {
119 first_range = false;
120 mid_range = true;
121 } else if !mid_range {
122 mid_range = true;
123 printer.print_snip(writer)?;
124 }
125 }
127 printer.print_line(false, writer, line_number, &line_buffer)?;
128 }
129 RangeCheckResult::AfterLastRange => {
130 break;
131 }
132 }
134 line_number += 1;
135 line_buffer.clear();
136 }
137 Ok(())
138 }