From 0f9d35ada15aefa019c80e403411762142fe076e Mon Sep 17 00:00:00 2001 From: PThorpe92 Date: Thu, 12 Oct 2023 16:56:59 -0400 Subject: [PATCH 1/3] feat: add icons=always,auto,never. dont display icons in a tty|piped --- src/options/file_name.rs | 47 ++++++++++++++++++++++++++------- src/options/flags.rs | 3 ++- src/options/view.rs | 4 +-- src/output/file_name.rs | 35 +++++++++++++++--------- src/output/grid.rs | 12 ++++++--- src/output/grid_details.rs | 5 ++-- tests/cmd/icons_all.toml | 2 +- tests/cmd/long_icons_nix.toml | 2 +- tests/cmd/non_term_icons.stdout | 1 + tests/cmd/non_term_icons.toml | 2 ++ 10 files changed, 80 insertions(+), 33 deletions(-) create mode 100644 tests/cmd/non_term_icons.stdout create mode 100644 tests/cmd/non_term_icons.toml diff --git a/src/options/file_name.rs b/src/options/file_name.rs index c69fa7c77..a178025d1 100644 --- a/src/options/file_name.rs +++ b/src/options/file_name.rs @@ -2,10 +2,15 @@ use crate::options::parser::MatchedFlags; use crate::options::vars::{self, Vars}; use crate::options::{flags, NumberSource, OptionsError}; +use super::vars::EZA_ICON_SPACING; use crate::output::file_name::{Classify, EmbedHyperlinks, Options, QuoteStyle, ShowIcons}; impl Options { - pub fn deduce(matches: &MatchedFlags<'_>, vars: &V) -> Result { + pub fn deduce( + matches: &MatchedFlags<'_>, + vars: &V, + is_a_tty: bool, + ) -> Result { let classify = Classify::deduce(matches)?; let show_icons = ShowIcons::deduce(matches, vars)?; @@ -17,6 +22,7 @@ impl Options { show_icons, quote_style, embed_hyperlinks, + is_a_tty, }) } } @@ -35,24 +41,47 @@ impl Classify { impl ShowIcons { pub fn deduce(matches: &MatchedFlags<'_>, vars: &V) -> Result { - if matches.has(&flags::NO_ICONS)? || !matches.has(&flags::ICONS)? { - Ok(Self::Off) - } else if let Some(columns) = vars - .get_with_fallback(vars::EZA_ICON_SPACING, vars::EXA_ICON_SPACING) + enum AlwaysOrAuto { + Always, + Automatic, + } + + let mode_opt = matches.get(&flags::ICONS)?; + if matches.has(&flags::NO_ICONS)? || (!matches.has(&flags::ICONS)? && mode_opt.is_none()) { + return Ok(Self::Never); + } + + let mode = match mode_opt { + Some(word) => match word.to_str() { + Some("always") => AlwaysOrAuto::Always, + Some("auto" | "automatic") => AlwaysOrAuto::Automatic, + Some("never") => return Ok(Self::Never), + _ => return Err(OptionsError::BadArgument(&flags::COLOR, word.into())), + }, + None => AlwaysOrAuto::Automatic, + }; + + let width = if let Some(columns) = vars + .get_with_fallback(vars::EXA_ICON_SPACING, vars::EZA_ICON_SPACING) .and_then(|s| s.into_string().ok()) { match columns.parse() { - Ok(width) => Ok(Self::On(width)), + Ok(width) => width, Err(e) => { let source = NumberSource::Env( - vars.source(vars::EZA_ICON_SPACING, vars::EXA_ICON_SPACING) + vars.source(vars::EXA_ICON_SPACING, EZA_ICON_SPACING) .unwrap(), ); - Err(OptionsError::FailedParse(columns, source, e)) + return Err(OptionsError::FailedParse(columns, source, e)); } } } else { - Ok(Self::On(1)) + 1 + }; + + match mode { + AlwaysOrAuto::Always => Ok(Self::Always(width)), + AlwaysOrAuto::Automatic => Ok(Self::Automatic(width)), } } } diff --git a/src/options/flags.rs b/src/options/flags.rs index 175a309ed..d4a111f47 100644 --- a/src/options/flags.rs +++ b/src/options/flags.rs @@ -45,7 +45,8 @@ pub static BYTES: Arg = Arg { short: Some(b'B'), long: "bytes", takes_ pub static GROUP: Arg = Arg { short: Some(b'g'), long: "group", takes_value: TakesValue::Forbidden }; pub static NUMERIC: Arg = Arg { short: Some(b'n'), long: "numeric", takes_value: TakesValue::Forbidden }; pub static HEADER: Arg = Arg { short: Some(b'h'), long: "header", takes_value: TakesValue::Forbidden }; -pub static ICONS: Arg = Arg { short: None, long: "icons", takes_value: TakesValue::Forbidden }; +pub static ICONS: Arg = Arg { short: None, long: "icons", takes_value: TakesValue::Necessary(Some(ICONS_VALUES ))}; +const ICONS_VALUES: Values = &["always", "auto", "never"]; pub static INODE: Arg = Arg { short: Some(b'i'), long: "inode", takes_value: TakesValue::Forbidden }; pub static LINKS: Arg = Arg { short: Some(b'H'), long: "links", takes_value: TakesValue::Forbidden }; pub static MODIFIED: Arg = Arg { short: Some(b'm'), long: "modified", takes_value: TakesValue::Forbidden }; diff --git a/src/options/view.rs b/src/options/view.rs index 40ba52779..8617d9d66 100644 --- a/src/options/view.rs +++ b/src/options/view.rs @@ -10,9 +10,9 @@ use crate::output::{details, grid, Mode, TerminalWidth, View}; impl View { pub fn deduce(matches: &MatchedFlags<'_>, vars: &V) -> Result { let mode = Mode::deduce(matches, vars)?; - let width = TerminalWidth::deduce(matches, vars)?; - let file_style = FileStyle::deduce(matches, vars)?; let deref_links = matches.has(&flags::DEREF_LINKS)?; + let width = TerminalWidth::deduce(matches, vars)?; + let file_style = FileStyle::deduce(matches, vars, width.actual_terminal_width().is_some())?; Ok(Self { mode, width, diff --git a/src/output/file_name.rs b/src/output/file_name.rs index 11bc18913..edd88df4a 100644 --- a/src/output/file_name.rs +++ b/src/output/file_name.rs @@ -24,6 +24,9 @@ pub struct Options { /// Whether to make file names hyperlinks. pub embed_hyperlinks: EmbedHyperlinks, + + /// Whether we are in a console or redirecting the output + pub is_a_tty: bool, } impl Options { @@ -94,14 +97,17 @@ enum MountStyle { } /// Whether and how to show icons. -#[derive(PartialEq, Eq, Debug, Copy, Clone)] +#[derive(PartialEq, Debug, Copy, Clone)] pub enum ShowIcons { - /// Don’t show icons at all. - Off, + /// Display icons next to file names, with the given number of spaces between + /// the icon and the file name, even when output isn’t going to a terminal. + Always(u32), + + /// Same as Always, but only when output is going to a terminal, not otherwise. + Automatic(u32), - /// Show icons next to file names, with the given number of spaces between - /// the icon and the file name. - On(usize), + /// Never display them, even when output is going to a terminal. + Never, } /// Whether to embed hyperlinks. @@ -176,13 +182,17 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { pub fn paint(&self) -> TextCellContents { let mut bits = Vec::new(); - if let ShowIcons::On(spaces_count) = self.options.show_icons { + let spaces_count_opt = match self.options.show_icons { + ShowIcons::Always(spaces_count) => Some(spaces_count), + ShowIcons::Automatic(spaces_count) if self.options.is_a_tty => Some(spaces_count), + _ => None, + }; + + if let Some(spaces_count) = spaces_count_opt { let style = iconify_style(self.style()); let file_icon = icon_for_file(self.file).to_string(); - bits.push(style.paint(file_icon)); - - bits.push(style.paint(" ".repeat(spaces_count))); + bits.push(style.paint(" ".repeat(spaces_count as usize))); } if self.file.parent_dir.is_none() { @@ -217,11 +227,10 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> { if !target.name.is_empty() { let target_options = Options { classify: Classify::JustFilenames, - show_icons: ShowIcons::Off, - quote_style: QuoteStyle::QuoteSpaces, - + show_icons: ShowIcons::Never, embed_hyperlinks: EmbedHyperlinks::Off, + is_a_tty: self.options.is_a_tty, }; let target_name = FileName { diff --git a/src/output/grid.rs b/src/output/grid.rs index cd0d900e3..643ebc3dc 100644 --- a/src/output/grid.rs +++ b/src/output/grid.rs @@ -61,12 +61,16 @@ impl<'a> Render<'a> { filename.options.embed_hyperlinks, filename.options.show_icons, ) { - (EmbedHyperlinks::On, ShowIcons::On(spacing)) => { - filename.bare_width() + classification_width + 1 + spacing - } - (EmbedHyperlinks::On, ShowIcons::Off) => { + #[rustfmt::skip] + (EmbedHyperlinks::On, ShowIcons::Always(spacing)) + | (EmbedHyperlinks::On, ShowIcons::Automatic(spacing)) => filename.bare_width() + classification_width + 1 + (spacing as usize), + (EmbedHyperlinks::On, ShowIcons::Never) => { filename.bare_width() + classification_width } + (EmbedHyperlinks::Off, ShowIcons::Always(spacing)) + | (EmbedHyperlinks::Off, ShowIcons::Automatic(spacing)) => { + filename.bare_width() + 1 + (spacing as usize) + } (EmbedHyperlinks::Off, _) => *contents.width(), }; diff --git a/src/output/grid_details.rs b/src/output/grid_details.rs index a666eeaa4..22026e6ec 100644 --- a/src/output/grid_details.rs +++ b/src/output/grid_details.rs @@ -164,8 +164,9 @@ impl<'a> Render<'a> { let contents = filename.paint(); #[rustfmt::skip] let width = match (filename.options.embed_hyperlinks, filename.options.show_icons) { - (EmbedHyperlinks::On, ShowIcons::On(spacing)) => filename.bare_width() + 1 + spacing, - (EmbedHyperlinks::On, ShowIcons::Off) => filename.bare_width(), + (EmbedHyperlinks::On, ShowIcons::Automatic(spacing)) => filename.bare_width() + 1 + (spacing as usize), + (EmbedHyperlinks::On, ShowIcons::Always(spacing)) => filename.bare_width() + 1 + (spacing as usize), + (EmbedHyperlinks::On, ShowIcons::Never) => filename.bare_width(), (EmbedHyperlinks::Off, _) => *contents.width(), }; diff --git a/tests/cmd/icons_all.toml b/tests/cmd/icons_all.toml index 756c3233e..ad19254e9 100644 --- a/tests/cmd/icons_all.toml +++ b/tests/cmd/icons_all.toml @@ -1,2 +1,2 @@ bin.name = "eza" -args = "tests/itest --icons" +args = "tests/itest --icons=always" diff --git a/tests/cmd/long_icons_nix.toml b/tests/cmd/long_icons_nix.toml index b9a8ffcf9..a9011c69e 100644 --- a/tests/cmd/long_icons_nix.toml +++ b/tests/cmd/long_icons_nix.toml @@ -1,2 +1,2 @@ bin.name = "eza" -args = "tests/itest --long --icons" +args = "tests/itest --long --icons=auto" diff --git a/tests/cmd/non_term_icons.stdout b/tests/cmd/non_term_icons.stdout new file mode 100644 index 000000000..62319d1d3 --- /dev/null +++ b/tests/cmd/non_term_icons.stdout @@ -0,0 +1 @@ + a  b  c  d  e  exa  f  g  h  i  image.jpg.img.c.rs.log.png 󰕙 index.svg  j  k  l  m  n  o  p  q  vagrant diff --git a/tests/cmd/non_term_icons.toml b/tests/cmd/non_term_icons.toml new file mode 100644 index 000000000..c3737173a --- /dev/null +++ b/tests/cmd/non_term_icons.toml @@ -0,0 +1,2 @@ +bin.name = "eza" +args = "tests/itest --icons=auto" From b52bc1e14ddb3361f4d397b81bd332050a2ff20c Mon Sep 17 00:00:00 2001 From: PThorpe92 Date: Thu, 12 Oct 2023 17:13:07 -0400 Subject: [PATCH 2/3] fix: clippy lint --- src/output/grid.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/output/grid.rs b/src/output/grid.rs index 643ebc3dc..5f43f5f70 100644 --- a/src/output/grid.rs +++ b/src/output/grid.rs @@ -62,15 +62,15 @@ impl<'a> Render<'a> { filename.options.show_icons, ) { #[rustfmt::skip] - (EmbedHyperlinks::On, ShowIcons::Always(spacing)) - | (EmbedHyperlinks::On, ShowIcons::Automatic(spacing)) => filename.bare_width() + classification_width + 1 + (spacing as usize), + (EmbedHyperlinks::On, ShowIcons::Always(spacing) + | ShowIcons::Automatic(spacing)) => filename.bare_width() + classification_width + 1 + (spacing as usize), (EmbedHyperlinks::On, ShowIcons::Never) => { filename.bare_width() + classification_width } - (EmbedHyperlinks::Off, ShowIcons::Always(spacing)) - | (EmbedHyperlinks::Off, ShowIcons::Automatic(spacing)) => { - filename.bare_width() + 1 + (spacing as usize) - } + ( + EmbedHyperlinks::Off, + ShowIcons::Always(spacing) | ShowIcons::Automatic(spacing), + ) => filename.bare_width() + 1 + (spacing as usize), (EmbedHyperlinks::Off, _) => *contents.width(), }; From 39ab30add4c0f0abf43f67d621cce7398a0a9cf7 Mon Sep 17 00:00:00 2001 From: PThorpe92 Date: Thu, 12 Oct 2023 17:25:38 -0400 Subject: [PATCH 3/3] ci: adjust test case to icons=auto (no icons should show due to tty) --- tests/cmd/long_icons_nix.stdout | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/cmd/long_icons_nix.stdout b/tests/cmd/long_icons_nix.stdout index 1e8455454..cf70b8a2b 100644 --- a/tests/cmd/long_icons_nix.stdout +++ b/tests/cmd/long_icons_nix.stdout @@ -1,21 +1,21 @@ -.rw-r--r-- 0 nixbld 1 Jan 1970  a -.rw-r--r-- 0 nixbld 1 Jan 1970  b -.rw-r--r-- 0 nixbld 1 Jan 1970  c -.rw-r--r-- 0 nixbld 1 Jan 1970  d -.rw-r--r-- 0 nixbld 1 Jan 1970  e -drwxr-xr-x - nixbld 1 Jan 1970  exa -.rw-r--r-- 0 nixbld 1 Jan 1970  f -.rw-r--r-- 0 nixbld 1 Jan 1970  g -.rw-r--r-- 0 nixbld 1 Jan 1970  h -.rw-r--r-- 0 nixbld 1 Jan 1970  i -.rw-r--r-- 0 nixbld 1 Jan 1970  image.jpg.img.c.rs.log.png -.rw-r--r-- 19 nixbld 1 Jan 1970 󰕙 index.svg -.rw-r--r-- 0 nixbld 1 Jan 1970  j -.rw-r--r-- 0 nixbld 1 Jan 1970  k -.rw-r--r-- 0 nixbld 1 Jan 1970  l -.rw-r--r-- 0 nixbld 1 Jan 1970  m -.rw-r--r-- 0 nixbld 1 Jan 1970  n -.rw-r--r-- 0 nixbld 1 Jan 1970  o -.rw-r--r-- 0 nixbld 1 Jan 1970  p -.rw-r--r-- 0 nixbld 1 Jan 1970  q -drwxr-xr-x - nixbld 1 Jan 1970  vagrant +.rw-r--r-- 0 nixbld 1 Jan 1970 a +.rw-r--r-- 0 nixbld 1 Jan 1970 b +.rw-r--r-- 0 nixbld 1 Jan 1970 c +.rw-r--r-- 0 nixbld 1 Jan 1970 d +.rw-r--r-- 0 nixbld 1 Jan 1970 e +drwxr-xr-x - nixbld 1 Jan 1970 exa +.rw-r--r-- 0 nixbld 1 Jan 1970 f +.rw-r--r-- 0 nixbld 1 Jan 1970 g +.rw-r--r-- 0 nixbld 1 Jan 1970 h +.rw-r--r-- 0 nixbld 1 Jan 1970 i +.rw-r--r-- 0 nixbld 1 Jan 1970 image.jpg.img.c.rs.log.png +.rw-r--r-- 19 nixbld 1 Jan 1970 index.svg +.rw-r--r-- 0 nixbld 1 Jan 1970 j +.rw-r--r-- 0 nixbld 1 Jan 1970 k +.rw-r--r-- 0 nixbld 1 Jan 1970 l +.rw-r--r-- 0 nixbld 1 Jan 1970 m +.rw-r--r-- 0 nixbld 1 Jan 1970 n +.rw-r--r-- 0 nixbld 1 Jan 1970 o +.rw-r--r-- 0 nixbld 1 Jan 1970 p +.rw-r--r-- 0 nixbld 1 Jan 1970 q +drwxr-xr-x - nixbld 1 Jan 1970 vagrant