@@ -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;
7+use bytesize::ByteSize;
7use console::AnsiCodeIterator;
9use console::AnsiCodeIterator;
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> {
256+ fn print_header_component_indent(&mut self, handle: &mut dyn Write) -> std::io::Result<()> {
257+ if self.config.style_components.grid() {
261+ " ".repeat(self.panel_width),
264+ .paint(if self.panel_width > 0 { "│ " } else { "" }),
267+ write!(handle, "{}", " ".repeat(self.panel_width))
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(());
290− if self.config.style_components.grid() {
291− self.print_horizontal_line(handle, '┬')?;
296− " ".repeat(self.panel_width),
299− .paint(if self.panel_width > 0 { "│ " } 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() {
306− write!(handle, "{}", " ".repeat(self.panel_width))?;
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> {
317 let description = &input.description;
316 let description = &input.description;
317+ let metadata = &input.metadata;
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> = [
323+ StyleComponent::HeaderFilename,
324+ self.config.style_components.header_filename(),
327+ StyleComponent::HeaderFilesize,
328+ self.config.style_components.header_filesize(),
332+ .filter(|(_, is_enabled)| *is_enabled)
333+ .map(|(component, _)| *component)
336+ // Print the cornering grid before the first header component
337+ if self.config.style_components.grid() {
338+ self.print_horizontal_line(handle, '┬')?;
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() {
319− writeln!(
346+ header_components.iter().try_for_each(|component| {
347+ self.print_header_component_indent(handle)?;
350+ StyleComponent::HeaderFilename => writeln!(
321− "{}{}{}",
352+ "{}{}{}",
322− description
353+ description
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()),
361+ StyleComponent::HeaderFilesize => {
362+ let bsize = metadata
364+ .map(|s| format!("{}", ByteSize(s)))
365+ .unwrap_or_else(|| "-".into());
366+ writeln!(handle, "Size: {}", self.colors.header_value.paint(bsize))
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 {
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(),