Bladeren bron

Add sorting by type

This isn’t perfect, as a file’s type isn’t cached, so it gets recomputed for every comparison in the sort! We can’t go off the file’s `st_mode` flag because it’s not guaranteed to be in any order between systems.
Benjamin Sago 8 jaren geleden
bovenliggende
commit
f750536420
5 gewijzigde bestanden met toevoegingen van 38 en 5 verwijderingen
  1. 4 1
      src/fs/fields.rs
  2. 14 2
      src/options/filter.rs
  3. 7 2
      xtests/run.sh
  4. 10 0
      xtests/sort-by-type
  5. 3 0
      xtests/specials_sort

+ 4 - 1
src/fs/fields.rs

@@ -40,8 +40,11 @@ pub type uid_t = u32;
 /// This type is set entirely by the filesystem, rather than relying on a
 /// file’s contents. So “link” is a type, but “image” is just a type of
 /// regular file. (See the `filetype` module for those checks.)
+///
+/// Its ordering is used when sorting by type.
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
 pub enum Type {
-    File, Directory, Pipe, Link, Socket, CharDevice, BlockDevice, Special,
+    Directory, File, Link, Pipe, Socket, CharDevice, BlockDevice, Special,
 }
 
 impl Type {

+ 14 - 2
src/options/filter.rs

@@ -135,6 +135,11 @@ impl FileFilter {
             SortField::AccessedDate  => a.metadata.atime().cmp(&b.metadata.atime()),
             SortField::CreatedDate   => a.metadata.ctime().cmp(&b.metadata.ctime()),
 
+            SortField::FileType => match a.type_char().cmp(&b.type_char()) { // todo: this recomputes
+                Ordering::Equal  => natord::compare(&*a.name, &*b.name),
+                order            => order,
+            },
+
             SortField::Extension(Sensitive) => match a.ext.cmp(&b.ext) {
                 Ordering::Equal  => natord::compare(&*a.name, &*b.name),
                 order            => order,
@@ -195,6 +200,12 @@ pub enum SortField {
     /// In original Unix, this was, however, meant as creation time.
     /// https://www.bell-labs.com/usr/dmr/www/cacm.html
     CreatedDate,
+
+    /// The type of the file: directories, links, pipes, regular, files, etc.
+    ///
+    /// Files are ordered according to the `PartialOrd` implementation of
+    /// `fs::fields::Type`, so changing that will change this.
+    FileType,
 }
 
 /// Whether a field should be sorted case-sensitively or case-insensitively.
@@ -226,7 +237,7 @@ impl SortField {
 
         const SORTS: &[&str] = &[ "name", "Name", "size", "extension",
                                   "Extension", "modified", "accessed",
-                                  "created", "inode", "none" ];
+                                  "created", "inode", "type", "none" ];
 
         if let Some(word) = matches.opt_str("sort") {
             match &*word {
@@ -238,8 +249,9 @@ impl SortField {
                 "mod"  | "modified"   => Ok(SortField::ModifiedDate),
                 "acc"  | "accessed"   => Ok(SortField::AccessedDate),
                 "cr"   | "created"    => Ok(SortField::CreatedDate),
-                "none"                => Ok(SortField::Unsorted),
                 "inode"               => Ok(SortField::FileInode),
+                "type"                => Ok(SortField::FileType),
+                "none"                => Ok(SortField::Unsorted),
                 field                 => Err(Misfire::bad_argument("sort", field, SORTS))
             }
         }

+ 7 - 2
xtests/run.sh

@@ -85,14 +85,19 @@ $exa $testcases/file-names-exts -1 2>&1 --sort=name | diff -q - $results/file-na
 $exa $testcases/file-names-exts -1 2>&1 --sort=Ext  | diff -q - $results/file-names-exts-ext       || exit 1
 $exa $testcases/file-names-exts -1 2>&1 --sort=ext  | diff -q - $results/file-names-exts-ext-case  || exit 1
 
+# Pass multiple input arguments because there aren’t enough of different types
+# in one directory already
+$exa $testcases/links -1 --sort=type 2>&1 | diff -q - $results/sort-by-type  || exit 1
+
 # We can’t guarantee inode numbers, but we can at least check that they’re in
 # order. The inode column is the leftmost one, so sort works for this.
 $exa $testcases/file-names-exts --long --inode --sort=inode | sort --check  || exit 1
 
 
 # Other file types
-$exa $testcases/specials     -l 2>&1 | diff -q - $results/specials    || exit 1
-$exa $testcases/specials  -F -l 2>&1 | diff -q - $results/specials_F  || exit 1
+$exa $testcases/specials             -l 2>&1 | diff -q - $results/specials       || exit 1
+$exa $testcases/specials          -F -l 2>&1 | diff -q - $results/specials_F     || exit 1
+$exa $testcases/specials --sort=type -1 2>&1 | diff -q - $results/specials_sort  || exit 1
 
 
 # Ignores

+ 10 - 0
xtests/sort-by-type

@@ -0,0 +1,10 @@
+some_file
+broken -> nowhere
+current_dir -> .
+forbidden -> /proc/1/root
+itself -> itself
+parent_dir -> ..
+root -> /
+some_file_absolute -> /testcases/links/some_file
+some_file_relative -> some_file
+usr -> /usr

+ 3 - 0
xtests/specials_sort

@@ -0,0 +1,3 @@
+named-pipe
+char-device
+block-device