Add new `--style` called `header-filesize` and display it by default (#1988)

Also rename `header` to `header-filename`.

Related to #1701
This commit is contained in:
Mahdi Dibaiee 2022-02-07 19:48:57 +00:00 committed by GitHub
parent f3f8194932
commit 312c8ef01f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
111 changed files with 302 additions and 42 deletions

View File

@ -2,6 +2,8 @@
## Features ## Features
- New style component `header-filesize` to show size of the displayed file in the header. See #1988 (@mdibaiee)
## Bugfixes ## Bugfixes
## Other ## Other

7
Cargo.lock generated
View File

@ -82,6 +82,7 @@ dependencies = [
"atty", "atty",
"bincode", "bincode",
"bugreport", "bugreport",
"bytesize",
"clap", "clap",
"clircle", "clircle",
"console", "console",
@ -169,6 +170,12 @@ version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f"
[[package]]
name = "bytesize"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.72" version = "1.0.72"

View File

@ -65,6 +65,7 @@ dirs-next = { version = "2.0.0", optional = true }
grep-cli = { version = "0.1.6", optional = true } grep-cli = { version = "0.1.6", optional = true }
regex = { version = "1.0", optional = true } regex = { version = "1.0", optional = true }
walkdir = { version = "2.0", optional = true } walkdir = { version = "2.0", optional = true }
bytesize = { version = "1.1.0" }
[dependencies.git2] [dependencies.git2]
version = "0.13" version = "0.13"

View File

@ -396,11 +396,19 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
.validator(|val| { .validator(|val| {
let mut invalid_vals = val.split(',').filter(|style| { let mut invalid_vals = val.split(',').filter(|style| {
!&[ !&[
"auto", "full", "plain", "header", "grid", "rule", "numbers", "snip", "auto",
"full",
"plain",
"header",
"header-filename",
"header-filesize",
"grid",
"rule",
"numbers",
"snip",
#[cfg(feature = "git")] #[cfg(feature = "git")]
"changes", "changes",
] ].contains(style)
.contains(style)
}); });
if let Some(invalid) = invalid_vals.next() { if let Some(invalid) = invalid_vals.next() {
@ -426,7 +434,9 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
* auto: same as 'full', unless the output is piped.\n \ * auto: same as 'full', unless the output is piped.\n \
* plain: disables all available components.\n \ * plain: disables all available components.\n \
* changes: show Git modification markers.\n \ * changes: show Git modification markers.\n \
* header: show filenames before the content.\n \ * header: alias for 'header-filename'.\n \
* header-filename: show filenames before the content.\n \
* header-filesize: show file sizes before the content.\n \
* grid: vertical/horizontal lines to separate side bar\n \ * grid: vertical/horizontal lines to separate side bar\n \
and the header from the content.\n \ and the header from the content.\n \
* rule: horizontal lines to delimit files.\n \ * rule: horizontal lines to delimit files.\n \

View File

@ -1,4 +1,5 @@
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fs;
use std::fs::File; use std::fs::File;
use std::io::{self, BufRead, BufReader, Read}; use std::io::{self, BufRead, BufReader, Read};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -87,6 +88,7 @@ impl<'a> InputKind<'a> {
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub(crate) struct InputMetadata { pub(crate) struct InputMetadata {
pub(crate) user_provided_name: Option<PathBuf>, pub(crate) user_provided_name: Option<PathBuf>,
pub(crate) size: Option<u64>,
} }
pub struct Input<'a> { pub struct Input<'a> {
@ -130,9 +132,14 @@ impl<'a> Input<'a> {
fn _ordinary_file(path: &Path) -> Self { fn _ordinary_file(path: &Path) -> Self {
let kind = InputKind::OrdinaryFile(path.to_path_buf()); let kind = InputKind::OrdinaryFile(path.to_path_buf());
let metadata = InputMetadata {
size: fs::metadata(path).map(|m| m.len()).ok(),
..InputMetadata::default()
};
Input { Input {
description: kind.description(), description: kind.description(),
metadata: InputMetadata::default(), metadata,
kind, kind,
} }
} }

View File

@ -4,6 +4,8 @@ use std::vec::Vec;
use ansi_term::Colour::{Fixed, Green, Red, Yellow}; use ansi_term::Colour::{Fixed, Green, Red, Yellow};
use ansi_term::Style; use ansi_term::Style;
use bytesize::ByteSize;
use console::AnsiCodeIterator; use console::AnsiCodeIterator;
use syntect::easy::HighlightLines; use syntect::easy::HighlightLines;
@ -29,6 +31,7 @@ use crate::error::*;
use crate::input::OpenedInput; use crate::input::OpenedInput;
use crate::line_range::RangeCheckResult; use crate::line_range::RangeCheckResult;
use crate::preprocessor::{expand_tabs, replace_nonprintable}; use crate::preprocessor::{expand_tabs, replace_nonprintable};
use crate::style::StyleComponent;
use crate::terminal::{as_terminal_escaped, to_ansi_color}; use crate::terminal::{as_terminal_escaped, to_ansi_color};
use crate::vscreen::AnsiStyle; use crate::vscreen::AnsiStyle;
use crate::wrapping::WrappingMode; use crate::wrapping::WrappingMode;
@ -250,6 +253,21 @@ impl<'a> InteractivePrinter<'a> {
} }
} }
fn print_header_component_indent(&mut self, handle: &mut dyn Write) -> std::io::Result<()> {
if self.config.style_components.grid() {
write!(
handle,
"{}{}",
" ".repeat(self.panel_width),
self.colors
.grid
.paint(if self.panel_width > 0 { "" } else { "" }),
)
} else {
write!(handle, "{}", " ".repeat(self.panel_width))
}
}
fn preprocess(&self, text: &str, cursor: &mut usize) -> String { fn preprocess(&self, text: &str, cursor: &mut usize) -> String {
if self.config.tab_width > 0 { if self.config.tab_width > 0 {
return expand_tabs(text, self.config.tab_width, cursor); return expand_tabs(text, self.config.tab_width, cursor);
@ -287,25 +305,6 @@ impl<'a> Printer for InteractivePrinter<'a> {
return Ok(()); return Ok(());
} }
if self.config.style_components.grid() {
self.print_horizontal_line(handle, '┬')?;
write!(
handle,
"{}{}",
" ".repeat(self.panel_width),
self.colors
.grid
.paint(if self.panel_width > 0 { "" } else { "" }),
)?;
} else {
// Only pad space between files, if we haven't already drawn a horizontal rule
if add_header_padding && !self.config.style_components.rule() {
writeln!(handle)?;
}
write!(handle, "{}", " ".repeat(self.panel_width))?;
}
let mode = match self.content_type { let mode = match self.content_type {
Some(ContentType::BINARY) => " <BINARY>", Some(ContentType::BINARY) => " <BINARY>",
Some(ContentType::UTF_16LE) => " <UTF-16LE>", Some(ContentType::UTF_16LE) => " <UTF-16LE>",
@ -315,17 +314,60 @@ impl<'a> Printer for InteractivePrinter<'a> {
}; };
let description = &input.description; let description = &input.description;
let metadata = &input.metadata;
writeln!( // We use this iterator to have a deterministic order for
handle, // header components. HashSet has arbitrary order, but Vec is ordered.
"{}{}{}", let header_components: Vec<StyleComponent> = [
description (
.kind() StyleComponent::HeaderFilename,
.map(|kind| format!("{}: ", kind)) self.config.style_components.header_filename(),
.unwrap_or_else(|| "".into()), ),
self.colors.filename.paint(description.title()), (
mode StyleComponent::HeaderFilesize,
)?; self.config.style_components.header_filesize(),
),
]
.iter()
.filter(|(_, is_enabled)| *is_enabled)
.map(|(component, _)| *component)
.collect();
// Print the cornering grid before the first header component
if self.config.style_components.grid() {
self.print_horizontal_line(handle, '┬')?;
} else {
// Only pad space between files, if we haven't already drawn a horizontal rule
if add_header_padding && !self.config.style_components.rule() {
writeln!(handle)?;
}
}
header_components.iter().try_for_each(|component| {
self.print_header_component_indent(handle)?;
match component {
StyleComponent::HeaderFilename => writeln!(
handle,
"{}{}{}",
description
.kind()
.map(|kind| format!("{}: ", kind))
.unwrap_or_else(|| "".into()),
self.colors.header_value.paint(description.title()),
mode
),
StyleComponent::HeaderFilesize => {
let bsize = metadata
.size
.map(|s| format!("{}", ByteSize(s)))
.unwrap_or_else(|| "-".into());
writeln!(handle, "Size: {}", self.colors.header_value.paint(bsize))
}
_ => Ok(()),
}
})?;
if self.config.style_components.grid() { if self.config.style_components.grid() {
if self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable { if self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable {
@ -617,7 +659,7 @@ const DEFAULT_GUTTER_COLOR: u8 = 238;
pub struct Colors { pub struct Colors {
pub grid: Style, pub grid: Style,
pub rule: Style, pub rule: Style,
pub filename: Style, pub header_value: Style,
pub git_added: Style, pub git_added: Style,
pub git_removed: Style, pub git_removed: Style,
pub git_modified: Style, pub git_modified: Style,
@ -646,7 +688,7 @@ impl Colors {
Colors { Colors {
grid: gutter_style, grid: gutter_style,
rule: gutter_style, rule: gutter_style,
filename: Style::new().bold(), header_value: Style::new().bold(),
git_added: Green.normal(), git_added: Green.normal(),
git_removed: Red.normal(), git_removed: Red.normal(),
git_modified: Yellow.normal(), git_modified: Yellow.normal(),

View File

@ -3,6 +3,7 @@ use std::str::FromStr;
use crate::error::*; use crate::error::*;
#[non_exhaustive]
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)] #[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
pub enum StyleComponent { pub enum StyleComponent {
Auto, Auto,
@ -11,6 +12,8 @@ pub enum StyleComponent {
Grid, Grid,
Rule, Rule,
Header, Header,
HeaderFilename,
HeaderFilesize,
LineNumbers, LineNumbers,
Snip, Snip,
Full, Full,
@ -31,14 +34,17 @@ impl StyleComponent {
StyleComponent::Changes => &[StyleComponent::Changes], StyleComponent::Changes => &[StyleComponent::Changes],
StyleComponent::Grid => &[StyleComponent::Grid], StyleComponent::Grid => &[StyleComponent::Grid],
StyleComponent::Rule => &[StyleComponent::Rule], StyleComponent::Rule => &[StyleComponent::Rule],
StyleComponent::Header => &[StyleComponent::Header], StyleComponent::Header => &[StyleComponent::HeaderFilename],
StyleComponent::HeaderFilename => &[StyleComponent::HeaderFilename],
StyleComponent::HeaderFilesize => &[StyleComponent::HeaderFilesize],
StyleComponent::LineNumbers => &[StyleComponent::LineNumbers], StyleComponent::LineNumbers => &[StyleComponent::LineNumbers],
StyleComponent::Snip => &[StyleComponent::Snip], StyleComponent::Snip => &[StyleComponent::Snip],
StyleComponent::Full => &[ StyleComponent::Full => &[
#[cfg(feature = "git")] #[cfg(feature = "git")]
StyleComponent::Changes, StyleComponent::Changes,
StyleComponent::Grid, StyleComponent::Grid,
StyleComponent::Header, StyleComponent::HeaderFilename,
StyleComponent::HeaderFilesize,
StyleComponent::LineNumbers, StyleComponent::LineNumbers,
StyleComponent::Snip, StyleComponent::Snip,
], ],
@ -58,6 +64,8 @@ impl FromStr for StyleComponent {
"grid" => Ok(StyleComponent::Grid), "grid" => Ok(StyleComponent::Grid),
"rule" => Ok(StyleComponent::Rule), "rule" => Ok(StyleComponent::Rule),
"header" => Ok(StyleComponent::Header), "header" => Ok(StyleComponent::Header),
"header-filename" => Ok(StyleComponent::HeaderFilename),
"header-filesize" => Ok(StyleComponent::HeaderFilesize),
"numbers" => Ok(StyleComponent::LineNumbers), "numbers" => Ok(StyleComponent::LineNumbers),
"snip" => Ok(StyleComponent::Snip), "snip" => Ok(StyleComponent::Snip),
"full" => Ok(StyleComponent::Full), "full" => Ok(StyleComponent::Full),
@ -89,7 +97,15 @@ impl StyleComponents {
} }
pub fn header(&self) -> bool { pub fn header(&self) -> bool {
self.0.contains(&StyleComponent::Header) self.header_filename() || self.header_filesize()
}
pub fn header_filename(&self) -> bool {
self.0.contains(&StyleComponent::HeaderFilename)
}
pub fn header_filesize(&self) -> bool {
self.0.contains(&StyleComponent::HeaderFilesize)
} }
pub fn numbers(&self) -> bool { pub fn numbers(&self) -> bool {

View File

@ -0,0 +1 @@
I am small file 0

View File

@ -0,0 +1 @@
I am small file 1

View File

@ -0,0 +1 @@
I am small file 10

View File

@ -0,0 +1 @@
I am small file 100

View File

@ -0,0 +1 @@
I am small file 11

View File

@ -0,0 +1 @@
I am small file 12

View File

@ -0,0 +1 @@
I am small file 13

View File

@ -0,0 +1 @@
I am small file 14

View File

@ -0,0 +1 @@
I am small file 15

View File

@ -0,0 +1 @@
I am small file 16

View File

@ -0,0 +1 @@
I am small file 17

View File

@ -0,0 +1 @@
I am small file 18

View File

@ -0,0 +1 @@
I am small file 19

View File

@ -0,0 +1 @@
I am small file 2

View File

@ -0,0 +1 @@
I am small file 20

View File

@ -0,0 +1 @@
I am small file 21

View File

@ -0,0 +1 @@
I am small file 22

View File

@ -0,0 +1 @@
I am small file 23

View File

@ -0,0 +1 @@
I am small file 24

View File

@ -0,0 +1 @@
I am small file 25

View File

@ -0,0 +1 @@
I am small file 26

View File

@ -0,0 +1 @@
I am small file 27

View File

@ -0,0 +1 @@
I am small file 28

View File

@ -0,0 +1 @@
I am small file 29

View File

@ -0,0 +1 @@
I am small file 3

View File

@ -0,0 +1 @@
I am small file 30

View File

@ -0,0 +1 @@
I am small file 31

View File

@ -0,0 +1 @@
I am small file 32

View File

@ -0,0 +1 @@
I am small file 33

View File

@ -0,0 +1 @@
I am small file 34

View File

@ -0,0 +1 @@
I am small file 35

View File

@ -0,0 +1 @@
I am small file 36

View File

@ -0,0 +1 @@
I am small file 37

View File

@ -0,0 +1 @@
I am small file 38

View File

@ -0,0 +1 @@
I am small file 39

View File

@ -0,0 +1 @@
I am small file 4

View File

@ -0,0 +1 @@
I am small file 40

View File

@ -0,0 +1 @@
I am small file 41

View File

@ -0,0 +1 @@
I am small file 42

View File

@ -0,0 +1 @@
I am small file 43

View File

@ -0,0 +1 @@
I am small file 44

View File

@ -0,0 +1 @@
I am small file 45

View File

@ -0,0 +1 @@
I am small file 46

View File

@ -0,0 +1 @@
I am small file 47

View File

@ -0,0 +1 @@
I am small file 48

View File

@ -0,0 +1 @@
I am small file 49

View File

@ -0,0 +1 @@
I am small file 5

View File

@ -0,0 +1 @@
I am small file 50

View File

@ -0,0 +1 @@
I am small file 51

View File

@ -0,0 +1 @@
I am small file 52

View File

@ -0,0 +1 @@
I am small file 53

View File

@ -0,0 +1 @@
I am small file 54

View File

@ -0,0 +1 @@
I am small file 55

View File

@ -0,0 +1 @@
I am small file 56

View File

@ -0,0 +1 @@
I am small file 57

View File

@ -0,0 +1 @@
I am small file 58

View File

@ -0,0 +1 @@
I am small file 59

View File

@ -0,0 +1 @@
I am small file 6

View File

@ -0,0 +1 @@
I am small file 60

View File

@ -0,0 +1 @@
I am small file 61

View File

@ -0,0 +1 @@
I am small file 62

View File

@ -0,0 +1 @@
I am small file 63

View File

@ -0,0 +1 @@
I am small file 64

View File

@ -0,0 +1 @@
I am small file 65

View File

@ -0,0 +1 @@
I am small file 66

View File

@ -0,0 +1 @@
I am small file 67

View File

@ -0,0 +1 @@
I am small file 68

View File

@ -0,0 +1 @@
I am small file 69

View File

@ -0,0 +1 @@
I am small file 7

View File

@ -0,0 +1 @@
I am small file 70

View File

@ -0,0 +1 @@
I am small file 71

View File

@ -0,0 +1 @@
I am small file 72

View File

@ -0,0 +1 @@
I am small file 73

View File

@ -0,0 +1 @@
I am small file 74

View File

@ -0,0 +1 @@
I am small file 75

View File

@ -0,0 +1 @@
I am small file 76

View File

@ -0,0 +1 @@
I am small file 77

View File

@ -0,0 +1 @@
I am small file 78

View File

@ -0,0 +1 @@
I am small file 79

View File

@ -0,0 +1 @@
I am small file 8

View File

@ -0,0 +1 @@
I am small file 80

View File

@ -0,0 +1 @@
I am small file 81

View File

@ -0,0 +1 @@
I am small file 82

View File

@ -0,0 +1 @@
I am small file 83

View File

@ -0,0 +1 @@
I am small file 84

View File

@ -0,0 +1 @@
I am small file 85

View File

@ -0,0 +1 @@
I am small file 86

View File

@ -0,0 +1 @@
I am small file 87

View File

@ -0,0 +1 @@
I am small file 88

View File

@ -0,0 +1 @@
I am small file 89

View File

@ -0,0 +1 @@
I am small file 9

View File

@ -0,0 +1 @@
I am small file 90

View File

@ -0,0 +1 @@
I am small file 91

Some files were not shown because too many files have changed in this diff Show More