on master help sign in
Add new `--style` called `header-filesize` and display it by default (#1988)
312c8efMahdi Dibaiee
CHANGELOG.md+2
@@ -2,6 +2,8 @@
2
2
3## Features
3## Features
4
4
5+- New style component `header-filesize` to show size of the displayed file in the header. See #1988 (@mdibaiee)
6+
5## Bugfixes
7## Bugfixes
6
8
7## Other
9## Other
Cargo.lock+7
@@ -82,6 +82,7 @@ dependencies = [
82 "atty",
82 "atty",
83 "bincode",
83 "bincode",
84 "bugreport",
84 "bugreport",
85+ "bytesize",
85 "clap",
86 "clap",
86 "clircle",
87 "clircle",
87 "console",
88 "console",
@@ -169,6 +170,12 @@ version = "1.7.3"
169source = "registry+https://github.com/rust-lang/crates.io-index"
170source = "registry+https://github.com/rust-lang/crates.io-index"
170checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f"
171checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f"
171
172
173+[[package]]
174+name = "bytesize"
175+version = "1.1.0"
176+source = "registry+https://github.com/rust-lang/crates.io-index"
177+checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70"
178+
172[[package]]
179[[package]]
173name = "cc"
180name = "cc"
174version = "1.0.72"
181version = "1.0.72"
Cargo.toml+1
@@ -65,6 +65,7 @@ dirs-next = { version = "2.0.0", optional = true }
65grep-cli = { version = "0.1.6", optional = true }
65grep-cli = { version = "0.1.6", optional = true }
66regex = { version = "1.0", optional = true }
66regex = { version = "1.0", optional = true }
67walkdir = { version = "2.0", optional = true }
67walkdir = { version = "2.0", optional = true }
68+bytesize = { version = "1.1.0" }
68
69
69[dependencies.git2]
70[dependencies.git2]
70version = "0.13"
71version = "0.13"
src/bin/bat/clap_app.rs+15−5
@@ -396,11 +396,19 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
396 .validator(|val| {
396 .validator(|val| {
397 let mut invalid_vals = val.split(',').filter(|style| {
397 let mut invalid_vals = val.split(',').filter(|style| {
398 !&[
398 !&[
399− "auto", "full", "plain", "header", "grid", "rule", "numbers", "snip",
399+ "auto",
400+ "full",
401+ "plain",
402+ "header",
403+ "header-filename",
404+ "header-filesize",
405+ "grid",
406+ "rule",
407+ "numbers",
408+ "snip",
400 #[cfg(feature = "git")]
409 #[cfg(feature = "git")]
401− "changes",
410+ "changes",
402− ]
403− .contains(style)
411+ ].contains(style)
404 });
412 });
405
413
406 if let Some(invalid) = invalid_vals.next() {
414 if let Some(invalid) = invalid_vals.next() {
@@ -426,7 +434,9 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> {
426 * auto: same as 'full', unless the output is piped.\n \
434 * auto: same as 'full', unless the output is piped.\n \
427 * plain: disables all available components.\n \
435 * plain: disables all available components.\n \
428 * changes: show Git modification markers.\n \
436 * changes: show Git modification markers.\n \
437+ * header: alias for 'header-filename'.\n \
429− * header: show filenames before the content.\n \
438+ * header-filename: show filenames before the content.\n \
439+ * header-filesize: show file sizes before the content.\n \
430 * grid: vertical/horizontal lines to separate side bar\n \
440 * grid: vertical/horizontal lines to separate side bar\n \
431 and the header from the content.\n \
441 and the header from the content.\n \
432 * rule: horizontal lines to delimit files.\n \
442 * rule: horizontal lines to delimit files.\n \
src/input.rs+8−1
@@ -1,4 +1,5 @@
1use std::convert::TryFrom;
1use std::convert::TryFrom;
2+use std::fs;
2use std::fs::File;
3use std::fs::File;
3use std::io::{self, BufRead, BufReader, Read};
4use std::io::{self, BufRead, BufReader, Read};
4use std::path::{Path, PathBuf};
5use std::path::{Path, PathBuf};
@@ -87,6 +88,7 @@ impl<'a> InputKind<'a> {
87#[derive(Clone, Default)]
88#[derive(Clone, Default)]
88pub(crate) struct InputMetadata {
89pub(crate) struct InputMetadata {
89 pub(crate) user_provided_name: Option<PathBuf>,
90 pub(crate) user_provided_name: Option<PathBuf>,
91+ pub(crate) size: Option<u64>,
90}
92}
91
93
92pub struct Input<'a> {
94pub struct Input<'a> {
@@ -130,9 +132,14 @@ impl<'a> Input<'a> {
130
132
131 fn _ordinary_file(path: &Path) -> Self {
133 fn _ordinary_file(path: &Path) -> Self {
132 let kind = InputKind::OrdinaryFile(path.to_path_buf());
134 let kind = InputKind::OrdinaryFile(path.to_path_buf());
135+ let metadata = InputMetadata {
136+ size: fs::metadata(path).map(|m| m.len()).ok(),
137+ ..InputMetadata::default()
138+ };
139+
133 Input {
140 Input {
134 description: kind.description(),
141 description: kind.description(),
135− metadata: InputMetadata::default(),
142+ metadata,
136 kind,
143 kind,
137 }
144 }
138 }
145 }
src/printer.rs+73−31
@@ -4,6 +4,8 @@ use std::vec::Vec;
4use ansi_term::Colour::{Fixed, Green, Red, Yellow};
4use ansi_term::Colour::{Fixed, Green, Red, Yellow};
5use ansi_term::Style;
5use ansi_term::Style;
6
6
7+use bytesize::ByteSize;
8+
7use console::AnsiCodeIterator;
9use console::AnsiCodeIterator;
8
10
9use syntect::easy::HighlightLines;
11use syntect::easy::HighlightLines;
@@ -29,6 +31,7 @@ use crate::error::*;
29use crate::input::OpenedInput;
31use crate::input::OpenedInput;
30use crate::line_range::RangeCheckResult;
32use crate::line_range::RangeCheckResult;
31use crate::preprocessor::{expand_tabs, replace_nonprintable};
33use crate::preprocessor::{expand_tabs, replace_nonprintable};
34+use crate::style::StyleComponent;
32use crate::terminal::{as_terminal_escaped, to_ansi_color};
35use crate::terminal::{as_terminal_escaped, to_ansi_color};
33use crate::vscreen::AnsiStyle;
36use crate::vscreen::AnsiStyle;
34use crate::wrapping::WrappingMode;
37use crate::wrapping::WrappingMode;
@@ -250,6 +253,21 @@ impl<'a> InteractivePrinter<'a> {
250 }
253 }
251 }
254 }
252
255
256+ fn print_header_component_indent(&mut self, handle: &mut dyn Write) -> std::io::Result<()> {
257+ if self.config.style_components.grid() {
258+ write!(
259+ handle,
260+ "{}{}",
261+ " ".repeat(self.panel_width),
262+ self.colors
263+ .grid
264+ .paint(if self.panel_width > 0 { "│ " } else { "" }),
265+ )
266+ } else {
267+ write!(handle, "{}", " ".repeat(self.panel_width))
268+ }
269+ }
270+
253 fn preprocess(&self, text: &str, cursor: &mut usize) -> String {
271 fn preprocess(&self, text: &str, cursor: &mut usize) -> String {
254 if self.config.tab_width > 0 {
272 if self.config.tab_width > 0 {
255 return expand_tabs(text, self.config.tab_width, cursor);
273 return expand_tabs(text, self.config.tab_width, cursor);
@@ -287,25 +305,6 @@ impl<'a> Printer for InteractivePrinter<'a> {
287 return Ok(());
305 return Ok(());
288 }
306 }
289
307
290− if self.config.style_components.grid() {
291− self.print_horizontal_line(handle, '┬')?;
292−
293− write!(
294− handle,
295− "{}{}",
296− " ".repeat(self.panel_width),
297− self.colors
298− .grid
299− .paint(if self.panel_width > 0 { "│ " } else { "" }),
300− )?;
301− } else {
302− // Only pad space between files, if we haven't already drawn a horizontal rule
303− if add_header_padding && !self.config.style_components.rule() {
304− writeln!(handle)?;
305− }
306− write!(handle, "{}", " ".repeat(self.panel_width))?;
307− }
308−
309 let mode = match self.content_type {
308 let mode = match self.content_type {
310 Some(ContentType::BINARY) => " <BINARY>",
309 Some(ContentType::BINARY) => " <BINARY>",
311 Some(ContentType::UTF_16LE) => " <UTF-16LE>",
310 Some(ContentType::UTF_16LE) => " <UTF-16LE>",
@@ -315,17 +314,60 @@ impl<'a> Printer for InteractivePrinter<'a> {
315 };
314 };
316
315
317 let description = &input.description;
316 let description = &input.description;
317+ let metadata = &input.metadata;
318+
319+ // We use this iterator to have a deterministic order for
320+ // header components. HashSet has arbitrary order, but Vec is ordered.
321+ let header_components: Vec<StyleComponent> = [
322+ (
323+ StyleComponent::HeaderFilename,
324+ self.config.style_components.header_filename(),
325+ ),
326+ (
327+ StyleComponent::HeaderFilesize,
328+ self.config.style_components.header_filesize(),
329+ ),
330+ ]
331+ .iter()
332+ .filter(|(_, is_enabled)| *is_enabled)
333+ .map(|(component, _)| *component)
334+ .collect();
335+
336+ // Print the cornering grid before the first header component
337+ if self.config.style_components.grid() {
338+ self.print_horizontal_line(handle, '┬')?;
339+ } else {
340+ // Only pad space between files, if we haven't already drawn a horizontal rule
341+ if add_header_padding && !self.config.style_components.rule() {
342+ writeln!(handle)?;
343+ }
344+ }
318
345
319− writeln!(
346+ header_components.iter().try_for_each(|component| {
347+ self.print_header_component_indent(handle)?;
348+
349+ match component {
350+ StyleComponent::HeaderFilename => writeln!(
320− handle,
351+ handle,
321− "{}{}{}",
352+ "{}{}{}",
322− description
353+ description
323− .kind()
354+ .kind()
324− .map(|kind| format!("{}: ", kind))
355+ .map(|kind| format!("{}: ", kind))
325− .unwrap_or_else(|| "".into()),
356+ .unwrap_or_else(|| "".into()),
326− self.colors.filename.paint(description.title()),
357+ self.colors.header_value.paint(description.title()),
327− mode
358+ mode
359+ ),
360+
361+ StyleComponent::HeaderFilesize => {
362+ let bsize = metadata
363+ .size
364+ .map(|s| format!("{}", ByteSize(s)))
365+ .unwrap_or_else(|| "-".into());
366+ writeln!(handle, "Size: {}", self.colors.header_value.paint(bsize))
367+ }
368+ _ => Ok(()),
369+ }
328− )?;
370+ })?;
329
371
330 if self.config.style_components.grid() {
372 if self.config.style_components.grid() {
331 if self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable {
373 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;
617pub struct Colors {
659pub struct Colors {
618 pub grid: Style,
660 pub grid: Style,
619 pub rule: Style,
661 pub rule: Style,
620− pub filename: Style,
662+ pub header_value: Style,
621 pub git_added: Style,
663 pub git_added: Style,
622 pub git_removed: Style,
664 pub git_removed: Style,
623 pub git_modified: Style,
665 pub git_modified: Style,
@@ -646,7 +688,7 @@ impl Colors {
646 Colors {
688 Colors {
647 grid: gutter_style,
689 grid: gutter_style,
648 rule: gutter_style,
690 rule: gutter_style,
649− filename: Style::new().bold(),
691+ header_value: Style::new().bold(),
650 git_added: Green.normal(),
692 git_added: Green.normal(),
651 git_removed: Red.normal(),
693 git_removed: Red.normal(),
652 git_modified: Yellow.normal(),
694 git_modified: Yellow.normal(),
src/style.rs+19−3
@@ -3,6 +3,7 @@ use std::str::FromStr;
3
3
4use crate::error::*;
4use crate::error::*;
5
5
6+#[non_exhaustive]
6#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
7#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
7pub enum StyleComponent {
8pub enum StyleComponent {
8 Auto,
9 Auto,
@@ -11,6 +12,8 @@ pub enum StyleComponent {
11 Grid,
12 Grid,
12 Rule,
13 Rule,
13 Header,
14 Header,
15+ HeaderFilename,
16+ HeaderFilesize,
14 LineNumbers,
17 LineNumbers,
15 Snip,
18 Snip,
16 Full,
19 Full,
@@ -31,14 +34,17 @@ impl StyleComponent {
31 StyleComponent::Changes => &[StyleComponent::Changes],
34 StyleComponent::Changes => &[StyleComponent::Changes],
32 StyleComponent::Grid => &[StyleComponent::Grid],
35 StyleComponent::Grid => &[StyleComponent::Grid],
33 StyleComponent::Rule => &[StyleComponent::Rule],
36 StyleComponent::Rule => &[StyleComponent::Rule],
34− StyleComponent::Header => &[StyleComponent::Header],
37+ StyleComponent::Header => &[StyleComponent::HeaderFilename],
38+ StyleComponent::HeaderFilename => &[StyleComponent::HeaderFilename],
39+ StyleComponent::HeaderFilesize => &[StyleComponent::HeaderFilesize],
35 StyleComponent::LineNumbers => &[StyleComponent::LineNumbers],
40 StyleComponent::LineNumbers => &[StyleComponent::LineNumbers],
36 StyleComponent::Snip => &[StyleComponent::Snip],
41 StyleComponent::Snip => &[StyleComponent::Snip],
37 StyleComponent::Full => &[
42 StyleComponent::Full => &[
38 #[cfg(feature = "git")]
43 #[cfg(feature = "git")]
39 StyleComponent::Changes,
44 StyleComponent::Changes,
40 StyleComponent::Grid,
45 StyleComponent::Grid,
41− StyleComponent::Header,
46+ StyleComponent::HeaderFilename,
47+ StyleComponent::HeaderFilesize,
42 StyleComponent::LineNumbers,
48 StyleComponent::LineNumbers,
43 StyleComponent::Snip,
49 StyleComponent::Snip,
44 ],
50 ],
@@ -58,6 +64,8 @@ impl FromStr for StyleComponent {
58 "grid" => Ok(StyleComponent::Grid),
64 "grid" => Ok(StyleComponent::Grid),
59 "rule" => Ok(StyleComponent::Rule),
65 "rule" => Ok(StyleComponent::Rule),
60 "header" => Ok(StyleComponent::Header),
66 "header" => Ok(StyleComponent::Header),
67+ "header-filename" => Ok(StyleComponent::HeaderFilename),
68+ "header-filesize" => Ok(StyleComponent::HeaderFilesize),
61 "numbers" => Ok(StyleComponent::LineNumbers),
69 "numbers" => Ok(StyleComponent::LineNumbers),
62 "snip" => Ok(StyleComponent::Snip),
70 "snip" => Ok(StyleComponent::Snip),
63 "full" => Ok(StyleComponent::Full),
71 "full" => Ok(StyleComponent::Full),
@@ -89,7 +97,15 @@ impl StyleComponents {
89 }
97 }
90
98
91 pub fn header(&self) -> bool {
99 pub fn header(&self) -> bool {
100+ self.header_filename() || self.header_filesize()
101+ }
102+
103+ pub fn header_filename(&self) -> bool {
92− self.0.contains(&StyleComponent::Header)
104+ self.0.contains(&StyleComponent::HeaderFilename)
105+ }
106+
107+ pub fn header_filesize(&self) -> bool {
108+ self.0.contains(&StyleComponent::HeaderFilesize)
93 }
109 }
94
110
95 pub fn numbers(&self) -> bool {
111 pub fn numbers(&self) -> bool {
tests/benchmarks/many-small-files/small-file-0.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 0
tests/benchmarks/many-small-files/small-file-1.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 1
tests/benchmarks/many-small-files/small-file-10.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 10
tests/benchmarks/many-small-files/small-file-100.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 100
tests/benchmarks/many-small-files/small-file-11.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 11
tests/benchmarks/many-small-files/small-file-12.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 12
tests/benchmarks/many-small-files/small-file-13.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 13
tests/benchmarks/many-small-files/small-file-14.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 14
tests/benchmarks/many-small-files/small-file-15.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 15
tests/benchmarks/many-small-files/small-file-16.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 16
tests/benchmarks/many-small-files/small-file-17.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 17
tests/benchmarks/many-small-files/small-file-18.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 18
tests/benchmarks/many-small-files/small-file-19.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 19
tests/benchmarks/many-small-files/small-file-2.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 2
tests/benchmarks/many-small-files/small-file-20.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 20
tests/benchmarks/many-small-files/small-file-21.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 21
tests/benchmarks/many-small-files/small-file-22.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 22
tests/benchmarks/many-small-files/small-file-23.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 23
tests/benchmarks/many-small-files/small-file-24.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 24
tests/benchmarks/many-small-files/small-file-25.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 25
tests/benchmarks/many-small-files/small-file-26.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 26
tests/benchmarks/many-small-files/small-file-27.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 27
tests/benchmarks/many-small-files/small-file-28.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 28
tests/benchmarks/many-small-files/small-file-29.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 29
tests/benchmarks/many-small-files/small-file-3.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 3
tests/benchmarks/many-small-files/small-file-30.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 30
tests/benchmarks/many-small-files/small-file-31.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 31
tests/benchmarks/many-small-files/small-file-32.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 32
tests/benchmarks/many-small-files/small-file-33.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 33
tests/benchmarks/many-small-files/small-file-34.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 34
tests/benchmarks/many-small-files/small-file-35.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 35
tests/benchmarks/many-small-files/small-file-36.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 36
tests/benchmarks/many-small-files/small-file-37.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 37
tests/benchmarks/many-small-files/small-file-38.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 38
tests/benchmarks/many-small-files/small-file-39.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 39
tests/benchmarks/many-small-files/small-file-4.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 4
tests/benchmarks/many-small-files/small-file-40.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 40
tests/benchmarks/many-small-files/small-file-41.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 41
tests/benchmarks/many-small-files/small-file-42.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 42
tests/benchmarks/many-small-files/small-file-43.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 43
tests/benchmarks/many-small-files/small-file-44.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 44
tests/benchmarks/many-small-files/small-file-45.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 45
tests/benchmarks/many-small-files/small-file-46.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 46
tests/benchmarks/many-small-files/small-file-47.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 47
tests/benchmarks/many-small-files/small-file-48.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 48
tests/benchmarks/many-small-files/small-file-49.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 49
tests/benchmarks/many-small-files/small-file-5.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 5
tests/benchmarks/many-small-files/small-file-50.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 50
tests/benchmarks/many-small-files/small-file-51.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 51
tests/benchmarks/many-small-files/small-file-52.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 52
tests/benchmarks/many-small-files/small-file-53.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 53
tests/benchmarks/many-small-files/small-file-54.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 54
tests/benchmarks/many-small-files/small-file-55.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 55
tests/benchmarks/many-small-files/small-file-56.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 56
tests/benchmarks/many-small-files/small-file-57.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 57
tests/benchmarks/many-small-files/small-file-58.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 58
tests/benchmarks/many-small-files/small-file-59.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 59
tests/benchmarks/many-small-files/small-file-6.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 6
tests/benchmarks/many-small-files/small-file-60.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 60
tests/benchmarks/many-small-files/small-file-61.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 61
tests/benchmarks/many-small-files/small-file-62.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 62
tests/benchmarks/many-small-files/small-file-63.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 63
tests/benchmarks/many-small-files/small-file-64.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 64
tests/benchmarks/many-small-files/small-file-65.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 65
tests/benchmarks/many-small-files/small-file-66.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 66
tests/benchmarks/many-small-files/small-file-67.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 67
tests/benchmarks/many-small-files/small-file-68.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 68
tests/benchmarks/many-small-files/small-file-69.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 69
tests/benchmarks/many-small-files/small-file-7.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 7
tests/benchmarks/many-small-files/small-file-70.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 70
tests/benchmarks/many-small-files/small-file-71.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 71
tests/benchmarks/many-small-files/small-file-72.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 72
tests/benchmarks/many-small-files/small-file-73.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 73
tests/benchmarks/many-small-files/small-file-74.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 74
tests/benchmarks/many-small-files/small-file-75.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 75
tests/benchmarks/many-small-files/small-file-76.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 76
tests/benchmarks/many-small-files/small-file-77.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 77
tests/benchmarks/many-small-files/small-file-78.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 78
tests/benchmarks/many-small-files/small-file-79.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 79
tests/benchmarks/many-small-files/small-file-8.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 8
tests/benchmarks/many-small-files/small-file-80.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 80
tests/benchmarks/many-small-files/small-file-81.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 81
tests/benchmarks/many-small-files/small-file-82.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 82
tests/benchmarks/many-small-files/small-file-83.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 83
tests/benchmarks/many-small-files/small-file-84.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 84
tests/benchmarks/many-small-files/small-file-85.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 85
tests/benchmarks/many-small-files/small-file-86.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 86
tests/benchmarks/many-small-files/small-file-87.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 87
tests/benchmarks/many-small-files/small-file-88.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 88
tests/benchmarks/many-small-files/small-file-89.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 89
tests/benchmarks/many-small-files/small-file-9.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 9
tests/benchmarks/many-small-files/small-file-90.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 90
tests/benchmarks/many-small-files/small-file-91.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 91
tests/benchmarks/many-small-files/small-file-92.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 92
tests/benchmarks/many-small-files/small-file-93.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 93
tests/benchmarks/many-small-files/small-file-94.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 94
tests/benchmarks/many-small-files/small-file-95.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 95
tests/benchmarks/many-small-files/small-file-96.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 96
tests/benchmarks/many-small-files/small-file-97.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 97
tests/benchmarks/many-small-files/small-file-98.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 98
tests/benchmarks/many-small-files/small-file-99.txtnew file+1
@@ -0,0 +1 @@
1+I am small file 99
tests/benchmarks/run-benchmarks.sh+10
@@ -136,3 +136,13 @@ for wrap in character never; do
136 cat "$RESULT_DIR/syntax-highlighting-speed-${filename}.md" >> "$REPORT"
136 cat "$RESULT_DIR/syntax-highlighting-speed-${filename}.md" >> "$REPORT"
137 done
137 done
138done
138done
139+
140+
141+heading "Many small files speed (overhead of metadata)"
142+hyperfine \
143+ "$(printf "%q" "$BAT") --no-config --language=txt --style=plain many-small-files/*.txt" \
144+ --command-name 'bat … --language=txt *.txt' \
145+ --warmup "$WARMUP_COUNT" \
146+ --export-markdown "$RESULT_DIR/many-small-files-speed.md" \
147+ --export-json "$RESULT_DIR/many-small-files-speed.json"
148+cat "$RESULT_DIR/many-small-files-speed.md" >> "$REPORT"
tests/integration_tests.rs+65−2
@@ -919,7 +919,7 @@ fn empty_file_leads_to_empty_output_with_rule_enabled() {
919}
919}
920
920
921#[test]
921#[test]
922−fn filename_basic() {
922+fn header_basic() {
923 bat()
923 bat()
924 .arg("test.txt")
924 .arg("test.txt")
925 .arg("--decorations=always")
925 .arg("--decorations=always")
@@ -933,7 +933,21 @@ fn filename_basic() {
933}
933}
934
934
935#[test]
935#[test]
936−fn filename_binary() {
936+fn header_full_basic() {
937+ bat()
938+ .arg("test.txt")
939+ .arg("--decorations=always")
940+ .arg("--style=header-filename,header-filesize")
941+ .arg("-r=0:0")
942+ .arg("--file-name=foo")
943+ .assert()
944+ .success()
945+ .stdout("File: foo\nSize: 12 B\n")
946+ .stderr("");
947+}
948+
949+#[test]
950+fn header_binary() {
937 bat()
951 bat()
938 .arg("test.binary")
952 .arg("test.binary")
939 .arg("--decorations=always")
953 .arg("--decorations=always")
@@ -946,6 +960,20 @@ fn filename_binary() {
946 .stderr("");
960 .stderr("");
947}
961}
948
962
963+#[test]
964+fn header_full_binary() {
965+ bat()
966+ .arg("test.binary")
967+ .arg("--decorations=always")
968+ .arg("--style=header-filename,header-filesize")
969+ .arg("-r=0:0")
970+ .arg("--file-name=foo")
971+ .assert()
972+ .success()
973+ .stdout("File: foo <BINARY>\nSize: 4 B\n")
974+ .stderr("");
975+}
976+
949#[test]
977#[test]
950fn filename_stdin() {
978fn filename_stdin() {
951 bat()
979 bat()
@@ -1016,6 +1044,18 @@ fn header_padding() {
1016 .stderr("");
1044 .stderr("");
1017}
1045}
1018
1046
1047+#[test]
1048+fn header_full_padding() {
1049+ bat()
1050+ .arg("--decorations=always")
1051+ .arg("--style=header-filename,header-filesize")
1052+ .arg("test.txt")
1053+ .arg("single-line.txt")
1054+ .assert()
1055+ .stdout("File: test.txt\nSize: 12 B\nhello world\n\nFile: single-line.txt\nSize: 11 B\nSingle Line\n")
1056+ .stderr("");
1057+}
1058+
1019#[test]
1059#[test]
1020fn header_padding_rule() {
1060fn header_padding_rule() {
1021 bat()
1061 bat()
@@ -1036,6 +1076,28 @@ Single Line
1036 .stderr("");
1076 .stderr("");
1037}
1077}
1038
1078
1079+#[test]
1080+fn header_full_padding_rule() {
1081+ bat()
1082+ .arg("--decorations=always")
1083+ .arg("--style=header-filename,header-filesize,rule")
1084+ .arg("--terminal-width=80")
1085+ .arg("test.txt")
1086+ .arg("single-line.txt")
1087+ .assert()
1088+ .stdout(
1089+ "File: test.txt
1090+Size: 12 B
1091+hello world
1092+────────────────────────────────────────────────────────────────────────────────
1093+File: single-line.txt
1094+Size: 11 B
1095+Single Line
1096+",
1097+ )
1098+ .stderr("");
1099+}
1100+
1039#[test]
1101#[test]
1040fn grid_overrides_rule() {
1102fn grid_overrides_rule() {
1041 bat()
1103 bat()
@@ -1219,6 +1281,7 @@ fn grid_for_file_without_newline() {
1219 "\
1281 "\
1220───────┬────────────────────────────────────────────────────────────────────────
1282───────┬────────────────────────────────────────────────────────────────────────
1221 │ File: single-line.txt
1283 │ File: single-line.txt
1284+ │ Size: 11 B
1222───────┼────────────────────────────────────────────────────────────────────────
1285───────┼────────────────────────────────────────────────────────────────────────
1223 1 │ Single Line
1286 1 │ Single Line
1224───────┴────────────────────────────────────────────────────────────────────────
1287───────┴────────────────────────────────────────────────────────────────────────
tests/snapshots/output/full.snapshot.txt+1
@@ -1,5 +1,6 @@
1───────┬────────────────────────────────────────────────────────────────────────
1───────┬────────────────────────────────────────────────────────────────────────
2 │ File: sample.rs
2 │ File: sample.rs
3+ │ Size: 533 B
3───────┼────────────────────────────────────────────────────────────────────────
4───────┼────────────────────────────────────────────────────────────────────────
4 1 + │ /// A rectangle. First line is changed to prevent a regression of #1869
5 1 + │ /// A rectangle. First line is changed to prevent a regression of #1869
5 2 │ struct Rectangle {
6 2 │ struct Rectangle {