Jelajahi Sumber

feat(flags): Add --absolute flag

This feature allows to display the full path of files and directories
when passing the --absolute flag.
The flag also allows to only print the absolute path of files or
directories.

Resolves #726
Tamino Bauknecht 2 tahun lalu
induk
melakukan
084ed33a35
7 mengubah file dengan 65 tambahan dan 3 penghapusan
  1. 7 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 1 0
      README.md
  4. 20 1
      src/options/file_name.rs
  5. 3 1
      src/options/flags.rs
  6. 1 0
      src/options/help.rs
  7. 32 1
      src/output/file_name.rs

+ 7 - 0
Cargo.lock

@@ -391,6 +391,7 @@ dependencies = [
  "number_prefix",
  "once_cell",
  "palette",
+ "path-clean",
  "percent-encoding",
  "phf",
  "plist",
@@ -767,6 +768,12 @@ dependencies = [
  "thiserror",
 ]
 
+[[package]]
+name = "path-clean"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef"
+
 [[package]]
 name = "percent-encoding"
 version = "2.3.1"

+ 1 - 0
Cargo.toml

@@ -78,6 +78,7 @@ libc = "0.2"
 locale = "0.2"
 log = "0.4"
 natord = "1.0"
+path-clean = "1.0.1"
 number_prefix = "0.4"
 palette = { version = "0.7.5", default-features = false, features = ["std"] }
 once_cell = "1.19.0"

+ 1 - 0
README.md

@@ -94,6 +94,7 @@ eza’s options are almost, but not quite, entirely unlike `ls`’s.
 - **--color-scale-mode=(mode)**: use gradient or fixed colors in --color-scale. valid options are `fixed` or `gradient`
 - **--icons=(when)**: when to display icons (always, auto, never)
 - **--hyperlink**: display entries as hyperlinks
+- **--absolute=(mode)**: display entries with their absolute path (on, follow, off)
 - **-w**, **--width=(columns)**: set screen width in columns
 
 ### Filtering options

+ 20 - 1
src/options/file_name.rs

@@ -2,7 +2,9 @@ use crate::options::parser::MatchedFlags;
 use crate::options::vars::{self, Vars};
 use crate::options::{flags, NumberSource, OptionsError};
 
-use crate::output::file_name::{Classify, EmbedHyperlinks, Options, QuoteStyle, ShowIcons};
+use crate::output::file_name::{
+    Absolute, Classify, EmbedHyperlinks, Options, QuoteStyle, ShowIcons,
+};
 
 impl Options {
     pub fn deduce<V: Vars>(
@@ -16,11 +18,14 @@ impl Options {
         let quote_style = QuoteStyle::deduce(matches)?;
         let embed_hyperlinks = EmbedHyperlinks::deduce(matches)?;
 
+        let absolute = Absolute::deduce(matches)?;
+
         Ok(Self {
             classify,
             show_icons,
             quote_style,
             embed_hyperlinks,
+            absolute,
             is_a_tty,
         })
     }
@@ -113,3 +118,17 @@ impl EmbedHyperlinks {
         }
     }
 }
+
+impl Absolute {
+    fn deduce(matches: &MatchedFlags<'_>) -> Result<Self, OptionsError> {
+        match matches.get(&flags::ABSOLUTE)? {
+            Some(word) => match word.to_str() {
+                Some("on" | "yes") => Ok(Self::On),
+                Some("follow") => Ok(Self::Follow),
+                Some("off" | "no") | None => Ok(Self::Off),
+                _ => Err(OptionsError::BadArgument(&flags::ABSOLUTE, word.into())),
+            },
+            None => Ok(Self::Off),
+        }
+    }
+}

+ 3 - 1
src/options/flags.rs

@@ -15,6 +15,8 @@ pub static CLASSIFY:    Arg = Arg { short: Some(b'F'), long: "classify",    take
 pub static DEREF_LINKS: Arg = Arg { short: Some(b'X'), long: "dereference", takes_value: TakesValue::Forbidden };
 pub static WIDTH:       Arg = Arg { short: Some(b'w'), long: "width",       takes_value: TakesValue::Necessary(None) };
 pub static NO_QUOTES:   Arg = Arg { short: None,       long: "no-quotes",   takes_value: TakesValue::Forbidden };
+pub static ABSOLUTE:    Arg = Arg { short: None,       long: "absolute",    takes_value: TakesValue::Optional(Some(ABSOLUTE_MODES), "on") };
+const ABSOLUTE_MODES: &[&str] = &["on", "follow", "off"];
 
 pub static COLOR:  Arg = Arg { short: None, long: "color",  takes_value: TakesValue::Optional(Some(WHEN), "auto") };
 pub static COLOUR: Arg = Arg { short: None, long: "colour", takes_value: TakesValue::Optional(Some(WHEN), "auto") };
@@ -88,7 +90,7 @@ pub static ALL_ARGS: Args = Args(&[
 
     &ONE_LINE, &LONG, &GRID, &ACROSS, &RECURSE, &TREE, &CLASSIFY, &DEREF_LINKS,
     &COLOR, &COLOUR, &COLOR_SCALE, &COLOUR_SCALE, &COLOR_SCALE_MODE, &COLOUR_SCALE_MODE,
-    &WIDTH, &NO_QUOTES,
+    &WIDTH, &NO_QUOTES, &ABSOLUTE,
 
     &ALL, &ALMOST_ALL, &LIST_DIRS, &LEVEL, &REVERSE, &SORT, &DIRS_FIRST,
     &IGNORE_GLOB, &GIT_IGNORE, &ONLY_DIRS, &ONLY_FILES,

+ 1 - 0
src/options/help.rs

@@ -26,6 +26,7 @@ DISPLAY OPTIONS
   --icons=WHEN               when to display icons (always, auto, never)
   --no-quotes                don't quote file names with spaces
   --hyperlink                display entries as hyperlinks
+  --absolute                 display entries with their absolute path (on, follow, off)
   -w, --width COLS           set screen width in columns
 
 

+ 32 - 1
src/output/file_name.rs

@@ -2,6 +2,7 @@ use std::fmt::Debug;
 use std::path::Path;
 
 use ansiterm::{ANSIString, Style};
+use path_clean;
 use unicode_width::UnicodeWidthStr;
 
 use crate::fs::{File, FileTarget};
@@ -25,6 +26,9 @@ pub struct Options {
     /// Whether to make file names hyperlinks.
     pub embed_hyperlinks: EmbedHyperlinks,
 
+    /// Whether to display files with their absolute path.
+    pub absolute: Absolute,
+
     /// Whether we are in a console or redirecting the output
     pub is_a_tty: bool,
 }
@@ -114,6 +118,14 @@ pub enum EmbedHyperlinks {
     On,
 }
 
+/// Whether to show absolute paths
+#[derive(PartialEq, Eq, Debug, Copy, Clone)]
+pub enum Absolute {
+    On,
+    Follow,
+    Off,
+}
+
 /// Whether or not to wrap file names with spaces in quotes.
 #[derive(PartialEq, Debug, Copy, Clone)]
 pub enum QuoteStyle {
@@ -231,6 +243,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
                             show_icons: ShowIcons::Never,
                             embed_hyperlinks: EmbedHyperlinks::Off,
                             is_a_tty: self.options.is_a_tty,
+                            absolute: Absolute::Off,
                         };
 
                         let target_name = FileName {
@@ -392,7 +405,7 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
         }
 
         escape(
-            self.file.name.clone(),
+            self.display_name(),
             &mut bits,
             file_style,
             self.colours.control_char(),
@@ -408,6 +421,24 @@ impl<'a, 'dir, C: Colours> FileName<'a, 'dir, C> {
         bits
     }
 
+    /// Returns the string that should be displayed as the file's name.
+    fn display_name(&self) -> String {
+        match self.options.absolute {
+            Absolute::On => std::env::current_dir().ok().and_then(|p| {
+                path_clean::clean(p.join(&self.file.path))
+                    .to_str()
+                    .map(std::borrow::ToOwned::to_owned)
+            }),
+            Absolute::Follow => self
+                .file
+                .absolute_path()
+                .and_then(|p| p.to_str())
+                .map(std::borrow::ToOwned::to_owned),
+            Absolute::Off => None,
+        }
+        .unwrap_or(self.file.name.clone())
+    }
+
     /// Figures out which colour to paint the filename part of the output,
     /// depending on which “type” of file it appears to be — either from the
     /// class on the filesystem or from its name. (Or the broken link colour,