mirror of
				https://github.com/sharkdp/bat.git
				synced 2025-11-04 09:01:56 +00:00 
			
		
		
		
	Add simple loop-through mode
Use a loop-through mode that simply copies input to output if a non-interactive terminal is detected. see #150
This commit is contained in:
		
							
								
								
									
										43
									
								
								src/app.rs
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								src/app.rs
									
									
									
									
									
								
							@@ -206,6 +206,18 @@ impl App {
 | 
			
		||||
                    .help("When to use colors.")
 | 
			
		||||
                    .long_help("Specify when to use colored output. The automatic mode \
 | 
			
		||||
                                only enables colors if an interactive terminal is detected."),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("decorations")
 | 
			
		||||
                    .long("decorations")
 | 
			
		||||
                    .overrides_with("decorations")
 | 
			
		||||
                    .takes_value(true)
 | 
			
		||||
                    .value_name("when")
 | 
			
		||||
                    .possible_values(&["auto", "never", "always"])
 | 
			
		||||
                    .default_value("auto")
 | 
			
		||||
                    .help("When to show the decorations specified by '--style'.")
 | 
			
		||||
                    .long_help("Specify when to use the decorations that have been specified \
 | 
			
		||||
                                via '--style'. The automatic mode only enables decorations if \
 | 
			
		||||
                                an interactive terminal is detected."),
 | 
			
		||||
            ).arg(
 | 
			
		||||
                Arg::with_name("paging")
 | 
			
		||||
                    .long("paging")
 | 
			
		||||
@@ -336,8 +348,9 @@ impl App {
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
            term_width: Term::stdout().size().1 as usize,
 | 
			
		||||
            loop_through: self.interactive_output
 | 
			
		||||
                && self.matches.value_of("color") != Some("always"),
 | 
			
		||||
            loop_through: !(self.interactive_output
 | 
			
		||||
                || self.matches.value_of("color") == Some("always")
 | 
			
		||||
                || self.matches.value_of("decorations") == Some("always")),
 | 
			
		||||
            files,
 | 
			
		||||
            theme: self
 | 
			
		||||
                .matches
 | 
			
		||||
@@ -366,16 +379,20 @@ impl App {
 | 
			
		||||
 | 
			
		||||
    fn output_components(&self) -> Result<OutputComponents> {
 | 
			
		||||
        let matches = &self.matches;
 | 
			
		||||
        Ok(OutputComponents(if matches.is_present("number") {
 | 
			
		||||
            [OutputComponent::Numbers].iter().cloned().collect()
 | 
			
		||||
        } else {
 | 
			
		||||
            values_t!(matches.values_of("style"), OutputComponent)?
 | 
			
		||||
                .into_iter()
 | 
			
		||||
                .map(|style| style.components(self.interactive_output))
 | 
			
		||||
                .fold(HashSet::new(), |mut acc, components| {
 | 
			
		||||
                    acc.extend(components.iter().cloned());
 | 
			
		||||
                    acc
 | 
			
		||||
                })
 | 
			
		||||
        }))
 | 
			
		||||
        Ok(OutputComponents(
 | 
			
		||||
            if matches.value_of("decorations") == Some("never") {
 | 
			
		||||
                HashSet::new()
 | 
			
		||||
            } else if matches.is_present("number") {
 | 
			
		||||
                [OutputComponent::Numbers].iter().cloned().collect()
 | 
			
		||||
            } else {
 | 
			
		||||
                values_t!(matches.values_of("style"), OutputComponent)?
 | 
			
		||||
                    .into_iter()
 | 
			
		||||
                    .map(|style| style.components(self.interactive_output))
 | 
			
		||||
                    .fold(HashSet::new(), |mut acc, components| {
 | 
			
		||||
                        acc.extend(components.iter().cloned());
 | 
			
		||||
                        acc
 | 
			
		||||
                    })
 | 
			
		||||
            },
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ use assets::HighlightingAssets;
 | 
			
		||||
use errors::*;
 | 
			
		||||
use line_range::LineRange;
 | 
			
		||||
use output::OutputType;
 | 
			
		||||
use printer::{InteractivePrinter, Printer};
 | 
			
		||||
use printer::{InteractivePrinter, Printer, SimplePrinter};
 | 
			
		||||
 | 
			
		||||
pub struct Controller<'a> {
 | 
			
		||||
    config: &'a Config<'a>,
 | 
			
		||||
@@ -23,8 +23,14 @@ impl<'b> Controller<'b> {
 | 
			
		||||
        let writer = output_type.handle()?;
 | 
			
		||||
        let mut no_errors: bool = true;
 | 
			
		||||
 | 
			
		||||
        for file in &self.config.files {
 | 
			
		||||
            let result = self.print_file(writer, *file);
 | 
			
		||||
        for filename in &self.config.files {
 | 
			
		||||
            let result = if self.config.loop_through {
 | 
			
		||||
                let mut printer = SimplePrinter::new();
 | 
			
		||||
                self.print_file(&mut printer, writer, *filename)
 | 
			
		||||
            } else {
 | 
			
		||||
                let mut printer = InteractivePrinter::new(&self.config, &self.assets, *filename);
 | 
			
		||||
                self.print_file(&mut printer, writer, *filename)
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if let Err(error) = result {
 | 
			
		||||
                handle_error(&error);
 | 
			
		||||
@@ -35,9 +41,12 @@ impl<'b> Controller<'b> {
 | 
			
		||||
        Ok(no_errors)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn print_file(&self, writer: &mut Write, filename: Option<&str>) -> Result<()> {
 | 
			
		||||
        let mut printer = InteractivePrinter::new(&self.config, &self.assets, filename);
 | 
			
		||||
 | 
			
		||||
    fn print_file<P: Printer>(
 | 
			
		||||
        &self,
 | 
			
		||||
        printer: &mut P,
 | 
			
		||||
        writer: &mut Write,
 | 
			
		||||
        filename: Option<&str>,
 | 
			
		||||
    ) -> Result<()> {
 | 
			
		||||
        let stdin = io::stdin();
 | 
			
		||||
        {
 | 
			
		||||
            let reader: Box<BufRead> = match filename {
 | 
			
		||||
@@ -46,7 +55,7 @@ impl<'b> Controller<'b> {
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            printer.print_header(writer, filename)?;
 | 
			
		||||
            self.print_file_ranges(&mut printer, writer, reader, &self.config.line_range)?;
 | 
			
		||||
            self.print_file_ranges(printer, writer, reader, &self.config.line_range)?;
 | 
			
		||||
            printer.print_footer(writer)?;
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
@@ -59,14 +68,12 @@ impl<'b> Controller<'b> {
 | 
			
		||||
        mut reader: Box<BufRead + 'a>,
 | 
			
		||||
        line_ranges: &Option<LineRange>,
 | 
			
		||||
    ) -> Result<()> {
 | 
			
		||||
        let mut buffer = Vec::new();
 | 
			
		||||
        let mut line_buffer = Vec::new();
 | 
			
		||||
 | 
			
		||||
        let mut line_number: usize = 1;
 | 
			
		||||
 | 
			
		||||
        while reader.read_until(b'\n', &mut buffer)? > 0 {
 | 
			
		||||
        while reader.read_until(b'\n', &mut line_buffer)? > 0 {
 | 
			
		||||
            {
 | 
			
		||||
                let line = String::from_utf8_lossy(&buffer);
 | 
			
		||||
 | 
			
		||||
                match line_ranges {
 | 
			
		||||
                    &Some(ref range) => {
 | 
			
		||||
                        if line_number < range.lower {
 | 
			
		||||
@@ -75,17 +82,17 @@ impl<'b> Controller<'b> {
 | 
			
		||||
                            // no more lines in range
 | 
			
		||||
                            break;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            printer.print_line(writer, line_number, &line)?;
 | 
			
		||||
                            printer.print_line(writer, line_number, &line_buffer)?;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    &None => {
 | 
			
		||||
                        printer.print_line(writer, line_number, &line)?;
 | 
			
		||||
                        printer.print_line(writer, line_number, &line_buffer)?;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                line_number += 1;
 | 
			
		||||
            }
 | 
			
		||||
            buffer.clear();
 | 
			
		||||
            line_buffer.clear();
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,40 @@ use terminal::{as_terminal_escaped, to_ansi_color};
 | 
			
		||||
pub trait Printer {
 | 
			
		||||
    fn print_header(&mut self, handle: &mut Write, filename: Option<&str>) -> Result<()>;
 | 
			
		||||
    fn print_footer(&mut self, handle: &mut Write) -> Result<()>;
 | 
			
		||||
    fn print_line(&mut self, handle: &mut Write, line_number: usize, line: &str) -> Result<()>;
 | 
			
		||||
    fn print_line(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        handle: &mut Write,
 | 
			
		||||
        line_number: usize,
 | 
			
		||||
        line_buffer: &[u8],
 | 
			
		||||
    ) -> Result<()>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct SimplePrinter;
 | 
			
		||||
 | 
			
		||||
impl SimplePrinter {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        SimplePrinter {}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Printer for SimplePrinter {
 | 
			
		||||
    fn print_header(&mut self, _handle: &mut Write, _filename: Option<&str>) -> Result<()> {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn print_footer(&mut self, _handle: &mut Write) -> Result<()> {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn print_line(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        handle: &mut Write,
 | 
			
		||||
        _line_number: usize,
 | 
			
		||||
        line_buffer: &[u8],
 | 
			
		||||
    ) -> Result<()> {
 | 
			
		||||
        handle.write(line_buffer)?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct InteractivePrinter<'a> {
 | 
			
		||||
@@ -153,7 +186,13 @@ impl<'a> Printer for InteractivePrinter<'a> {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn print_line(&mut self, handle: &mut Write, line_number: usize, line: &str) -> Result<()> {
 | 
			
		||||
    fn print_line(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        handle: &mut Write,
 | 
			
		||||
        line_number: usize,
 | 
			
		||||
        line_buffer: &[u8],
 | 
			
		||||
    ) -> Result<()> {
 | 
			
		||||
        let line = String::from_utf8_lossy(&line_buffer);
 | 
			
		||||
        let regions = self.highlighter.highlight(line.as_ref());
 | 
			
		||||
 | 
			
		||||
        let mut cursor: usize = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -41,8 +41,11 @@ impl BatTester {
 | 
			
		||||
    pub fn test_snapshot(&self, style: &str) {
 | 
			
		||||
        let output = Command::new(&self.exe)
 | 
			
		||||
            .current_dir(self.temp_dir.path())
 | 
			
		||||
            .args(&["sample.rs", &format!("--style={}", style)])
 | 
			
		||||
            .output()
 | 
			
		||||
            .args(&[
 | 
			
		||||
                "sample.rs",
 | 
			
		||||
                "--decorations=always",
 | 
			
		||||
                &format!("--style={}", style),
 | 
			
		||||
            ]).output()
 | 
			
		||||
            .expect("bat failed");
 | 
			
		||||
 | 
			
		||||
        // have to do the replace because the filename in the header changes based on the current working directory
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user