mirror of
https://github.com/sharkdp/bat.git
synced 2025-03-15 15:18:45 +00:00
Merge branch 'master' into split-modules
This commit is contained in:
commit
eaa257f0ad
105
src/main.rs
105
src/main.rs
@ -22,10 +22,12 @@ mod diff;
|
|||||||
mod printer;
|
mod printer;
|
||||||
mod terminal;
|
mod terminal;
|
||||||
|
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::{self, BufRead, BufReader, Write};
|
use std::io::{self, BufRead, BufReader, Write};
|
||||||
use std::process::{self, Child, Command, Stdio};
|
use std::process::{self, Child, Command, Stdio};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix::fs::FileTypeExt;
|
use std::os::unix::fs::FileTypeExt;
|
||||||
@ -46,22 +48,92 @@ use printer::Printer;
|
|||||||
mod errors {
|
mod errors {
|
||||||
error_chain! {
|
error_chain! {
|
||||||
foreign_links {
|
foreign_links {
|
||||||
|
Clap(::clap::Error);
|
||||||
Io(::std::io::Error);
|
Io(::std::io::Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errors {
|
||||||
|
NoCorrectStylesSpecified {
|
||||||
|
description("no correct styles specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
UnknownStyleName(name: String) {
|
||||||
|
description("unknown style name")
|
||||||
|
display("unknown style name: '{}'", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use errors::*;
|
use errors::*;
|
||||||
|
|
||||||
pub enum OptionsStyle {
|
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
|
||||||
Plain,
|
pub enum OutputComponent {
|
||||||
LineNumbers,
|
Changes,
|
||||||
|
Grid,
|
||||||
|
Header,
|
||||||
|
Numbers,
|
||||||
Full,
|
Full,
|
||||||
|
Plain,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutputComponent {
|
||||||
|
fn components(&self) -> &'static [OutputComponent] {
|
||||||
|
match *self {
|
||||||
|
OutputComponent::Changes => &[OutputComponent::Changes],
|
||||||
|
OutputComponent::Grid => &[OutputComponent::Grid],
|
||||||
|
OutputComponent::Header => &[OutputComponent::Header],
|
||||||
|
OutputComponent::Numbers => &[OutputComponent::Numbers],
|
||||||
|
OutputComponent::Full => &[
|
||||||
|
OutputComponent::Changes,
|
||||||
|
OutputComponent::Grid,
|
||||||
|
OutputComponent::Header,
|
||||||
|
OutputComponent::Numbers,
|
||||||
|
],
|
||||||
|
OutputComponent::Plain => &[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for OutputComponent {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self> {
|
||||||
|
match s {
|
||||||
|
"changes" => Ok(OutputComponent::Changes),
|
||||||
|
"grid" => Ok(OutputComponent::Grid),
|
||||||
|
"header" => Ok(OutputComponent::Header),
|
||||||
|
"numbers" => Ok(OutputComponent::Numbers),
|
||||||
|
"full" => Ok(OutputComponent::Full),
|
||||||
|
"plain" => Ok(OutputComponent::Plain),
|
||||||
|
_ => Err(ErrorKind::UnknownStyleName(s.to_owned()).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OutputComponents(HashSet<OutputComponent>);
|
||||||
|
|
||||||
|
impl OutputComponents {
|
||||||
|
fn changes(&self) -> bool {
|
||||||
|
self.0.contains(&OutputComponent::Changes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grid(&self) -> bool {
|
||||||
|
self.0.contains(&OutputComponent::Grid)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn header(&self) -> bool {
|
||||||
|
self.0.contains(&OutputComponent::Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn numbers(&self) -> bool {
|
||||||
|
self.0.contains(&OutputComponent::Numbers)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Options<'a> {
|
pub struct Options<'a> {
|
||||||
pub true_color: bool,
|
pub true_color: bool,
|
||||||
pub style: OptionsStyle,
|
pub output_components: OutputComponents,
|
||||||
pub language: Option<&'a str>,
|
pub language: Option<&'a str>,
|
||||||
pub colored_output: bool,
|
pub colored_output: bool,
|
||||||
pub paging: bool,
|
pub paging: bool,
|
||||||
@ -256,8 +328,10 @@ fn run() -> Result<()> {
|
|||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("style")
|
Arg::with_name("style")
|
||||||
.long("style")
|
.long("style")
|
||||||
.possible_values(&["auto", "plain", "line-numbers", "full"])
|
.use_delimiter(true)
|
||||||
.default_value("auto")
|
.takes_value(true)
|
||||||
|
.possible_values(&["full", "plain", "changes", "header", "grid", "numbers"])
|
||||||
|
.default_value("full")
|
||||||
.help("Additional info to display along with content"),
|
.help("Additional info to display along with content"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
@ -345,18 +419,17 @@ fn run() -> Result<()> {
|
|||||||
})
|
})
|
||||||
.unwrap_or_else(|| vec![None]); // read from stdin (None) if no args are given
|
.unwrap_or_else(|| vec![None]); // read from stdin (None) if no args are given
|
||||||
|
|
||||||
|
let output_components = values_t!(app_matches.values_of("style"), OutputComponent)?
|
||||||
|
.into_iter()
|
||||||
|
.map(|style| style.components())
|
||||||
|
.fold(HashSet::new(), |mut acc, components| {
|
||||||
|
acc.extend(components.iter().cloned());
|
||||||
|
acc
|
||||||
|
});
|
||||||
|
|
||||||
let options = Options {
|
let options = Options {
|
||||||
true_color: is_truecolor_terminal(),
|
true_color: is_truecolor_terminal(),
|
||||||
style: match app_matches.value_of("style") {
|
output_components: OutputComponents(output_components),
|
||||||
Some("plain") => OptionsStyle::Plain,
|
|
||||||
Some("line-numbers") => OptionsStyle::LineNumbers,
|
|
||||||
Some("full") => OptionsStyle::Full,
|
|
||||||
Some("auto") | _ => if interactive_terminal {
|
|
||||||
OptionsStyle::Full
|
|
||||||
} else {
|
|
||||||
OptionsStyle::Plain
|
|
||||||
},
|
|
||||||
},
|
|
||||||
language: app_matches.value_of("language"),
|
language: app_matches.value_of("language"),
|
||||||
colored_output: match app_matches.value_of("color") {
|
colored_output: match app_matches.value_of("color") {
|
||||||
Some("always") => true,
|
Some("always") => true,
|
||||||
|
101
src/printer.rs
101
src/printer.rs
@ -4,7 +4,7 @@ use errors::*;
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use syntect::highlighting;
|
use syntect::highlighting;
|
||||||
use terminal::as_terminal_escaped;
|
use terminal::as_terminal_escaped;
|
||||||
use {Colors, Options, OptionsStyle};
|
use {Colors, Options};
|
||||||
|
|
||||||
const PANEL_WIDTH: usize = 7;
|
const PANEL_WIDTH: usize = 7;
|
||||||
|
|
||||||
@ -32,19 +32,20 @@ impl<'a> Printer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_header(&mut self, filename: Option<&str>) -> Result<()> {
|
pub fn print_header(&mut self, filename: Option<&str>) -> Result<()> {
|
||||||
match self.options.style {
|
if !self.options.output_components.header() {
|
||||||
OptionsStyle::Full => {}
|
return Ok(());
|
||||||
_ => return Ok(()),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.print_horizontal_line('┬')?;
|
if self.options.output_components.grid() {
|
||||||
|
self.print_horizontal_line('┬')?;
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
self.handle,
|
self.handle,
|
||||||
"{}{} ",
|
"{}{} ",
|
||||||
" ".repeat(PANEL_WIDTH),
|
" ".repeat(PANEL_WIDTH),
|
||||||
self.colors.grid.paint("│"),
|
self.colors.grid.paint("│"),
|
||||||
)?;
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
writeln!(
|
writeln!(
|
||||||
self.handle,
|
self.handle,
|
||||||
@ -53,11 +54,15 @@ impl<'a> Printer<'a> {
|
|||||||
self.colors.filename.paint(filename.unwrap_or("STDIN"))
|
self.colors.filename.paint(filename.unwrap_or("STDIN"))
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.print_horizontal_line('┼')
|
if self.options.output_components.grid() {
|
||||||
|
self.print_horizontal_line('┼')?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_footer(&mut self) -> Result<()> {
|
pub fn print_footer(&mut self) -> Result<()> {
|
||||||
if let OptionsStyle::Full = self.options.style {
|
if self.options.output_components.grid() {
|
||||||
self.print_horizontal_line('┴')
|
self.print_horizontal_line('┴')
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -80,12 +85,17 @@ impl<'a> Printer<'a> {
|
|||||||
)),
|
)),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let grid_requested = self.options.output_components.grid();
|
||||||
write!(
|
write!(
|
||||||
self.handle,
|
self.handle,
|
||||||
"{}",
|
"{}",
|
||||||
decorations
|
decorations
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|dec| dec)
|
.filter_map(|dec| if grid_requested {
|
||||||
|
Some(dec.unwrap_or(" ".to_owned()))
|
||||||
|
} else {
|
||||||
|
dec
|
||||||
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(" ")
|
.join(" ")
|
||||||
)?;
|
)?;
|
||||||
@ -94,45 +104,48 @@ impl<'a> Printer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_line_number(&self, line_number: usize) -> Option<String> {
|
fn print_line_number(&self, line_number: usize) -> Option<String> {
|
||||||
if let OptionsStyle::Plain = self.options.style {
|
if self.options.output_components.numbers() {
|
||||||
return None;
|
Some(
|
||||||
|
self.colors
|
||||||
|
.line_number
|
||||||
|
.paint(format!("{:4}", line_number))
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
} else if self.options.output_components.grid() {
|
||||||
|
Some(" ".to_owned())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(
|
|
||||||
self.colors
|
|
||||||
.line_number
|
|
||||||
.paint(format!("{:4}", line_number))
|
|
||||||
.to_string(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_git_marker(&self, line_number: usize) -> Option<String> {
|
fn print_git_marker(&self, line_number: usize) -> Option<String> {
|
||||||
match self.options.style {
|
if self.options.output_components.changes() {
|
||||||
OptionsStyle::Full => {}
|
Some(
|
||||||
_ => return None,
|
if let Some(ref changes) = self.line_changes {
|
||||||
}
|
match changes.get(&(line_number as u32)) {
|
||||||
|
Some(&LineChange::Added) => self.colors.git_added.paint("+"),
|
||||||
let marker = if let Some(ref changes) = self.line_changes {
|
Some(&LineChange::RemovedAbove) => self.colors.git_removed.paint("‾"),
|
||||||
match changes.get(&(line_number as u32)) {
|
Some(&LineChange::RemovedBelow) => self.colors.git_removed.paint("_"),
|
||||||
Some(&LineChange::Added) => self.colors.git_added.paint("+"),
|
Some(&LineChange::Modified) => self.colors.git_modified.paint("~"),
|
||||||
Some(&LineChange::RemovedAbove) => self.colors.git_removed.paint("‾"),
|
_ => Style::default().paint(" "),
|
||||||
Some(&LineChange::RemovedBelow) => self.colors.git_removed.paint("_"),
|
}
|
||||||
Some(&LineChange::Modified) => self.colors.git_modified.paint("~"),
|
} else {
|
||||||
_ => Style::default().paint(" "),
|
Style::default().paint(" ")
|
||||||
}
|
}.to_string(),
|
||||||
|
)
|
||||||
|
} else if self.options.output_components.grid() {
|
||||||
|
Some(" ".to_owned())
|
||||||
} else {
|
} else {
|
||||||
Style::default().paint(" ")
|
None
|
||||||
};
|
}
|
||||||
|
|
||||||
Some(marker.to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_line_border(&self) -> Option<String> {
|
fn print_line_border(&self) -> Option<String> {
|
||||||
if let OptionsStyle::Plain = self.options.style {
|
if self.options.output_components.grid() {
|
||||||
return None;
|
Some(self.colors.grid.paint("│").to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(self.colors.grid.paint("│").to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_horizontal_line(&mut self, grid_char: char) -> Result<()> {
|
fn print_horizontal_line(&mut self, grid_char: char) -> Result<()> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user