Просмотр исходного кода

feat: add --no-|show-symlinks flags for filtering output

PThorpe92 1 год назад
Родитель
Сommit
99b2fc214e
8 измененных файлов с 51 добавлено и 8 удалено
  1. 2 0
      README.md
  2. 2 0
      completions/fish/eza.fish
  3. 2 0
      completions/nush/eza.nu
  4. 2 0
      completions/zsh/_eza
  5. 5 0
      man/eza.1.md
  6. 31 7
      src/fs/filter.rs
  7. 4 0
      src/options/filter.rs
  8. 3 1
      src/options/flags.rs

+ 2 - 0
README.md

@@ -110,6 +110,8 @@ eza’s options are almost, but not quite, entirely unlike `ls`’s. Quick overv
 - **--group-directories-first**: list directories before other files
 - **--group-directories-first**: list directories before other files
 - **-D**, **--only-dirs**: list only directories
 - **-D**, **--only-dirs**: list only directories
 - **-f**, **--only-files**: list only files
 - **-f**, **--only-files**: list only files
+- **--no-symlinks**: don't show symbolic links
+- **--show-symlinks**: explicitly show links (with `--only-dirs`, `--only-files`, to show symlinks that match the filter)
 - **--git-ignore**: ignore files mentioned in `.gitignore`
 - **--git-ignore**: ignore files mentioned in `.gitignore`
 - **-I**, **--ignore-glob=(globs)**: glob patterns (pipe-separated) of files to ignore
 - **-I**, **--ignore-glob=(globs)**: glob patterns (pipe-separated) of files to ignore
 
 

+ 2 - 0
completions/fish/eza.fish

@@ -81,6 +81,8 @@ complete -c eza -s s -l sort -d "Which field to sort by" -x -a "
 complete -c eza -s I -l ignore-glob -d "Ignore files that match these glob patterns" -r
 complete -c eza -s I -l ignore-glob -d "Ignore files that match these glob patterns" -r
 complete -c eza -s D -l only-dirs -d "List only directories"
 complete -c eza -s D -l only-dirs -d "List only directories"
 complete -c eza -s f -l only-files -d "List only files"
 complete -c eza -s f -l only-files -d "List only files"
+complete -c eza -l show-symlinks -d "Explicitly show symbolic links (For use with --only-dirs | --only-files)"
+complete -c eza -l no-symlinks -d "Do not show symbolic links"
 
 
 # Long view options
 # Long view options
 complete -c eza -s b -l binary -d "List file sizes with binary prefixes"
 complete -c eza -s b -l binary -d "List file sizes with binary prefixes"

+ 2 - 0
completions/nush/eza.nu

