mirror of
https://github.com/sharkdp/bat.git
synced 2025-03-14 06:38:24 +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:
parent
246cf79dbd
commit
226d9a573a
43
src/app.rs
43
src/app.rs
@ -206,6 +206,18 @@ impl App {
|
|||||||
.help("When to use colors.")
|
.help("When to use colors.")
|
||||||
.long_help("Specify when to use colored output. The automatic mode \
|
.long_help("Specify when to use colored output. The automatic mode \
|
||||||
only enables colors if an interactive terminal is detected."),
|
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(
|
||||||
Arg::with_name("paging")
|
Arg::with_name("paging")
|
||||||
.long("paging")
|
.long("paging")
|
||||||
@ -336,8 +348,9 @@ impl App {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
term_width: Term::stdout().size().1 as usize,
|
term_width: Term::stdout().size().1 as usize,
|
||||||
loop_through: self.interactive_output
|
loop_through: !(self.interactive_output
|
||||||
&& self.matches.value_of("color") != Some("always"),
|
|| self.matches.value_of("color") == Some("always")
|
||||||
|
|| self.matches.value_of("decorations") == Some("always")),
|
||||||
files,
|
files,
|
||||||
theme: self
|
theme: self
|
||||||
.matches
|
.matches
|
||||||
@ -366,16 +379,20 @@ impl App {
|
|||||||
|
|
||||||
fn output_components(&self) -> Result<OutputComponents> {
|
fn output_components(&self) -> Result<OutputComponents> {
|
||||||
let matches = &self.matches;
|
let matches = &self.matches;
|
||||||
Ok(OutputComponents(if matches.is_present("number") {
|
Ok(OutputComponents(
|
||||||
[OutputComponent::Numbers].iter().cloned().collect()
|
if matches.value_of("decorations") == Some("never") {
|
||||||
} else {
|
HashSet::new()
|
||||||
values_t!(matches.values_of("style"), OutputComponent)?
|
} else if matches.is_present("number") {
|
||||||
.into_iter()
|
[OutputComponent::Numbers].iter().cloned().collect()
|
||||||
.map(|style| style.components(self.interactive_output))
|
} else {
|
||||||
.fold(HashSet::new(), |mut acc, components| {
|
values_t!(matches.values_of("style"), OutputComponent)?
|
||||||
acc.extend(components.iter().cloned());
|
.into_iter()
|
||||||
acc
|
.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 errors::*;
|
||||||
use line_range::LineRange;
|
use line_range::LineRange;
|
||||||
use output::OutputType;
|
use output::OutputType;
|
||||||
use printer::{InteractivePrinter, Printer};
|
use printer::{InteractivePrinter, Printer, SimplePrinter};
|
||||||
|
|
||||||
pub struct Controller<'a> {
|
pub struct Controller<'a> {
|
||||||
config: &'a Config<'a>,
|
config: &'a Config<'a>,
|
||||||
@ -23,8 +23,14 @@ impl<'b> Controller<'b> {
|
|||||||
let writer = output_type.handle()?;
|
let writer = output_type.handle()?;
|
||||||
let mut no_errors: bool = true;
|
let mut no_errors: bool = true;
|
||||||
|
|
||||||
for file in &self.config.files {
|
for filename in &self.config.files {
|
||||||
let result = self.print_file(writer, *file);
|
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 {
|
if let Err(error) = result {
|
||||||
handle_error(&error);
|
handle_error(&error);
|
||||||
@ -35,9 +41,12 @@ impl<'b> Controller<'b> {
|
|||||||
Ok(no_errors)
|
Ok(no_errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_file(&self, writer: &mut Write, filename: Option<&str>) -> Result<()> {
|
fn print_file<P: Printer>(
|
||||||
let mut printer = InteractivePrinter::new(&self.config, &self.assets, filename);
|
&self,
|
||||||
|
printer: &mut P,
|
||||||
|
writer: &mut Write,
|
||||||
|
filename: Option<&str>,
|
||||||
|
) -> Result<()> {
|
||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
{
|
{
|
||||||
let reader: Box<BufRead> = match filename {
|
let reader: Box<BufRead> = match filename {
|
||||||
@ -46,7 +55,7 @@ impl<'b> Controller<'b> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
printer.print_header(writer, filename)?;
|
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)?;
|
printer.print_footer(writer)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -59,14 +68,12 @@ impl<'b> Controller<'b> {
|
|||||||
mut reader: Box<BufRead + 'a>,
|
mut reader: Box<BufRead + 'a>,
|
||||||
line_ranges: &Option<LineRange>,
|
line_ranges: &Option<LineRange>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut buffer = Vec::new();
|
let mut line_buffer = Vec::new();
|
||||||
|
|
||||||
let mut line_number: usize = 1;
|
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 {
|
match line_ranges {
|
||||||
&Some(ref range) => {
|
&Some(ref range) => {
|
||||||
if line_number < range.lower {
|
if line_number < range.lower {
|
||||||
@ -75,17 +82,17 @@ impl<'b> Controller<'b> {
|
|||||||
// no more lines in range
|
// no more lines in range
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
printer.print_line(writer, line_number, &line)?;
|
printer.print_line(writer, line_number, &line_buffer)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&None => {
|
&None => {
|
||||||
printer.print_line(writer, line_number, &line)?;
|
printer.print_line(writer, line_number, &line_buffer)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
line_number += 1;
|
line_number += 1;
|
||||||
}
|
}
|
||||||
buffer.clear();
|
line_buffer.clear();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,40 @@ use terminal::{as_terminal_escaped, to_ansi_color};
|
|||||||
pub trait Printer {
|
pub trait Printer {
|
||||||
fn print_header(&mut self, handle: &mut Write, filename: Option<&str>) -> Result<()>;
|
fn print_header(&mut self, handle: &mut Write, filename: Option<&str>) -> Result<()>;
|
||||||
fn print_footer(&mut self, handle: &mut Write) -> 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> {
|
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 regions = self.highlighter.highlight(line.as_ref());
|
||||||
|
|
||||||
let mut cursor: usize = 0;
|
let mut cursor: usize = 0;
|
||||||
|
@ -41,8 +41,11 @@ impl BatTester {
|
|||||||
pub fn test_snapshot(&self, style: &str) {
|
pub fn test_snapshot(&self, style: &str) {
|
||||||
let output = Command::new(&self.exe)
|
let output = Command::new(&self.exe)
|
||||||
.current_dir(self.temp_dir.path())
|
.current_dir(self.temp_dir.path())
|
||||||
.args(&["sample.rs", &format!("--style={}", style)])
|
.args(&[
|
||||||
.output()
|
"sample.rs",
|
||||||
|
"--decorations=always",
|
||||||
|
&format!("--style={}", style),
|
||||||
|
]).output()
|
||||||
.expect("bat failed");
|
.expect("bat failed");
|
||||||
|
|
||||||
// have to do the replace because the filename in the header changes based on the current working directory
|
// have to do the replace because the filename in the header changes based on the current working directory
|
||||||
|
Loading…
x
Reference in New Issue
Block a user