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.
This commit is contained in:
Benjamin Sago 2017-06-29 14:50:39 +01:00
parent 7d1448da36
commit f750536420
5 changed files with 38 additions and 5 deletions

View File

@ -40,8 +40,11 @@ pub type uid_t = u32;
/// This type is set entirely by the filesystem, rather than relying on a
/// files 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 {

View File

@ -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))
}
}

View File

@ -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 arent 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 cant guarantee inode numbers, but we can at least check that theyre 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
xtests/sort-by-type Normal file
View File

@ -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
xtests/specials_sort Normal file
View File

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