mirror of
https://github.com/sharkdp/bat.git
synced 2025-02-21 12:28:30 +00:00
Add printer
This adds a separate struct that handles printing of the different tokens.
This commit is contained in:
parent
b625d07c34
commit
53d67e2b6e
138
src/main.rs
138
src/main.rs
@ -17,6 +17,7 @@ extern crate directories;
|
|||||||
extern crate git2;
|
extern crate git2;
|
||||||
extern crate syntect;
|
extern crate syntect;
|
||||||
|
|
||||||
|
mod printer;
|
||||||
mod terminal;
|
mod terminal;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -30,7 +31,6 @@ use ansi_term::Colour::{Fixed, Green, Red, White, Yellow};
|
|||||||
use ansi_term::Style;
|
use ansi_term::Style;
|
||||||
use atty::Stream;
|
use atty::Stream;
|
||||||
use clap::{App, AppSettings, Arg, SubCommand};
|
use clap::{App, AppSettings, Arg, SubCommand};
|
||||||
use console::Term;
|
|
||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
use git2::{DiffOptions, IntoCString, Repository};
|
use git2::{DiffOptions, IntoCString, Repository};
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ use syntect::easy::HighlightLines;
|
|||||||
use syntect::highlighting::{Theme, ThemeSet};
|
use syntect::highlighting::{Theme, ThemeSet};
|
||||||
use syntect::parsing::SyntaxSet;
|
use syntect::parsing::SyntaxSet;
|
||||||
|
|
||||||
use terminal::as_terminal_escaped;
|
use printer::Printer;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref PROJECT_DIRS: ProjectDirs = ProjectDirs::from("", "", crate_name!());
|
static ref PROJECT_DIRS: ProjectDirs = ProjectDirs::from("", "", crate_name!());
|
||||||
@ -55,18 +55,18 @@ mod errors {
|
|||||||
|
|
||||||
use errors::*;
|
use errors::*;
|
||||||
|
|
||||||
enum OptionsStyle {
|
pub enum OptionsStyle {
|
||||||
Plain,
|
Plain,
|
||||||
LineNumbers,
|
LineNumbers,
|
||||||
Full,
|
Full,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Options<'a> {
|
pub struct Options<'a> {
|
||||||
true_color: bool,
|
pub true_color: bool,
|
||||||
style: OptionsStyle,
|
pub style: OptionsStyle,
|
||||||
language: Option<&'a str>,
|
pub language: Option<&'a str>,
|
||||||
colored_output: bool,
|
pub colored_output: bool,
|
||||||
paging: bool,
|
pub paging: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OutputType<'a> {
|
enum OutputType<'a> {
|
||||||
@ -107,27 +107,26 @@ impl<'a> Drop for OutputType<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
enum LineChange {
|
pub enum LineChange {
|
||||||
Added,
|
Added,
|
||||||
RemovedAbove,
|
RemovedAbove,
|
||||||
RemovedBelow,
|
RemovedBelow,
|
||||||
Modified,
|
Modified,
|
||||||
}
|
}
|
||||||
|
|
||||||
type LineChanges = HashMap<u32, LineChange>;
|
pub type LineChanges = HashMap<u32, LineChange>;
|
||||||
|
|
||||||
const PANEL_WIDTH: usize = 7;
|
|
||||||
const GRID_COLOR: u8 = 238;
|
const GRID_COLOR: u8 = 238;
|
||||||
const LINE_NUMBER_COLOR: u8 = 244;
|
const LINE_NUMBER_COLOR: u8 = 244;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Colors {
|
pub struct Colors {
|
||||||
grid: Style,
|
pub grid: Style,
|
||||||
filename: Style,
|
pub filename: Style,
|
||||||
git_added: Style,
|
pub git_added: Style,
|
||||||
git_removed: Style,
|
pub git_removed: Style,
|
||||||
git_modified: Style,
|
pub git_modified: Style,
|
||||||
line_number: Style,
|
pub line_number: Style,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Colors {
|
impl Colors {
|
||||||
@ -147,27 +146,12 @@ impl Colors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_horizontal_line(
|
|
||||||
handle: &mut Write,
|
|
||||||
grid_color: &Style,
|
|
||||||
grid_char: char,
|
|
||||||
term_width: usize,
|
|
||||||
) -> Result<()> {
|
|
||||||
let hline = "─".repeat(term_width - (PANEL_WIDTH + 1));
|
|
||||||
let hline = format!("{}{}{}", "─".repeat(PANEL_WIDTH), grid_char, hline);
|
|
||||||
|
|
||||||
writeln!(handle, "{}", grid_color.paint(hline))?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_file<P: AsRef<Path>>(
|
fn print_file<P: AsRef<Path>>(
|
||||||
options: &Options,
|
options: &Options,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
syntax_set: &SyntaxSet,
|
syntax_set: &SyntaxSet,
|
||||||
handle: &mut Write,
|
printer: &mut Printer,
|
||||||
filename: P,
|
filename: P,
|
||||||
line_changes: &Option<LineChanges>,
|
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut reader = BufReader::new(File::open(filename.as_ref())?);
|
let mut reader = BufReader::new(File::open(filename.as_ref())?);
|
||||||
let syntax = match options.language {
|
let syntax = match options.language {
|
||||||
@ -178,33 +162,7 @@ fn print_file<P: AsRef<Path>>(
|
|||||||
let syntax = syntax.unwrap_or_else(|| syntax_set.find_syntax_plain_text());
|
let syntax = syntax.unwrap_or_else(|| syntax_set.find_syntax_plain_text());
|
||||||
let mut highlighter = HighlightLines::new(syntax, theme);
|
let mut highlighter = HighlightLines::new(syntax, theme);
|
||||||
|
|
||||||
let term = Term::stdout();
|
printer.print_header(filename.as_ref().to_string_lossy().as_ref())?;
|
||||||
let (_, term_width) = term.size();
|
|
||||||
let term_width = term_width as usize;
|
|
||||||
|
|
||||||
let colors = if options.colored_output {
|
|
||||||
Colors::colored()
|
|
||||||
} else {
|
|
||||||
Colors::plain()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Show file name and bars for all but plain style
|
|
||||||
match options.style {
|
|
||||||
OptionsStyle::LineNumbers | OptionsStyle::Full => {
|
|
||||||
print_horizontal_line(handle, &colors.grid, '┬', term_width)?;
|
|
||||||
|
|
||||||
writeln!(
|
|
||||||
handle,
|
|
||||||
"{}{} File {}",
|
|
||||||
" ".repeat(PANEL_WIDTH),
|
|
||||||
colors.grid.paint("│"),
|
|
||||||
colors.filename.paint(filename.as_ref().to_string_lossy())
|
|
||||||
)?;
|
|
||||||
|
|
||||||
print_horizontal_line(handle, &colors.grid, '┼', term_width)?;
|
|
||||||
}
|
|
||||||
OptionsStyle::Plain => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut line_nr = 1;
|
let mut line_nr = 1;
|
||||||
let mut line_buffer = String::new();
|
let mut line_buffer = String::new();
|
||||||
@ -222,49 +180,12 @@ fn print_file<P: AsRef<Path>>(
|
|||||||
|
|
||||||
let regions = highlighter.highlight(line);
|
let regions = highlighter.highlight(line);
|
||||||
|
|
||||||
let line_change = if let Some(ref changes) = *line_changes {
|
printer.print_line(line_nr, ®ions)?;
|
||||||
match changes.get(&(line_nr as u32)) {
|
|
||||||
Some(&LineChange::Added) => colors.git_added.paint("+"),
|
|
||||||
Some(&LineChange::RemovedAbove) => colors.git_removed.paint("‾"),
|
|
||||||
Some(&LineChange::RemovedBelow) => colors.git_removed.paint("_"),
|
|
||||||
Some(&LineChange::Modified) => colors.git_modified.paint("~"),
|
|
||||||
_ => Style::default().paint(" "),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Style::default().paint(" ")
|
|
||||||
};
|
|
||||||
|
|
||||||
match options.style {
|
|
||||||
// Show only content for plain style
|
|
||||||
OptionsStyle::Plain => write!(
|
|
||||||
handle,
|
|
||||||
"{}",
|
|
||||||
as_terminal_escaped(®ions, options.true_color, options.colored_output)
|
|
||||||
)?,
|
|
||||||
_ => write!(
|
|
||||||
handle,
|
|
||||||
"{} {} {} {}",
|
|
||||||
colors.line_number.paint(format!("{:4}", line_nr)),
|
|
||||||
// Show git modification markers only for full style
|
|
||||||
match options.style {
|
|
||||||
OptionsStyle::Full => line_change,
|
|
||||||
_ => Style::default().paint(" "),
|
|
||||||
},
|
|
||||||
colors.grid.paint("│"),
|
|
||||||
as_terminal_escaped(®ions, options.true_color, options.colored_output)
|
|
||||||
)?,
|
|
||||||
}
|
|
||||||
|
|
||||||
line_nr += 1;
|
line_nr += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show bars for all but plain style
|
printer.print_footer()?;
|
||||||
match options.style {
|
|
||||||
OptionsStyle::LineNumbers | OptionsStyle::Full => {
|
|
||||||
print_horizontal_line(handle, &colors.grid, '┴', term_width)?
|
|
||||||
}
|
|
||||||
OptionsStyle::Plain => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -514,7 +435,7 @@ fn run() -> Result<()> {
|
|||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(&["auto", "never", "always"])
|
.possible_values(&["auto", "never", "always"])
|
||||||
.default_value("auto")
|
.default_value("auto")
|
||||||
.help("When to use the pager")
|
.help("When to use the pager"),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("init-cache")
|
SubCommand::with_name("init-cache")
|
||||||
@ -552,7 +473,7 @@ fn run() -> Result<()> {
|
|||||||
Some("always") => true,
|
Some("always") => true,
|
||||||
Some("never") => false,
|
Some("never") => false,
|
||||||
Some("auto") | _ => interactive_terminal,
|
Some("auto") | _ => interactive_terminal,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let assets =
|
let assets =
|
||||||
@ -569,16 +490,11 @@ fn run() -> Result<()> {
|
|||||||
let stdout = io::stdout();
|
let stdout = io::stdout();
|
||||||
let mut output_type = get_output_type(&stdout, options.paging);
|
let mut output_type = get_output_type(&stdout, options.paging);
|
||||||
let handle = output_type.handle()?;
|
let handle = output_type.handle()?;
|
||||||
|
let mut printer = Printer::new(handle, &options);
|
||||||
for file in files {
|
for file in files {
|
||||||
let line_changes = get_git_diff(&file.to_string());
|
let line_changes = get_git_diff(&file.to_string());
|
||||||
print_file(
|
printer.line_changes = line_changes;
|
||||||
&options,
|
print_file(&options, theme, &assets.syntax_set, &mut printer, file)?;
|
||||||
theme,
|
|
||||||
&assets.syntax_set,
|
|
||||||
handle,
|
|
||||||
file,
|
|
||||||
&line_changes,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
145
src/printer.rs
Normal file
145
src/printer.rs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
use ansi_term::Style;
|
||||||
|
use console::Term;
|
||||||
|
use errors::*;
|
||||||
|
use std::io::Write;
|
||||||
|
use syntect::highlighting;
|
||||||
|
use terminal::as_terminal_escaped;
|
||||||
|
use {Colors, LineChange, LineChanges, Options, OptionsStyle};
|
||||||
|
|
||||||
|
const PANEL_WIDTH: usize = 7;
|
||||||
|
|
||||||
|
pub struct Printer<'a> {
|
||||||
|
handle: &'a mut Write,
|
||||||
|
colors: Colors,
|
||||||
|
term_width: usize,
|
||||||
|
options: &'a Options<'a>,
|
||||||
|
pub line_changes: Option<LineChanges>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Printer<'a> {
|
||||||
|
pub fn new(handle: &'a mut Write, options: &'a Options) -> Self {
|
||||||
|
let (_, term_width) = Term::stdout().size();
|
||||||
|
let term_width = term_width as usize;
|
||||||
|
|
||||||
|
let colors = if options.colored_output {
|
||||||
|
Colors::colored()
|
||||||
|
} else {
|
||||||
|
Colors::plain()
|
||||||
|
};
|
||||||
|
|
||||||
|
Printer {
|
||||||
|
handle,
|
||||||
|
colors,
|
||||||
|
term_width,
|
||||||
|
options,
|
||||||
|
line_changes: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_header(&mut self, filename: &str) -> Result<()> {
|
||||||
|
match self.options.style {
|
||||||
|
OptionsStyle::Full => {}
|
||||||
|
_ => return Ok(()),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.print_horizontal_line('┬')?;
|
||||||
|
|
||||||
|
writeln!(
|
||||||
|
self.handle,
|
||||||
|
"{}{} File {}",
|
||||||
|
" ".repeat(PANEL_WIDTH),
|
||||||
|
self.colors.grid.paint("│"),
|
||||||
|
self.colors.filename.paint(filename)
|
||||||
|
)?;
|
||||||
|
|
||||||
|
self.print_horizontal_line('┼')
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_footer(&mut self) -> Result<()> {
|
||||||
|
if let OptionsStyle::Full = self.options.style {
|
||||||
|
self.print_horizontal_line('┴')
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_line(
|
||||||
|
&mut self,
|
||||||
|
line_number: usize,
|
||||||
|
regions: &[(highlighting::Style, &str)],
|
||||||
|
) -> Result<()> {
|
||||||
|
let decorations = vec![
|
||||||
|
self.print_line_number(line_number),
|
||||||
|
self.print_git_marker(line_number),
|
||||||
|
self.print_line_border(),
|
||||||
|
Some(as_terminal_escaped(
|
||||||
|
®ions,
|
||||||
|
self.options.true_color,
|
||||||
|
self.options.colored_output,
|
||||||
|
)),
|
||||||
|
];
|
||||||
|
|
||||||
|
write!(
|
||||||
|
self.handle,
|
||||||
|
"{}",
|
||||||
|
decorations
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|dec| dec)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ")
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_line_number(&self, line_number: usize) -> Option<String> {
|
||||||
|
if let OptionsStyle::Plain = self.options.style {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(
|
||||||
|
self.colors
|
||||||
|
.line_number
|
||||||
|
.paint(format!("{:4}", line_number))
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_git_marker(&self, line_number: usize) -> Option<String> {
|
||||||
|
match self.options.style {
|
||||||
|
OptionsStyle::Full => {}
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
|
||||||
|
let marker = if let Some(ref changes) = self.line_changes {
|
||||||
|
match changes.get(&(line_number as u32)) {
|
||||||
|
Some(&LineChange::Added) => self.colors.git_added.paint("+"),
|
||||||
|
Some(&LineChange::RemovedAbove) => self.colors.git_removed.paint("‾"),
|
||||||
|
Some(&LineChange::RemovedBelow) => self.colors.git_removed.paint("_"),
|
||||||
|
Some(&LineChange::Modified) => self.colors.git_modified.paint("~"),
|
||||||
|
_ => Style::default().paint(" "),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Style::default().paint(" ")
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(marker.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_line_border(&self) -> Option<String> {
|
||||||
|
if let OptionsStyle::Plain = self.options.style {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(self.colors.grid.paint("│").to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_horizontal_line(&mut self, grid_char: char) -> Result<()> {
|
||||||
|
let hline = "─".repeat(self.term_width - (PANEL_WIDTH + 1));
|
||||||
|
let hline = format!("{}{}{}", "─".repeat(PANEL_WIDTH), grid_char, hline);
|
||||||
|
|
||||||
|
writeln!(self.handle, "{}", self.colors.grid.paint(hline))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user