@@ -17,6 +17,7 @@ extern crate directories;
1717extern crate git2;
1818extern crate syntect;
1919
20+mod printer;
2021mod terminal;
2122
2223use std::collections::HashMap;
@@ -30,7 +31,6 @@ use ansi_term::Colour::{Fixed, Green, Red, White, Yellow};
3031use ansi_term::Style;
3132use atty::Stream;
3233use clap::{App, AppSettings, Arg, SubCommand};
33−use console::Term;
3434use directories::ProjectDirs;
3535use git2::{DiffOptions, IntoCString, Repository};
3636
@@ -39,7 +39,7 @@ use syntect::easy::HighlightLines;
3939use syntect::highlighting::{Theme, ThemeSet};
4040use syntect::parsing::SyntaxSet;
4141
42−use terminal::as_terminal_escaped;
42+use printer::Printer;
4343
4444lazy_static! {
4545 static ref PROJECT_DIRS: ProjectDirs = ProjectDirs::from("", "", crate_name!());
@@ -55,18 +55,18 @@ mod errors {
5555
5656use errors::*;
5757
58−enum OptionsStyle {
58+pub enum OptionsStyle {
5959 Plain,
6060 LineNumbers,
6161 Full,
6262}
6363
64−struct Options<'a> {
65− true_color: bool,
66− style: OptionsStyle,
67− language: Option<&'a str>,
68− colored_output: bool,
69− paging: bool,
64+pub struct Options<'a> {
65+ pub true_color: bool,
66+ pub style: OptionsStyle,
67+ pub language: Option<&'a str>,
68+ pub colored_output: bool,
69+ pub paging: bool,
7070}
7171
7272enum OutputType<'a> {
@@ -107,27 +107,26 @@ impl<'a> Drop for OutputType<'a> {
107107}
108108
109109#[derive(Copy, Clone, Debug)]
110−enum LineChange {
110+pub enum LineChange {
111111 Added,
112112 RemovedAbove,
113113 RemovedBelow,
114114 Modified,
115115}
116116
117−type LineChanges = HashMap<u32, LineChange>;
117+pub type LineChanges = HashMap<u32, LineChange>;
118118
119−const PANEL_WIDTH: usize = 7;
120119const GRID_COLOR: u8 = 238;
121120const LINE_NUMBER_COLOR: u8 = 244;
122121
123122#[derive(Default)]
124−struct Colors {
125− grid: Style,
126− filename: Style,
127− git_added: Style,
128− git_removed: Style,
129− git_modified: Style,
130− line_number: Style,
123+pub struct Colors {
124+ pub grid: Style,
125+ pub filename: Style,
126+ pub git_added: Style,
127+ pub git_removed: Style,
128+ pub git_modified: Style,
129+ pub line_number: Style,
131130}
132131
133132impl Colors {
@@ -147,27 +146,12 @@ impl Colors {
147146 }
148147}
149148
150−fn print_horizontal_line(
151− handle: &mut Write,
152− grid_color: &Style,
153− grid_char: char,
154− term_width: usize,
155−) -> Result<()> {
156− let hline = "─".repeat(term_width - (PANEL_WIDTH + 1));
157− let hline = format!("{}{}{}", "─".repeat(PANEL_WIDTH), grid_char, hline);
158−
159− writeln!(handle, "{}", grid_color.paint(hline))?;
160−
161− Ok(())
162−}
163−
164149fn print_file<P: AsRef<Path>>(
165150 options: &Options,
166151 theme: &Theme,
167152 syntax_set: &SyntaxSet,
168− handle: &mut Write,
153+ printer: &mut Printer,
169154 filename: P,
170− line_changes: &Option<LineChanges>,
171155) -> Result<()> {
172156 let mut reader = BufReader::new(File::open(filename.as_ref())?);
173157 let syntax = match options.language {
@@ -178,33 +162,7 @@ fn print_file<P: AsRef<Path>>(
178162 let syntax = syntax.unwrap_or_else(|| syntax_set.find_syntax_plain_text());
179163 let mut highlighter = HighlightLines::new(syntax, theme);
180164
181− let term = Term::stdout();
182− let (_, term_width) = term.size();
183− let term_width = term_width as usize;
184−
185− let colors = if options.colored_output {
186− Colors::colored()
187− } else {
188− Colors::plain()
189− };
190−
191− // Show file name and bars for all but plain style
192− match options.style {
193− OptionsStyle::LineNumbers | OptionsStyle::Full => {
194− print_horizontal_line(handle, &colors.grid, '┬', term_width)?;
195−
196− writeln!(
197− handle,
198− "{}{} File {}",
199− " ".repeat(PANEL_WIDTH),
200− colors.grid.paint("│"),
201− colors.filename.paint(filename.as_ref().to_string_lossy())
202− )?;
203−
204− print_horizontal_line(handle, &colors.grid, '┼', term_width)?;
205− }
206− OptionsStyle::Plain => {}
207− };
165+ printer.print_header(filename.as_ref().to_string_lossy().as_ref())?;
208166
209167 let mut line_nr = 1;
210168 let mut line_buffer = String::new();
@@ -222,49 +180,12 @@ fn print_file<P: AsRef<Path>>(
222180
223181 let regions = highlighter.highlight(line);
224182
225− let line_change = if let Some(ref changes) = *line_changes {
226− match changes.get(&(line_nr as u32)) {
227− Some(&LineChange::Added) => colors.git_added.paint("+"),
228− Some(&LineChange::RemovedAbove) => colors.git_removed.paint("‾"),
229− Some(&LineChange::RemovedBelow) => colors.git_removed.paint("_"),
230− Some(&LineChange::Modified) => colors.git_modified.paint("~"),
231− _ => Style::default().paint(" "),
232− }
233− } else {
234− Style::default().paint(" ")
235− };
236−
237− match options.style {
238− // Show only content for plain style
239− OptionsStyle::Plain => write!(
240− handle,
241− "{}",
242− as_terminal_escaped(®ions, options.true_color, options.colored_output)
243− )?,
244− _ => write!(
245− handle,
246− "{} {} {} {}",
247− colors.line_number.paint(format!("{:4}", line_nr)),
248− // Show git modification markers only for full style
249− match options.style {
250− OptionsStyle::Full => line_change,
251− _ => Style::default().paint(" "),
252− },
253− colors.grid.paint("│"),
254− as_terminal_escaped(®ions, options.true_color, options.colored_output)
255− )?,
256− }
183+ printer.print_line(line_nr, ®ions)?;
257184
258185 line_nr += 1;
259186 }
260187
261− // Show bars for all but plain style
262− match options.style {
263− OptionsStyle::LineNumbers | OptionsStyle::Full => {
264− print_horizontal_line(handle, &colors.grid, '┴', term_width)?
265− }
266− OptionsStyle::Plain => {}
267− };
188+ printer.print_footer()?;
268189
269190 Ok(())
270191}
@@ -514,7 +435,7 @@ fn run() -> Result<()> {
514435 .takes_value(true)
515436 .possible_values(&["auto", "never", "always"])
516437 .default_value("auto")
517− .help("When to use the pager")
438+ .help("When to use the pager"),
518439 )
519440 .subcommand(
520441 SubCommand::with_name("init-cache")
@@ -552,7 +473,7 @@ fn run() -> Result<()> {
552473 Some("always") => true,
553474 Some("never") => false,
554475 Some("auto") | _ => interactive_terminal,
555− }
476+ },
556477 };
557478
558479 let assets =
@@ -569,16 +490,11 @@ fn run() -> Result<()> {
569490 let stdout = io::stdout();
570491 let mut output_type = get_output_type(&stdout, options.paging);
571492 let handle = output_type.handle()?;
493+ let mut printer = Printer::new(handle, &options);
572494 for file in files {
573495 let line_changes = get_git_diff(&file.to_string());
574− print_file(
575− &options,
576− theme,
577− &assets.syntax_set,
578− handle,
579− file,
580− &line_changes,
581− )?;
496+ printer.line_changes = line_changes;
497+ print_file(&options, theme, &assets.syntax_set, &mut printer, file)?;
582498 }
583499 }
584500 }