1use std::io::{self, Write};
3use crate::assets::HighlightingAssets;
4use crate::config::Config;
5#[cfg(feature = "paging")]
6use crate::config::PagingMode;
8use crate::inputfile::{InputFile, InputFileReader};
9use crate::line_range::{LineRanges, RangeCheckResult};
10use crate::output::OutputType;
11use crate::printer::{InteractivePrinter, Printer, SimplePrinter};
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 }
23 pub fn run(&self) -> Result<bool> {
24 self.run_with_error_handler(default_error_handler)
27 pub fn run_with_error_handler(&self, handle_error: impl Fn(&Error)) -> Result<bool> {
30 #[cfg(feature = "paging")]
34 // Do not launch the pager if NONE of the input files exist
35 let mut paging_mode = self.config.paging_mode;
36 if self.config.paging_mode != PagingMode::Never {
37 let call_pager = self.config.files.iter().any(|file| {
38 if let InputFile::Ordinary(ofile) = file {
39 return Path::new(ofile.filename()).exists();
45 paging_mode = PagingMode::Never;
48 output_type = OutputType::from_mode(paging_mode, self.config.pager)?;
51 #[cfg(not(feature = "paging"))]
53 output_type = OutputType::stdout();
56 let writer = output_type.handle()?;
57 let mut no_errors: bool = true;
59 let stdin = io::stdin();
61 for input_file in self.config.files.iter() {
62 match input_file.get_reader(&stdin) {
68 let result = if self.config.loop_through {
69 let mut printer = SimplePrinter::new();
70 self.print_file(reader, &mut printer, writer, *input_file)
72 let mut printer = InteractivePrinter::new(
78 self.print_file(reader, &mut printer, writer, *input_file)
81 if let Err(error) = result {
92 fn print_file<'a, P: Printer>(
94 reader: InputFileReader,
96 writer: &mut dyn Write,
97 input_file: InputFile<'a>,
99 if !reader.first_line.is_empty() || self.config.style_components.header() {
100 printer.print_header(writer, input_file)?;
103 if !reader.first_line.is_empty() {
104 self.print_file_ranges(printer, writer, reader, &self.config.line_ranges)?;
106 printer.print_footer(writer)?;
111 fn print_file_ranges<P: Printer>(
114 writer: &mut dyn Write,
115 mut reader: InputFileReader,
116 line_ranges: &LineRanges,
118 let mut line_buffer = Vec::new();
119 let mut line_number: usize = 1;
121 let mut first_range: bool = true;
122 let mut mid_range: bool = false;
124 while reader.read_line(&mut line_buffer)? {
125 match line_ranges.check(line_number) {
126 RangeCheckResult::BeforeOrBetweenRanges => {
127 // Call the printer in case we need to call the syntax highlighter
128 // for this line. However, set `out_of_range` to `true`.
129 printer.print_line(true, writer, line_number, &line_buffer)?;
133 RangeCheckResult::InRange => {
134 if self.config.style_components.snip() {
138 } else if !mid_range {
140 printer.print_snip(writer)?;
144 printer.print_line(false, writer, line_number, &line_buffer)?;
146 RangeCheckResult::AfterLastRange => {
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list