Selaa lähdekoodia

feat: Add --follow-symlinks option

The option enables drilling down into symbolic links that point to
directories.
Ihar Hrachyshka 1 vuosi sitten
vanhempi
sitoutus
da5d198910
7 muutettua tiedostoa jossa 41 lisäystä ja 17 poistoa
  1. 3 0
      man/eza.1.md
  2. 8 4
      src/main.rs
  3. 13 12
      src/options/flags.rs
  4. 1 0
      src/options/help.rs
  5. 4 0
      src/options/view.rs
  6. 11 1
      src/output/details.rs
  7. 1 0
      src/output/mod.rs

+ 3 - 0
man/eza.1.md

@@ -73,6 +73,9 @@ The default behavior (`automatic` or `auto`) will display file kind indicators o
 `-T`, `--tree`
 : Recurse into directories as a tree.
 
+`--follow-symlinks`
+: Drill down into symbolic links that point to directories.
+
 `-X`, `--dereference`
 : Dereference symbolic links when displaying information.
 

+ 8 - 4
src/main.rs

@@ -362,12 +362,16 @@ impl<'args> Exa<'args> {
                     .filter(|&c| c != Component::CurDir)
                     .count()
                     + 1;
+                let follow_links = self.options.view.follow_links;
                 if !recurse_opts.tree && !recurse_opts.is_too_deep(depth) {
                     let mut child_dirs = Vec::new();
-                    for child_dir in children
-                        .iter()
-                        .filter(|f| f.points_to_directory() && !f.is_all_all)
-                    {
+                    for child_dir in children.iter().filter(|f| {
+                        (if follow_links {
+                            f.points_to_directory()
+                        } else {
+                            f.is_directory()
+                        }) && !f.is_all_all
+                    }) {
                         match child_dir.to_dir() {
                             Ok(d) => child_dirs.push(d),
                             Err(e) => {

+ 13 - 12
src/options/flags.rs

@@ -12,17 +12,18 @@ pub static VERSION: Arg = Arg { short: Some(b'v'), long: "version",  takes_value
 pub static HELP:    Arg = Arg { short: Some(b'?'), long: "help",     takes_value: TakesValue::Forbidden };
 
 // display options
-pub static ONE_LINE:    Arg = Arg { short: Some(b'1'), long: "oneline",     takes_value: TakesValue::Forbidden };
-pub static LONG:        Arg = Arg { short: Some(b'l'), long: "long",        takes_value: TakesValue::Forbidden };
-pub static GRID:        Arg = Arg { short: Some(b'G'), long: "grid",        takes_value: TakesValue::Forbidden };
-pub static ACROSS:      Arg = Arg { short: Some(b'x'), long: "across",      takes_value: TakesValue::Forbidden };
-pub static RECURSE:     Arg = Arg { short: Some(b'R'), long: "recurse",     takes_value: TakesValue::Forbidden };
-pub static TREE:        Arg = Arg { short: Some(b'T'), long: "tree",        takes_value: TakesValue::Forbidden };
-pub static CLASSIFY:    Arg = Arg { short: Some(b'F'), long: "classify",    takes_value: TakesValue::Optional(Some(WHEN), "auto") };
-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") };
+pub static ONE_LINE:     Arg = Arg { short: Some(b'1'), long: "oneline",         takes_value: TakesValue::Forbidden };
+pub static LONG:         Arg = Arg { short: Some(b'l'), long: "long",            takes_value: TakesValue::Forbidden };
+pub static GRID:         Arg = Arg { short: Some(b'G'), long: "grid",            takes_value: TakesValue::Forbidden };
+pub static ACROSS:       Arg = Arg { short: Some(b'x'), long: "across",          takes_value: TakesValue::Forbidden };
+pub static RECURSE:      Arg = Arg { short: Some(b'R'), long: "recurse",         takes_value: TakesValue::Forbidden };
+pub static TREE:         Arg = Arg { short: Some(b'T'), long: "tree",            takes_value: TakesValue::Forbidden };
+pub static CLASSIFY:     Arg = Arg { short: Some(b'F'), long: "classify",        takes_value: TakesValue::Optional(Some(WHEN), "auto") };
+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") };
+pub static FOLLOW_LINKS: Arg = Arg { short: None,       long: "follow-symlinks", takes_value: TakesValue::Forbidden };
 const ABSOLUTE_MODES: &[&str] = &["on", "follow", "off"];
 
 pub static COLOR:  Arg = Arg { short: None, long: "color",  takes_value: TakesValue::Optional(Some(WHEN), "auto") };
@@ -97,7 +98,7 @@ pub static FILE_FLAGS:        Arg = Arg { short: Some(b'O'), long: "flags",
 pub static ALL_ARGS: Args = Args(&[
     &VERSION, &HELP,
 
-    &ONE_LINE, &LONG, &GRID, &ACROSS, &RECURSE, &TREE, &CLASSIFY, &DEREF_LINKS,
+    &ONE_LINE, &LONG, &GRID, &ACROSS, &RECURSE, &TREE, &CLASSIFY, &DEREF_LINKS, &FOLLOW_LINKS,
     &COLOR, &COLOUR, &COLOR_SCALE, &COLOUR_SCALE, &COLOR_SCALE_MODE, &COLOUR_SCALE_MODE,
     &WIDTH, &NO_QUOTES, &ABSOLUTE,
 

+ 1 - 0
src/options/help.rs

@@ -33,6 +33,7 @@ DISPLAY OPTIONS
   --no-quotes                don't quote file names with spaces
   --hyperlink                display entries as hyperlinks
   --absolute                 display entries with their absolute path (on, follow, off)
+  --follow-symlinks          drill down into symbolic links that point to directories
   -w, --width COLS           set screen width in columns
 
 

+ 4 - 0
src/options/view.rs

@@ -22,6 +22,7 @@ impl View {
     pub fn deduce<V: Vars>(matches: &MatchedFlags<'_>, vars: &V) -> Result<Self, OptionsError> {
         let mode = Mode::deduce(matches, vars)?;
         let deref_links = matches.has(&flags::DEREF_LINKS)?;
+        let follow_links = matches.has(&flags::FOLLOW_LINKS)?;
         let total_size = matches.has(&flags::TOTAL_SIZE)?;
         let width = TerminalWidth::deduce(matches, vars)?;
         let file_style = FileStyle::deduce(matches, vars, width.actual_terminal_width().is_some())?;
@@ -30,6 +31,7 @@ impl View {
             width,
             file_style,
             deref_links,
+            follow_links,
             total_size,
         })
     }
@@ -157,6 +159,7 @@ impl details::Options {
             secattr: xattr::ENABLED && matches.has(&flags::SECURITY_CONTEXT)?,
             mounts: matches.has(&flags::MOUNTS)?,
             color_scale: ColorScaleOptions::deduce(matches, vars)?,
+            follow_links: matches.has(&flags::FOLLOW_LINKS)?,
         };
 
         Ok(details)
@@ -178,6 +181,7 @@ impl details::Options {
             secattr: xattr::ENABLED && matches.has(&flags::SECURITY_CONTEXT)?,
             mounts: matches.has(&flags::MOUNTS)?,
             color_scale: ColorScaleOptions::deduce(matches, vars)?,
+            follow_links: matches.has(&flags::FOLLOW_LINKS)?,
         })
     }
 }

+ 11 - 1
src/output/details.rs

@@ -121,6 +121,9 @@ pub struct Options {
     pub mounts: bool,
 
     pub color_scale: ColorScaleOptions,
+
+    /// Whether to drill down into symbolic links that point to directories
+    pub follow_links: bool,
 }
 
 pub struct Render<'a> {
@@ -291,8 +294,15 @@ impl<'a> Render<'a> {
                     .map(|t| t.row_for_file(file, self.show_xattr_hint(file), color_scale_info));
 
                 let mut dir = None;
+                let follow_links = self.opts.follow_links;
                 if let Some(r) = self.recurse {
-                    if file.points_to_directory() && r.tree && !r.is_too_deep(depth.0) {
+                    if (if follow_links {
+                        file.points_to_directory()
+                    } else {
+                        file.is_directory()
+                    }) && r.tree
+                        && !r.is_too_deep(depth.0)
+                    {
                         trace!("matching on to_dir");
                         match file.to_dir() {
                             Ok(d) => {

+ 1 - 0
src/output/mod.rs

@@ -30,6 +30,7 @@ pub struct View {
     pub width: TerminalWidth,
     pub file_style: file_name::Options,
     pub deref_links: bool,
+    pub follow_links: bool,
     pub total_size: bool,
 }