sort: add version sort

fix https://github.com/Peltoche/lsd/issues/394
This commit is contained in:
zwPapEr 2020-09-18 22:50:37 +08:00 committed by Abin Simon
parent 08a55f90d3
commit 16f1b1ce7c
7 changed files with 103 additions and 4 deletions

7
Cargo.lock generated
View file

@ -201,6 +201,11 @@ dependencies = [
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "human-sort"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ignore"
version = "0.4.14"
@ -264,6 +269,7 @@ dependencies = [
"chrono-humanize 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"globset 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"human-sort 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
"lscolors 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"predicates 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -609,6 +615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum globset 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad1da430bd7281dde2576f44c84cc3f0f7b475e7202cd503042dff01a8c8120"
"checksum globwalk 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d9db17aec586697a93219b19726b5b68307eba92898c34b170857343fe67c99d"
"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e"
"checksum human-sort 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "140a09c9305e6d5e557e2ed7cbc68e05765a7d4213975b87cb04920689cc6219"
"checksum ignore 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf60d063dbe6b75388eec66cfc07781167ae3d34a09e0c433e6c5de0511f7fb"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"

View file

@ -31,6 +31,7 @@ unicode-width = "0.1.*"
lscolors = "0.7"
wild = "2.0.*"
globset = "0.4.*"
human-sort = "0.2.2"
[target.'cfg(unix)'.dependencies]
users = "0.10.*"

View file

@ -146,6 +146,7 @@ pub fn build() -> App<'static, 'static> {
.long("timesort")
.overrides_with("sizesort")
.overrides_with("extensionsort")
.overrides_with("versionsort")
.multiple(true)
.help("Sort by time modified"),
)
@ -155,6 +156,7 @@ pub fn build() -> App<'static, 'static> {
.long("sizesort")
.overrides_with("timesort")
.overrides_with("extensionsort")
.overrides_with("versionsort")
.multiple(true)
.help("Sort by size"),
)
@ -164,9 +166,19 @@ pub fn build() -> App<'static, 'static> {
.long("extensionsort")
.overrides_with("sizesort")
.overrides_with("timesort")
.overrides_with("versionsort")
.multiple(true)
.help("Sort by file extension"),
)
.arg(
Arg::with_name("versionsort")
.short("v")
.multiple(true)
.overrides_with("timesort")
.overrides_with("sizesort")
.overrides_with("extensionsort")
.help("Natural sort of (version) numbers within text"),
)
.arg(
Arg::with_name("reverse")
.short("r")

View file

@ -60,6 +60,8 @@ impl Flags {
SortFlag::Size
} else if matches.is_present("extensionsort") {
SortFlag::Extension
} else if matches.is_present("versionsort") {
SortFlag::Version
} else {
SortFlag::Name
};
@ -308,6 +310,7 @@ pub enum SortFlag {
Name,
Time,
Size,
Version,
Extension,
}

View file

@ -81,10 +81,7 @@ impl FileType {
}
pub fn is_dirlike(self) -> bool {
match self {
FileType::Directory { .. } | FileType::SymLink { is_dir: true } => true,
_ => false,
}
matches!(self, FileType::Directory { .. } | FileType::SymLink { is_dir: true })
}
}

View file

@ -1,5 +1,6 @@
use crate::flags::{DirOrderFlag, Flags, SortFlag, SortOrder};
use crate::meta::Meta;
use human_sort::compare;
use std::cmp::Ordering;
pub type SortFn = fn(&Meta, &Meta) -> Ordering;
@ -19,6 +20,7 @@ pub fn assemble_sorters(flags: &Flags) -> Vec<(SortOrder, SortFn)> {
SortFlag::Name => by_name,
SortFlag::Size => by_size,
SortFlag::Time => by_date,
SortFlag::Version => by_version,
SortFlag::Extension => by_extension,
};
sorters.push((flags.sort_order, other_sort));
@ -56,6 +58,10 @@ fn by_date(a: &Meta, b: &Meta) -> Ordering {
b.date.cmp(&a.date).then(a.name.cmp(&b.name))
}
fn by_version(a: &Meta, b: &Meta) -> Ordering {
compare(&a.name.name, &b.name.name)
}
fn by_extension(a: &Meta, b: &Meta) -> Ordering {
a.name.extension().cmp(&b.name.extension())
}
@ -263,4 +269,30 @@ mod tests {
let sorter = assemble_sorters(&flags);
assert_eq!(by_meta(&sorter, &meta_a, &meta_t), Ordering::Less);
}
#[test]
fn test_sort_assemble_sorters_by_version() {
let tmp_dir = tempdir().expect("failed to create temp dir");
let path_a = tmp_dir.path().join("2");
File::create(&path_a).expect("failed to create file");
let meta_a = Meta::from_path(&path_a, false).expect("failed to get meta");
let path_b = tmp_dir.path().join("11");
File::create(&path_b).expect("failed to create file");
let meta_b = Meta::from_path(&path_b, false).expect("failed to get meta");
let path_c = tmp_dir.path().join("12");
File::create(&path_c).expect("failed to create file");
let meta_c = Meta::from_path(&path_c, false).expect("failed to get meta");
let mut flags = Flags::default();
flags.sort_by = SortFlag::Version;
let sorter = assemble_sorters(&flags);
assert_eq!(by_meta(&sorter, &meta_b, &meta_a), Ordering::Greater);
let sorter = assemble_sorters(&flags);
assert_eq!(by_meta(&sorter, &meta_b, &meta_c), Ordering::Less);
}
}

View file

@ -260,6 +260,53 @@ fn test_show_folder_of_symlink_for_long_multi() {
.stdout(predicate::str::contains("link/:"));
}
#[test]
fn test_version_sort() {
let dir = tempdir();
dir.child("0.3.7").touch().unwrap();
dir.child("0.11.5").touch().unwrap();
dir.child("11a").touch().unwrap();
dir.child("0.2").touch().unwrap();
dir.child("0.11").touch().unwrap();
dir.child("1").touch().unwrap();
dir.child("11").touch().unwrap();
dir.child("2").touch().unwrap();
dir.child("22").touch().unwrap();
cmd().arg("-v").arg(dir.path()).assert().stdout(
predicate::str::is_match("0.2\n0.3.7\n0.11\n0.11.5\n1\n2\n11\n11a\n22\n$").unwrap(),
);
}
#[test]
fn test_version_sort_overwrite_by_timesort() {
let dir = tempdir();
dir.child("2").touch().unwrap();
dir.child("11").touch().unwrap();
cmd()
.arg("-v")
.arg("-t")
.arg(dir.path())
.assert()
.stdout(predicate::str::is_match("11\n2\n$").unwrap());
}
#[test]
fn test_version_sort_overwrite_by_sizesort() {
use std::fs::File;
use std::io::Write;
let dir = tempdir();
dir.child("2").touch().unwrap();
let larger = dir.path().join("11");
let mut larger_file = File::create(larger).unwrap();
writeln!(larger_file, "this is larger").unwrap();
cmd()
.arg("-v")
.arg("-S")
.arg(dir.path())
.assert()
.stdout(predicate::str::is_match("11\n2\n$").unwrap());
}
fn cmd() -> Command {
Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap()
}