on 3446fdf help sign in
bat/src/controller.rs
112 lines 3.7 kB history raw
1use std::fs::File;
2use std::io::{self, BufRead, BufReader, Write};
4use app::{Config, InputFile};
5use assets::HighlightingAssets;
6use errors::*;
7use line_range::LineRange;
8use output::OutputType;
9use printer::{InteractivePrinter, Printer, SimplePrinter};
11const THEME_PREVIEW_FILE: &[u8] = include_bytes!("../assets/theme_preview.rs");
13pub struct Controller<'a> {
14 config: &'a Config<'a>,
15 assets: &'a HighlightingAssets,
18impl<'b> Controller<'b> {
19 pub fn new<'a>(config: &'a Config, assets: &'a HighlightingAssets) -> Controller<'a> {
20 Controller { config, assets }
21 }
23 pub fn run(&self) -> Result<bool> {
24 let mut output_type = OutputType::from_mode(self.config.paging_mode);
25 let writer = output_type.handle()?;
26 let mut no_errors: bool = true;
28 for filename in &self.config.files {
29 let result = if self.config.loop_through {
30 let mut printer = SimplePrinter::new();
31 self.print_file(&mut printer, writer, *filename)
32 } else {
33 let mut printer = InteractivePrinter::new(&self.config, &self.assets, *filename);
34 self.print_file(&mut printer, writer, *filename)
35 };
37 if let Err(error) = result {
38 handle_error(&error);
39 no_errors = false;
40 }
41 }
43 Ok(no_errors)
44 }
46 fn print_file<'a, P: Printer>(
47 &self,
48 printer: &mut P,
49 writer: &mut Write,
50 filename: InputFile<'a>,
51 ) -> Result<()> {
52 let stdin = io::stdin();
53 {
54 let reader: Box<BufRead> = match filename {
55 InputFile::StdIn => Box::new(stdin.lock()),
56 InputFile::Ordinary(filename) => {
57 let file = File::open(filename)?;
59 if file.metadata()?.is_dir() {
60 return Err(format!("'{}' is a directory.", filename).into());
61 }
63 Box::new(BufReader::new(file))
64 }
65 InputFile::ThemePreviewFile => Box::new(THEME_PREVIEW_FILE),
66 };
68 printer.print_header(writer, filename)?;
69 self.print_file_ranges(printer, writer, reader, &self.config.line_range)?;
70 printer.print_footer(writer)?;
71 }
72 Ok(())
73 }
75 fn print_file_ranges<'a, P: Printer>(
76 &self,
77 printer: &mut P,
78 writer: &mut Write,
79 mut reader: Box<BufRead + 'a>,
80 line_ranges: &Option<LineRange>,
81 ) -> Result<()> {
82 let mut line_buffer = Vec::new();
84 let mut line_number: usize = 1;
86 while reader.read_until(b'\n', &mut line_buffer)? > 0 {
87 {
88 match line_ranges {
89 &Some(ref range) => {
90 if line_number < range.lower {
91 // Call the printer in case we need to call the syntax highlighter
92 // for this line. However, set `out_of_range` to `true`.
93 printer.print_line(true, writer, line_number, &line_buffer)?;
94 } else if line_number > range.upper {
95 // no more lines in range, exit early
96 break;
97 } else {
98 printer.print_line(false, writer, line_number, &line_buffer)?;
99 }
100 }
101 &None => {
102 printer.print_line(false, writer, line_number, &line_buffer)?;
103 }
104 }
106 line_number += 1;
107 }
108 line_buffer.clear();
109 }
110 Ok(())
111 }