mirror of
https://github.com/lsd-rs/lsd
synced 2024-12-14 06:02:36 +00:00
Add the directory-order flag
This commit is contained in:
parent
5f50be78e9
commit
92d018255a
4 changed files with 238 additions and 87 deletions
10
src/app.rs
10
src/app.rs
|
@ -98,4 +98,14 @@ pub fn build() -> App<'static, 'static> {
|
|||
.multiple(true)
|
||||
.help("Reverse the order of the sort"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("group-dirs")
|
||||
.long("group-dirs")
|
||||
.possible_value("none")
|
||||
.possible_value("first")
|
||||
.possible_value("last")
|
||||
.default_value("none")
|
||||
.multiple(true)
|
||||
.help("Sort the directories then the files"),
|
||||
)
|
||||
}
|
||||
|
|
275
src/batch.rs
275
src/batch.rs
|
@ -1,9 +1,8 @@
|
|||
use ansi_term::{ANSIString, ANSIStrings};
|
||||
use color::Colors;
|
||||
use flags::{Flags, SortFlag, SortOrder};
|
||||
use flags::{DirOrderFlag, Flags, SortFlag, SortOrder};
|
||||
use icon::Icons;
|
||||
use meta::FileType;
|
||||
use meta::Meta;
|
||||
use meta::{FileType, Meta};
|
||||
use std::cmp::Ordering;
|
||||
use std::iter::IntoIterator;
|
||||
use std::vec::IntoIter;
|
||||
|
@ -139,98 +138,230 @@ impl Batch {
|
|||
}
|
||||
|
||||
fn sort_by_meta(a: &Meta, b: &Meta, flags: Flags) -> Ordering {
|
||||
let ord = match flags.sort_by {
|
||||
SortFlag::Name => {
|
||||
if a.file_type == FileType::Directory && b.file_type != FileType::Directory {
|
||||
Ordering::Less
|
||||
} else if b.file_type == FileType::Directory && a.file_type != FileType::Directory {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
a.name.cmp(&b.name)
|
||||
}
|
||||
match flags.sort_by {
|
||||
SortFlag::Name => match flags.directory_order {
|
||||
DirOrderFlag::First => sort_by_name_with_dirs_first(a, b, flags),
|
||||
DirOrderFlag::None => sort_by_name_with_dirs_unordored(a, b, flags),
|
||||
DirOrderFlag::Last => sort_by_name_with_files_first(a, b, flags),
|
||||
},
|
||||
|
||||
SortFlag::Time => match flags.directory_order {
|
||||
DirOrderFlag::First => sort_by_date_with_dirs_first(a, b, flags),
|
||||
DirOrderFlag::None => sort_by_date_with_dirs_unordored(a, b, flags),
|
||||
DirOrderFlag::Last => sort_by_date_with_files_first(a, b, flags),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_by_name_with_dirs_unordored(a: &Meta, b: &Meta, flags: Flags) -> Ordering {
|
||||
if flags.sort_order == SortOrder::Default {
|
||||
a.name.cmp(&b.name)
|
||||
} else {
|
||||
b.name.cmp(&a.name)
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_by_name_with_dirs_first(a: &Meta, b: &Meta, flags: Flags) -> Ordering {
|
||||
if a.file_type == FileType::Directory && b.file_type != FileType::Directory {
|
||||
Ordering::Less
|
||||
} else if b.file_type == FileType::Directory && a.file_type != FileType::Directory {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
if flags.sort_order == SortOrder::Default {
|
||||
a.name.cmp(&b.name)
|
||||
} else {
|
||||
b.name.cmp(&a.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_by_name_with_files_first(a: &Meta, b: &Meta, flags: Flags) -> Ordering {
|
||||
if a.file_type == FileType::Directory && b.file_type != FileType::Directory {
|
||||
Ordering::Greater
|
||||
} else if b.file_type == FileType::Directory && a.file_type != FileType::Directory {
|
||||
Ordering::Less
|
||||
} else {
|
||||
if flags.sort_order == SortOrder::Default {
|
||||
a.name.cmp(&b.name)
|
||||
} else {
|
||||
b.name.cmp(&a.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_by_date_with_dirs_unordored(a: &Meta, b: &Meta, flags: Flags) -> Ordering {
|
||||
if flags.sort_order == SortOrder::Default {
|
||||
b.date.cmp(&a.date).then(a.name.cmp(&b.name))
|
||||
} else {
|
||||
a.date.cmp(&b.date).then(b.name.cmp(&a.name))
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_by_date_with_dirs_first(a: &Meta, b: &Meta, flags: Flags) -> Ordering {
|
||||
if a.file_type == FileType::Directory && b.file_type != FileType::Directory {
|
||||
Ordering::Less
|
||||
} else if b.file_type == FileType::Directory && a.file_type != FileType::Directory {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
if flags.sort_order == SortOrder::Default {
|
||||
b.date.cmp(&a.date).then(a.name.cmp(&b.name))
|
||||
} else {
|
||||
a.date.cmp(&b.date).then(b.name.cmp(&a.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_by_date_with_files_first(a: &Meta, b: &Meta, flags: Flags) -> Ordering {
|
||||
if a.file_type == FileType::Directory && b.file_type != FileType::Directory {
|
||||
Ordering::Greater
|
||||
} else if b.file_type == FileType::Directory && a.file_type != FileType::Directory {
|
||||
Ordering::Less
|
||||
} else {
|
||||
if flags.sort_order == SortOrder::Default {
|
||||
b.date.cmp(&a.date).then(a.name.cmp(&b.name))
|
||||
} else {
|
||||
a.date.cmp(&b.date).then(b.name.cmp(&a.name))
|
||||
}
|
||||
// most recently modified first
|
||||
SortFlag::Time => b.date.cmp(&a.date).then(a.name.cmp(&b.name)),
|
||||
};
|
||||
match flags.sort_order {
|
||||
SortOrder::Default => ord,
|
||||
SortOrder::Reverse => ord.reverse(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use flags::Flags;
|
||||
use std::fs::{create_dir, File};
|
||||
use std::process::Command;
|
||||
use tempdir::TempDir;
|
||||
|
||||
#[test]
|
||||
fn test_sort_by_meta() {
|
||||
fn test_sort_by_meta_by_name_with_dirs_first() {
|
||||
let tmp_dir = TempDir::new("test_dir").expect("failed to create temp dir");
|
||||
|
||||
// Create a file and make sure that its mod time is before now.
|
||||
let path_a = tmp_dir.path().join("a.txt");
|
||||
// Create the file;
|
||||
let path_a = tmp_dir.path().join("zzz");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let success = Command::new("touch")
|
||||
.arg("-t")
|
||||
.arg("198511160000")
|
||||
.arg(&path_a)
|
||||
.status()
|
||||
.unwrap()
|
||||
.success();
|
||||
assert!(success, "failed to exec touch");
|
||||
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
|
||||
|
||||
// Create a dir;
|
||||
let path_b = tmp_dir.path().join("b");
|
||||
create_dir(&path_b).expect("failed to create dir");
|
||||
let meta_b = Meta::from_path(&path_b).expect("failed to get meta");
|
||||
let path_z = tmp_dir.path().join("aaa");
|
||||
create_dir(&path_z).expect("failed to create dir");
|
||||
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
|
||||
|
||||
// Sort by name
|
||||
assert_eq!(
|
||||
sort_by_meta(&meta_a, &meta_b, Flags::default()),
|
||||
Ordering::Greater
|
||||
);
|
||||
let mut flags = Flags::default();
|
||||
flags.directory_order = DirOrderFlag::First;
|
||||
|
||||
// Sort by name reversed
|
||||
assert_eq!(
|
||||
sort_by_meta(
|
||||
&meta_a,
|
||||
&meta_b,
|
||||
Flags {
|
||||
sort_order: SortOrder::Reverse,
|
||||
..Flags::default()
|
||||
}
|
||||
),
|
||||
Ordering::Less
|
||||
);
|
||||
// Sort with the dirs first
|
||||
assert_eq!(sort_by_meta(&meta_a, &meta_z, flags), Ordering::Greater);
|
||||
|
||||
// Sort with the dirs first (the dirs stay first)
|
||||
flags.sort_order = SortOrder::Reverse;
|
||||
assert_eq!(sort_by_meta(&meta_a, &meta_z, flags), Ordering::Greater);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sort_by_meta_by_name_with_files_first() {
|
||||
let tmp_dir = TempDir::new("test_dir").expect("failed to create temp dir");
|
||||
|
||||
// Create the file;
|
||||
let path_a = tmp_dir.path().join("zzz");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
|
||||
|
||||
// Create a dir;
|
||||
let path_z = tmp_dir.path().join("aaa");
|
||||
create_dir(&path_z).expect("failed to create dir");
|
||||
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.directory_order = DirOrderFlag::Last;
|
||||
|
||||
// Sort with file first
|
||||
assert_eq!(sort_by_meta(&meta_a, &meta_z, flags), Ordering::Less);
|
||||
|
||||
// Sort with file first reversed (thie files stay first)
|
||||
assert_eq!(sort_by_meta(&meta_a, &meta_z, flags), Ordering::Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sort_by_meta_by_name_unordered() {
|
||||
let tmp_dir = TempDir::new("test_dir").expect("failed to create temp dir");
|
||||
|
||||
// Create the file;
|
||||
let path_a = tmp_dir.path().join("aaa");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
|
||||
|
||||
// Create a dir;
|
||||
let path_z = tmp_dir.path().join("zzz");
|
||||
create_dir(&path_z).expect("failed to create dir");
|
||||
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.directory_order = DirOrderFlag::None;
|
||||
|
||||
// Sort by name unordered
|
||||
assert_eq!(sort_by_meta(&meta_a, &meta_z, flags), Ordering::Less);
|
||||
|
||||
// Sort by name unordered
|
||||
flags.sort_order = SortOrder::Reverse;
|
||||
assert_eq!(sort_by_meta(&meta_a, &meta_z, flags), Ordering::Greater);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sort_by_meta_by_name_unordered_2() {
|
||||
let tmp_dir = TempDir::new("test_dir").expect("failed to create temp dir");
|
||||
|
||||
// Create the file;
|
||||
let path_a = tmp_dir.path().join("zzz");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
|
||||
|
||||
// Create a dir;
|
||||
let path_z = tmp_dir.path().join("aaa");
|
||||
create_dir(&path_z).expect("failed to create dir");
|
||||
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.directory_order = DirOrderFlag::None;
|
||||
|
||||
// Sort by name unordered
|
||||
assert_eq!(sort_by_meta(&meta_a, &meta_z, flags), Ordering::Greater);
|
||||
|
||||
// Sort by name unordered reversed
|
||||
flags.sort_order = SortOrder::Reverse;
|
||||
assert_eq!(sort_by_meta(&meta_a, &meta_z, flags), Ordering::Less);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sort_by_meta_by_time() {
|
||||
let tmp_dir = TempDir::new("test_dir").expect("failed to create temp dir");
|
||||
|
||||
// Create the file;
|
||||
let path_a = tmp_dir.path().join("aaa");
|
||||
File::create(&path_a).expect("failed to create file");
|
||||
let meta_a = Meta::from_path(&path_a).expect("failed to get meta");
|
||||
|
||||
// Create the file;
|
||||
let path_z = tmp_dir.path().join("zzz");
|
||||
File::create(&path_z).expect("failed to create file");
|
||||
let success = Command::new("touch")
|
||||
.arg("-t")
|
||||
.arg("198511160000")
|
||||
.arg(&path_z)
|
||||
.status()
|
||||
.unwrap()
|
||||
.success();
|
||||
assert_eq!(true, success, "failed to exec mkfifo");
|
||||
let meta_z = Meta::from_path(&path_z).expect("failed to get meta");
|
||||
|
||||
let mut flags = Flags::default();
|
||||
flags.sort_by = SortFlag::Time;
|
||||
|
||||
// Sort by time
|
||||
assert_eq!(
|
||||
sort_by_meta(
|
||||
&meta_a,
|
||||
&meta_b,
|
||||
Flags {
|
||||
sort_by: SortFlag::Time,
|
||||
..Flags::default()
|
||||
}
|
||||
),
|
||||
Ordering::Greater
|
||||
);
|
||||
assert_eq!(sort_by_meta(&meta_a, &meta_z, flags), Ordering::Less);
|
||||
|
||||
// Sort by time reversed
|
||||
assert_eq!(
|
||||
sort_by_meta(
|
||||
&meta_a,
|
||||
&meta_b,
|
||||
Flags {
|
||||
sort_by: SortFlag::Time,
|
||||
sort_order: SortOrder::Reverse,
|
||||
..Flags::default()
|
||||
}
|
||||
),
|
||||
Ordering::Less
|
||||
);
|
||||
flags.sort_order = SortOrder::Reverse;
|
||||
assert_eq!(sort_by_meta(&meta_a, &meta_z, flags), Ordering::Greater);
|
||||
}
|
||||
}
|
||||
|
|
22
src/flags.rs
22
src/flags.rs
|
@ -10,6 +10,7 @@ pub struct Flags {
|
|||
pub recursive: bool,
|
||||
pub sort_by: SortFlag,
|
||||
pub sort_order: SortOrder,
|
||||
pub directory_order: DirOrderFlag,
|
||||
pub date: DateFlag,
|
||||
pub color: WhenFlag,
|
||||
pub icon: WhenFlag,
|
||||
|
@ -21,6 +22,7 @@ impl Flags {
|
|||
let color_inputs: Vec<&str> = matches.values_of("color").unwrap().collect();
|
||||
let icon_inputs: Vec<&str> = matches.values_of("icon").unwrap().collect();
|
||||
let date_inputs: Vec<&str> = matches.values_of("date").unwrap().collect();
|
||||
let dir_order_inputs: Vec<&str> = matches.values_of("group-dirs").unwrap().collect();
|
||||
|
||||
let sort_by = if matches.is_present("timesort") {
|
||||
SortFlag::Time
|
||||
|
@ -68,6 +70,7 @@ impl Flags {
|
|||
date: DateFlag::from(date_inputs[date_inputs.len() - 1]),
|
||||
color: WhenFlag::from(color_inputs[color_inputs.len() - 1]),
|
||||
icon: WhenFlag::from(icon_inputs[icon_inputs.len() - 1]),
|
||||
directory_order: DirOrderFlag::from(dir_order_inputs[dir_order_inputs.len() - 1]),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +87,7 @@ impl Default for Flags {
|
|||
recursion_depth: usize::max_value(),
|
||||
sort_by: SortFlag::Name,
|
||||
sort_order: SortOrder::Default,
|
||||
directory_order: DirOrderFlag::None,
|
||||
date: DateFlag::Date,
|
||||
color: WhenFlag::Auto,
|
||||
icon: WhenFlag::Auto,
|
||||
|
@ -137,6 +141,24 @@ pub enum SortOrder {
|
|||
Reverse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum DirOrderFlag {
|
||||
None,
|
||||
First,
|
||||
Last,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for DirOrderFlag {
|
||||
fn from(when: &'a str) -> Self {
|
||||
match when {
|
||||
"none" => DirOrderFlag::None,
|
||||
"first" => DirOrderFlag::First,
|
||||
"last" => DirOrderFlag::Last,
|
||||
_ => panic!("invalid \"when\" flag: {}", when),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Flags;
|
||||
|
|
|
@ -34,7 +34,7 @@ impl Indicator {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Indicator;
|
||||
use flags::{DateFlag, Flags, SortFlag, SortOrder, WhenFlag};
|
||||
use flags::Flags;
|
||||
use meta::FileType;
|
||||
|
||||
#[test]
|
||||
|
@ -69,20 +69,8 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_symlink_indicator() {
|
||||
let flags = Flags {
|
||||
display_all: true,
|
||||
display_long: true,
|
||||
display_online: true,
|
||||
display_tree: true,
|
||||
display_indicators: true,
|
||||
recursive: true,
|
||||
recursion_depth: usize::max_value(),
|
||||
sort_by: SortFlag::Name,
|
||||
sort_order: SortOrder::Default,
|
||||
date: DateFlag::Relative,
|
||||
color: WhenFlag::Always,
|
||||
icon: WhenFlag::Always,
|
||||
};
|
||||
let mut flags = Flags::default();
|
||||
flags.display_indicators = true;
|
||||
|
||||
let file_type = Indicator::from(FileType::SymLink);
|
||||
|
||||
|
|
Loading…
Reference in a new issue