Refactoring, introduce Printer trait

This commit is contained in:
sharkdp 2018-08-23 19:43:10 +02:00
parent 6223ad6d52
commit ea955c734d
5 changed files with 77 additions and 51 deletions

View File

@ -32,8 +32,8 @@ pub struct Config<'a> {
/// The character width of the terminal /// The character width of the terminal
pub term_width: usize, pub term_width: usize,
/// Whether or not the terminal is interactive /// Whether or not to simply loop through all input (`cat` mode)
pub interactive_output: bool, pub loop_through: bool,
/// Whether or not the output should be colorized /// Whether or not the output should be colorized
pub colored_output: bool, pub colored_output: bool,
@ -336,6 +336,8 @@ impl App {
}, },
}, },
term_width: Term::stdout().size().1 as usize, term_width: Term::stdout().size().1 as usize,
loop_through: self.interactive_output
&& self.matches.value_of("color") != Some("always"),
files, files,
theme: self theme: self
.matches .matches

View File

@ -1,6 +1,6 @@
use ansi_term::Style; use ansi_term::Style;
use diff::LineChange; use diff::LineChange;
use printer::{Colors, Printer}; use printer::{Colors, InteractivePrinter};
#[derive(Clone)] #[derive(Clone)]
pub struct DecorationText { pub struct DecorationText {
@ -9,8 +9,12 @@ pub struct DecorationText {
} }
pub trait Decoration { pub trait Decoration {
fn generate(&self, line_number: usize, continuation: bool, printer: &Printer) fn generate(
-> DecorationText; &self,
line_number: usize,
continuation: bool,
printer: &InteractivePrinter,
) -> DecorationText;
fn width(&self) -> usize; fn width(&self) -> usize;
} }
@ -38,7 +42,7 @@ impl Decoration for LineNumberDecoration {
&self, &self,
line_number: usize, line_number: usize,
continuation: bool, continuation: bool,
_printer: &Printer, _printer: &InteractivePrinter,
) -> DecorationText { ) -> DecorationText {
if continuation { if continuation {
if line_number > self.cached_wrap_invalid_at { if line_number > self.cached_wrap_invalid_at {
@ -97,7 +101,7 @@ impl Decoration for LineChangesDecoration {
&self, &self,
line_number: usize, line_number: usize,
continuation: bool, continuation: bool,
printer: &Printer, printer: &InteractivePrinter,
) -> DecorationText { ) -> DecorationText {
if !continuation { if !continuation {
if let Some(ref changes) = printer.line_changes { if let Some(ref changes) = printer.line_changes {
@ -139,7 +143,7 @@ impl Decoration for GridBorderDecoration {
&self, &self,
_line_number: usize, _line_number: usize,
_continuation: bool, _continuation: bool,
_printer: &Printer, _printer: &InteractivePrinter,
) -> DecorationText { ) -> DecorationText {
self.cached.clone() self.cached.clone()
} }

View File

@ -13,7 +13,7 @@ use diff::get_git_diff;
use errors::*; use errors::*;
use line_range::LineRange; use line_range::LineRange;
use output::OutputType; use output::OutputType;
use printer::Printer; use printer::{InteractivePrinter, Printer};
pub fn list_languages(assets: &HighlightingAssets, term_width: usize) { pub fn list_languages(assets: &HighlightingAssets, term_width: usize) {
let mut languages = assets let mut languages = assets
@ -72,7 +72,7 @@ pub fn print_files(assets: &HighlightingAssets, config: &Config) -> Result<bool>
let mut output_type = OutputType::from_mode(config.paging_mode); let mut output_type = OutputType::from_mode(config.paging_mode);
let handle = output_type.handle()?; let handle = output_type.handle()?;
let mut printer = Printer::new(handle, &config, &theme); let mut printer = InteractivePrinter::new(handle, &config, &theme);
let mut no_errors: bool = true; let mut no_errors: bool = true;
for file in &config.files { for file in &config.files {
@ -80,7 +80,7 @@ pub fn print_files(assets: &HighlightingAssets, config: &Config) -> Result<bool>
printer.line_changes = file.and_then(|filename| get_git_diff(filename)); printer.line_changes = file.and_then(|filename| get_git_diff(filename));
let syntax = assets.get_syntax(config.language, *file); let syntax = assets.get_syntax(config.language, *file);
let result = print_file(theme, &syntax, &mut printer, *file); let result = print_file(config, theme, &syntax, &mut printer, *file);
if let Err(error) = result { if let Err(error) = result {
handle_error(&error); handle_error(&error);
@ -91,13 +91,14 @@ pub fn print_files(assets: &HighlightingAssets, config: &Config) -> Result<bool>
Ok(no_errors) Ok(no_errors)
} }
fn print_file( fn print_file<P: Printer>(
config: &Config,
theme: &Theme, theme: &Theme,
syntax: &SyntaxDefinition, syntax: &SyntaxDefinition,
printer: &mut Printer, printer: &mut P,
filename: Option<&str>, filename: Option<&str>,
) -> Result<()> { ) -> Result<()> {
let stdin = io::stdin(); // TODO: this variable is not always needed let stdin = io::stdin();
{ {
let reader: Box<BufRead> = match filename { let reader: Box<BufRead> = match filename {
None => Box::new(stdin.lock()), None => Box::new(stdin.lock()),
@ -107,20 +108,22 @@ fn print_file(
let highlighter = HighlightLines::new(syntax, theme); let highlighter = HighlightLines::new(syntax, theme);
printer.print_header(filename)?; printer.print_header(filename)?;
print_file_ranges(printer, reader, highlighter, &printer.config.line_range)?; print_file_ranges(printer, reader, highlighter, &config.line_range)?;
printer.print_footer()?; printer.print_footer()?;
} }
Ok(()) Ok(())
} }
fn print_file_ranges<'a>( fn print_file_ranges<'a, P: Printer>(
printer: &mut Printer, printer: &mut P,
mut reader: Box<BufRead + 'a>, mut reader: Box<BufRead + 'a>,
mut highlighter: HighlightLines, mut highlighter: HighlightLines,
line_ranges: &Option<LineRange>, line_ranges: &Option<LineRange>,
) -> Result<()> { ) -> Result<()> {
let mut buffer = Vec::new(); let mut 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 buffer)? > 0 {
{ {
let line = String::from_utf8_lossy(&buffer); let line = String::from_utf8_lossy(&buffer);
@ -128,20 +131,21 @@ fn print_file_ranges<'a>(
match line_ranges { match line_ranges {
&Some(ref range) => { &Some(ref range) => {
if printer.line_number + 1 < range.lower { if line_number < range.lower {
// skip line // skip line
printer.line_number += 1; } else if line_number > range.upper {
} else if printer.line_number >= range.upper {
// no more lines in range // no more lines in range
break; break;
} else { } else {
printer.print_line(&regions)?; printer.print_line(line_number, &regions)?;
} }
} }
&None => { &None => {
printer.print_line(&regions)?; printer.print_line(line_number, &regions)?;
} }
} }
line_number += 1;
} }
buffer.clear(); buffer.clear();
} }

View File

@ -104,7 +104,12 @@ fn run() -> Result<bool> {
Ok(true) Ok(true)
} else { } else {
print_files(&assets, &config) if config.loop_through {
// TODO
print_files(&assets, &config)
} else {
print_files(&assets, &config)
}
} }
} }
} }

View File

@ -16,18 +16,27 @@ use errors::*;
use style::OutputWrap; use style::OutputWrap;
use terminal::{as_terminal_escaped, to_ansi_color}; use terminal::{as_terminal_escaped, to_ansi_color};
pub struct Printer<'a> { pub trait Printer {
fn print_header(&mut self, filename: Option<&str>) -> Result<()>;
fn print_footer(&mut self) -> Result<()>;
fn print_line(
&mut self,
line_number: usize,
regions: &[(highlighting::Style, &str)],
) -> Result<()>;
}
pub struct InteractivePrinter<'a> {
handle: &'a mut Write, handle: &'a mut Write,
colors: Colors, colors: Colors,
pub config: &'a Config<'a>, pub config: &'a Config<'a>,
decorations: Vec<Box<Decoration>>, decorations: Vec<Box<Decoration>>,
panel_width: usize, panel_width: usize,
pub ansi_prefix_sgr: String, pub ansi_prefix_sgr: String,
pub line_number: usize,
pub line_changes: Option<LineChanges>, pub line_changes: Option<LineChanges>,
} }
impl<'a> Printer<'a> { impl<'a> InteractivePrinter<'a> {
pub fn new(handle: &'a mut Write, config: &'a Config, theme: &Theme) -> Self { pub fn new(handle: &'a mut Write, config: &'a Config, theme: &Theme) -> Self {
let colors = if config.colored_output { let colors = if config.colored_output {
Colors::colored(theme, config.true_color) Colors::colored(theme, config.true_color)
@ -66,21 +75,36 @@ impl<'a> Printer<'a> {
} }
// Create printer. // Create printer.
Printer { InteractivePrinter {
panel_width, panel_width,
handle, handle,
colors, colors,
config, config,
decorations, decorations,
ansi_prefix_sgr: String::new(), ansi_prefix_sgr: String::new(),
line_number: 0,
line_changes: None, line_changes: None,
} }
} }
pub fn print_header(&mut self, filename: Option<&str>) -> Result<()> { fn print_horizontal_line(&mut self, grid_char: char) -> Result<()> {
self.line_number = 0; if self.panel_width == 0 {
writeln!(
self.handle,
"{}",
self.colors.grid.paint("".repeat(self.config.term_width))
)?;
} else {
let hline = "".repeat(self.config.term_width - (self.panel_width + 1));
let hline = format!("{}{}{}", "".repeat(self.panel_width), grid_char, hline);
writeln!(self.handle, "{}", self.colors.grid.paint(hline))?;
}
Ok(())
}
}
impl<'a> Printer for InteractivePrinter<'a> {
fn print_header(&mut self, filename: Option<&str>) -> Result<()> {
if !self.config.output_components.header() { if !self.config.output_components.header() {
return Ok(()); return Ok(());
} }
@ -114,7 +138,7 @@ impl<'a> Printer<'a> {
Ok(()) Ok(())
} }
pub fn print_footer(&mut self) -> Result<()> { fn print_footer(&mut self) -> Result<()> {
if self.config.output_components.grid() { if self.config.output_components.grid() {
self.print_horizontal_line('┴') self.print_horizontal_line('┴')
} else { } else {
@ -122,8 +146,11 @@ impl<'a> Printer<'a> {
} }
} }
pub fn print_line(&mut self, regions: &[(highlighting::Style, &str)]) -> Result<()> { fn print_line(
self.line_number += 1; &mut self,
line_number: usize,
regions: &[(highlighting::Style, &str)],
) -> Result<()> {
let mut cursor: usize = 0; let mut cursor: usize = 0;
let mut cursor_max: usize = self.config.term_width; let mut cursor_max: usize = self.config.term_width;
let mut panel_wrap: Option<String> = None; let mut panel_wrap: Option<String> = None;
@ -133,7 +160,7 @@ impl<'a> Printer<'a> {
let decorations = self let decorations = self
.decorations .decorations
.iter() .iter()
.map(|ref d| d.generate(self.line_number, false, self)) .map(|ref d| d.generate(line_number, false, self))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for deco in decorations { for deco in decorations {
@ -218,7 +245,7 @@ impl<'a> Printer<'a> {
self.decorations self.decorations
.iter() .iter()
.map(|ref d| d .map(|ref d| d
.generate(self.line_number, true, self) .generate(line_number, true, self)
.text).collect::<Vec<String>>() .text).collect::<Vec<String>>()
.join(" ") .join(" ")
)) ))
@ -260,22 +287,6 @@ impl<'a> Printer<'a> {
Ok(()) Ok(())
} }
fn print_horizontal_line(&mut self, grid_char: char) -> Result<()> {
if self.panel_width == 0 {
writeln!(
self.handle,
"{}",
self.colors.grid.paint("".repeat(self.config.term_width))
)?;
} else {
let hline = "".repeat(self.config.term_width - (self.panel_width + 1));
let hline = format!("{}{}{}", "".repeat(self.panel_width), grid_char, hline);
writeln!(self.handle, "{}", self.colors.grid.paint(hline))?;
}
Ok(())
}
} }
const DEFAULT_GUTTER_COLOR: u8 = 238; const DEFAULT_GUTTER_COLOR: u8 = 238;