@@ -30,6 +30,8 @@ export extern "eza" [
     --sort(-s)                 # Which field to sort by
     --sort(-s)                 # Which field to sort by
     --only-dirs(-D)            # List only directories
     --only-dirs(-D)            # List only directories
     --only-files(-f)           # List only files
     --only-files(-f)           # List only files
+    --show-symlinks            # Explicitly show symbolic links (for use with --only-dirs | --only-files)
+    --no-symlinks              # Do not show symbolic links
     --binary(-b)               # List file sizes with binary prefixes
     --binary(-b)               # List file sizes with binary prefixes
     --bytes(-B)                # List file sizes in bytes, without any prefixes
     --bytes(-B)                # List file sizes in bytes, without any prefixes
     --group(-g)                # List each file's group
     --group(-g)                # List each file's group

+ 2 - 0
completions/zsh/_eza

@@ -33,6 +33,8 @@ __eza() {
         {-A,--almost-all}"[Equivalent to --all; included for compatibility with \'ls -A\']" \
         {-A,--almost-all}"[Equivalent to --all; included for compatibility with \'ls -A\']" \
         {-d,--list-dirs}"[List directories like regular files]" \
         {-d,--list-dirs}"[List directories like regular files]" \
         {-D,--only-dirs}"[List only directories]" \
         {-D,--only-dirs}"[List only directories]" \
+        --no-symlinks"[Do not show symbolic links]"
+        --show-symlinks"[Explictly show symbolic links: for use with '--only-dirs'| '--only-files']"
         {-f,--only-files}"[List only files]" \
         {-f,--only-files}"[List only files]" \
         {-L,--level}"+[Limit the depth of recursion]" \
         {-L,--level}"+[Limit the depth of recursion]" \
         {-w,--width}"+[Limits column output of grid, 0 implies auto-width]" \
         {-w,--width}"+[Limits column output of grid, 0 implies auto-width]" \

+ 5 - 0
man/eza.1.md

@@ -166,6 +166,11 @@ Sort fields starting with a capital letter will sort uppercase before lowercase:
 `-f`, `--only-files`
 `-f`, `--only-files`
 : List only files, not directories.
 : List only files, not directories.
 
 
+`--show-symlinks`
+: Explicitly show symbolic links (when used with `--only-files` | `--only-dirs`)
+
+`--no-symlinks`
+: Do not show symbolic links
 
 
 LONG VIEW OPTIONS
 LONG VIEW OPTIONS
 =================
 =================

+ 31 - 7
src/fs/filter.rs

@@ -21,6 +21,12 @@ pub enum FileFilterFlags {
 
 
     /// Whether to only show files.
     /// Whether to only show files.
     OnlyFiles,
     OnlyFiles,
+
+    /// Whether to ignore symlinks
+    NoSymlinks,
+
+    /// Whether to explicitly show symlinks
+    ShowSymlinks,
 }
 }
 
 
 /// The **file filter** processes a list of files before displaying them to
 /// The **file filter** processes a list of files before displaying them to
@@ -68,28 +74,47 @@ pub struct FileFilter {
 
 
     /// Whether to ignore Git-ignored patterns.
     /// Whether to ignore Git-ignored patterns.
     pub git_ignore: GitIgnore,
     pub git_ignore: GitIgnore,
+
+    /// Whether to ignore symlinks
+    pub no_symlinks: bool,
+
+    /// Whether to explicitly show symlinks
+    pub show_symlinks: bool,
 }
 }
 
 
 impl FileFilter {
 impl FileFilter {
     /// Remove every file in the given vector that does *not* pass the
     /// Remove every file in the given vector that does *not* pass the
     /// filter predicate for files found inside a directory.
     /// filter predicate for files found inside a directory.
     pub fn filter_child_files(&self, files: &mut Vec<File<'_>>) {
     pub fn filter_child_files(&self, files: &mut Vec<File<'_>>) {
-        use FileFilterFlags::{OnlyDirs, OnlyFiles};
+        use FileFilterFlags::{NoSymlinks, OnlyDirs, OnlyFiles, ShowSymlinks};
 
 
         files.retain(|f| !self.ignore_patterns.is_ignored(&f.name));
         files.retain(|f| !self.ignore_patterns.is_ignored(&f.name));
 
 
         match (
         match (
             self.flags.contains(&OnlyDirs),
             self.flags.contains(&OnlyDirs),
             self.flags.contains(&OnlyFiles),
             self.flags.contains(&OnlyFiles),
+            self.flags.contains(&NoSymlinks),
+            self.flags.contains(&ShowSymlinks),
         ) {
         ) {
-            (true, false) => {
-                // On pass -'-only-dirs' flag only
+            (true, false, false, false) => {
+                // On pass '--only-dirs' flag only
+                files.retain(File::is_directory);
+            }
+            (true, false, true, false) => {
                 files.retain(File::is_directory);
                 files.retain(File::is_directory);
             }
             }
-            (false, true) => {
-                // On pass -'-only-files' flag only
+            (true, false, false, true) => {
+                files.retain(|f| f.is_directory() || f.points_to_directory());
+            }
+            (false, true, false, false) => {
                 files.retain(File::is_file);
                 files.retain(File::is_file);
             }
             }
+            (false, true, false, true) => {
+                files.retain(|f| f.is_file() || f.is_link() && !f.points_to_directory());
+            }
+            (false, false, true, false) => {
+                files.retain(|f| !f.is_link());
+            }
             _ => {}
             _ => {}
         }
         }
     }
     }
@@ -99,7 +124,7 @@ impl FileFilter {
     ///
     ///
     /// The rules are different for these types of files than the other
     /// The rules are different for these types of files than the other
     /// type because the ignore rules can be used with globbing. For
     /// type because the ignore rules can be used with globbing. For
-    /// example, running `exa -I='*.tmp' .vimrc` shouldn’t filter out the
+    /// example, running `exa -I='*. tmp' .vimrc` shouldn’t filter out the
     /// dotfile, because it’s been directly specified. But running
     /// dotfile, because it’s been directly specified. But running
     /// `exa -I='*.ogg' music/*` should filter out the ogg files obtained
     /// `exa -I='*.ogg' music/*` should filter out the ogg files obtained
     /// from the glob, even though the globbing is done by the shell!
     /// from the glob, even though the globbing is done by the shell!
@@ -249,7 +274,6 @@ impl SortField {
             Self::ChangedDate   => a.changed_time().cmp(&b.changed_time()),
             Self::ChangedDate   => a.changed_time().cmp(&b.changed_time()),
             Self::CreatedDate   => a.created_time().cmp(&b.created_time()),
             Self::CreatedDate   => a.created_time().cmp(&b.created_time()),
             Self::ModifiedAge   => b.modified_time().cmp(&a.modified_time()),  // flip b and a
             Self::ModifiedAge   => b.modified_time().cmp(&a.modified_time()),  // flip b and a
-
             Self::FileType => match a.type_char().cmp(&b.type_char()) { // todo: this recomputes
             Self::FileType => match a.type_char().cmp(&b.type_char()) { // todo: this recomputes
                 Ordering::Equal  => natord::compare(&a.name, &b.name),
                 Ordering::Equal  => natord::compare(&a.name, &b.name),
                 order            => order,
                 order            => order,

+ 4 - 0
src/options/filter.rs

@@ -18,6 +18,8 @@ impl FileFilter {
             (matches.has(&flags::REVERSE)?, FFF::Reverse),
             (matches.has(&flags::REVERSE)?, FFF::Reverse),
             (matches.has(&flags::ONLY_DIRS)?, FFF::OnlyDirs),
             (matches.has(&flags::ONLY_DIRS)?, FFF::OnlyDirs),
             (matches.has(&flags::ONLY_FILES)?, FFF::OnlyFiles),
             (matches.has(&flags::ONLY_FILES)?, FFF::OnlyFiles),
+            (matches.has(&flags::NO_SYMLINKS)?, FFF::NoSymlinks),
+            (matches.has(&flags::SHOW_SYMLINKS)?, FFF::ShowSymlinks),
         ] {
         ] {
             if *has {
             if *has {
                 filter_flags.push(flag.clone());
                 filter_flags.push(flag.clone());
@@ -27,6 +29,8 @@ impl FileFilter {
         #[rustfmt::skip]
         #[rustfmt::skip]
         return Ok(Self {
         return Ok(Self {
             list_dirs_first:  matches.has(&flags::DIRS_FIRST)?,
             list_dirs_first:  matches.has(&flags::DIRS_FIRST)?,
+            no_symlinks:      filter_flags.contains(&FFF::NoSymlinks),
+            show_symlinks:    filter_flags.contains(&FFF::ShowSymlinks),
             flags: filter_flags,
             flags: filter_flags,
             sort_field:       SortField::deduce(matches)?,
             sort_field:       SortField::deduce(matches)?,
             dot_filter:       DotFilter::deduce(matches)?,
             dot_filter:       DotFilter::deduce(matches)?,

+ 3 - 1
src/options/flags.rs

@@ -41,6 +41,8 @@ pub static GIT_IGNORE:  Arg = Arg { short: None, long: "git-ignore",           t
 pub static DIRS_FIRST:  Arg = Arg { short: None, long: "group-directories-first",  takes_value: TakesValue::Forbidden };
 pub static DIRS_FIRST:  Arg = Arg { short: None, long: "group-directories-first",  takes_value: TakesValue::Forbidden };
 pub static ONLY_DIRS:   Arg = Arg { short: Some(b'D'), long: "only-dirs", takes_value: TakesValue::Forbidden };
 pub static ONLY_DIRS:   Arg = Arg { short: Some(b'D'), long: "only-dirs", takes_value: TakesValue::Forbidden };
 pub static ONLY_FILES:  Arg = Arg { short: Some(b'f'), long: "only-files", takes_value: TakesValue::Forbidden };
 pub static ONLY_FILES:  Arg = Arg { short: Some(b'f'), long: "only-files", takes_value: TakesValue::Forbidden };
+pub static NO_SYMLINKS: Arg = Arg { short: None,       long: "no-symlinks", takes_value: TakesValue::Forbidden };
+pub static SHOW_SYMLINKS: Arg = Arg { short: None,     long: "show-symlinks", takes_value: TakesValue::Forbidden };
 const SORTS: Values = &[ "name", "Name", "size", "extension",
 const SORTS: Values = &[ "name", "Name", "size", "extension",
                          "Extension", "modified", "changed", "accessed",
                          "Extension", "modified", "changed", "accessed",
                          "created", "inode", "type", "none" ];
                          "created", "inode", "type", "none" ];
@@ -97,7 +99,7 @@ pub static ALL_ARGS: Args = Args(&[
 
 
     &BINARY, &BYTES, &GROUP, &NUMERIC, &HEADER, &ICONS, &INODE, &LINKS, &MODIFIED, &CHANGED,
     &BINARY, &BYTES, &GROUP, &NUMERIC, &HEADER, &ICONS, &INODE, &LINKS, &MODIFIED, &CHANGED,
     &BLOCKSIZE, &TOTAL_SIZE, &TIME, &ACCESSED, &CREATED, &TIME_STYLE, &HYPERLINK, &MOUNTS,
     &BLOCKSIZE, &TOTAL_SIZE, &TIME, &ACCESSED, &CREATED, &TIME_STYLE, &HYPERLINK, &MOUNTS,
-    &NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME, &SMART_GROUP,
+    &NO_PERMISSIONS, &NO_FILESIZE, &NO_USER, &NO_TIME, &SMART_GROUP, &NO_SYMLINKS, &SHOW_SYMLINKS,
 
 
     &GIT, &NO_GIT, &GIT_REPOS, &GIT_REPOS_NO_STAT,
     &GIT, &NO_GIT, &GIT_REPOS, &GIT_REPOS_NO_STAT,
     &EXTENDED, &OCTAL, &SECURITY_CONTEXT, &STDIN, &FILE_FLAGS
     &EXTENDED, &OCTAL, &SECURITY_CONTEXT, &STDIN, &FILE_FLAGS