use clap::ArgMatches;
use crate::fs::DotFilter;
use crate::fs::filter::{
FileFilter, FileFilterFlags, GitIgnore, IgnorePatterns, SortCase, SortField,
};
use crate::options::OptionsError;
impl FileFilter {
pub fn deduce(matches: &ArgMatches, strict: bool) -> Result<Self, OptionsError> {
use FileFilterFlags as FFF;
let mut filter_flags: Vec<FileFilterFlags> = vec![];
for (flag, filter_flag) in &[
("reverse", FFF::Reverse),
("only-dirs", FFF::OnlyDirs),
("only-files", FFF::OnlyFiles),
("no-symlinks", FFF::NoSymlinks),
("show-symlinks", FFF::ShowSymlinks),
("dirs-last", FFF::ListDirsLast),
("dirs-first", FFF::ListDirsFirst),
] {
if matches.get_flag(flag) {
filter_flags.push(filter_flag.clone());
}
}
Ok(Self {
no_symlinks: matches.get_flag("no-symlinks"),
show_symlinks: matches.get_flag("show-symlinks"),
flags: filter_flags,
sort_field: *matches.get_one("sort").unwrap(),
dot_filter: DotFilter::deduce(matches, strict)?,
ignore_patterns: IgnorePatterns::deduce(matches)?,
git_ignore: GitIgnore::deduce(matches),
})
}
}
impl Default for SortField {
fn default() -> Self {
Self::Name(SortCase::AaBbCc)
}
}
impl DotFilter {
pub fn deduce(matches: &ArgMatches, strict: bool) -> Result<Self, OptionsError> {
let all_count = matches.get_count("all");
let has_almost_all = matches.get_flag("almost-all");
match (all_count, has_almost_all) {
(0, false) => Ok(Self::JustFiles),
(1, _) | (0, true) => Ok(Self::Dotfiles),
(c, _) => {
if matches.get_flag("tree") {
Err(OptionsError::TreeAllAll)
} else if strict && c > 2 {
Err(OptionsError::Conflict("all", "all"))
} else {
Ok(Self::DotfilesAndDots)
}
}
}
}
}
impl IgnorePatterns {
pub fn deduce(matches: &ArgMatches) -> Result<Self, OptionsError> {
let Some(inputs) = matches.get_one::<String>("ignore-glob") else {
return Ok(Self::empty());
};
let (patterns, mut errors) = Self::parse_from_iter(inputs.split('|'));
match errors.pop() {
Some(e) => Err(e.into()),
None => Ok(patterns),
}
}
}
impl GitIgnore {
pub fn deduce(matches: &ArgMatches) -> Self {
if matches.get_flag("git-ignore") {
Self::CheckAndIgnore
} else {
Self::Off
}
}
}
#[cfg(test)]
mod tests {
use std::ffi::OsString;
use super::*;
use crate::options::parser::test::{mock_cli, mock_cli_try};
#[test]
fn deduce_git_ignore_off() {
assert_eq!(GitIgnore::deduce(&mock_cli(vec![""])), GitIgnore::Off);
}
#[test]
fn deduce_git_ignore_on() {
assert_eq!(
GitIgnore::deduce(&mock_cli(vec!["--git-ignore"])),
GitIgnore::CheckAndIgnore
);
}
#[test]
fn deduce_ignore_patterns_empty() {
assert_eq!(
IgnorePatterns::deduce(&mock_cli(vec![""])),
Ok(IgnorePatterns::empty())
);
}
#[test]
fn deduce_ignore_patterns_one() {
let pattern = OsString::from("*.o");
let (res, _) = IgnorePatterns::parse_from_iter(pattern.to_string_lossy().split('|'));
assert_eq!(
IgnorePatterns::deduce(&mock_cli(vec!["--ignore-glob", "*.o"])),
Ok(res)
);
}
#[test]
fn deduce_ignore_patterns_error() {
let pattern = OsString::from("[");
let (_, mut e) = IgnorePatterns::parse_from_iter(pattern.to_string_lossy().split('|'));
assert_eq!(
IgnorePatterns::deduce(&mock_cli(vec!["--ignore-glob", "["])),
Err(e.pop().unwrap().into())
);
}
#[test]
fn deduce_dot_filter_just_files() {
assert_eq!(
DotFilter::deduce(&mock_cli(vec![""]), false),
Ok(DotFilter::JustFiles)
);
}
#[test]
fn deduce_dot_filter_dotfiles() {
assert_eq!(
DotFilter::deduce(&mock_cli(vec!["--all"]), false),
Ok(DotFilter::Dotfiles)
);
}
#[test]
fn deduce_dot_filter_dotfiles_and_dots() {
assert_eq!(
DotFilter::deduce(&mock_cli(vec!["--all", "--all"]), false),
Ok(DotFilter::DotfilesAndDots)
);
}
#[test]
fn deduce_dot_filter_tree_all_all() {
assert_eq!(
DotFilter::deduce(&mock_cli(vec!["--all", "--all", "--tree"]), false),
Err(OptionsError::TreeAllAll)
);
}
#[test]
fn deduce_dot_filter_all_all() {
assert_eq!(
DotFilter::deduce(&mock_cli(vec!["--all", "--all", "--all"]), true),
Err(OptionsError::Conflict("all", "all"))
);
}
#[test]
fn deduce_dot_filter_almost_all() {
assert_eq!(
DotFilter::deduce(&mock_cli(vec!["--almost-all"]), false),
Ok(DotFilter::Dotfiles)
);
}
#[test]
fn deduce_sort_field_default() {
assert_eq!(
mock_cli(vec![""]).get_one::<SortField>("sort"),
Some(&SortField::default())
);
}
#[test]
fn deduce_sort_field_name() {
assert_eq!(
mock_cli(vec!["--sort", "name"]).get_one::<SortField>("sort"),
Some(&SortField::Name(SortCase::AaBbCc))
);
}
#[test]
fn deduce_sort_field_name_case() {
assert_eq!(
mock_cli(vec!["--sort", "Name"]).get_one::<SortField>("sort"),
Some(&SortField::Name(SortCase::ABCabc))
);
}
#[test]
fn deduce_sort_field_name_mix_hidden() {
assert_eq!(
mock_cli(vec!["--sort", ".name"]).get_one::<SortField>("sort"),
Some(&SortField::NameMixHidden(SortCase::AaBbCc))
);
}
#[test]
fn deduce_sort_field_name_mix_hidden_case() {
assert_eq!(
mock_cli(vec!["--sort", ".Name"]).get_one::<SortField>("sort"),
Some(&SortField::NameMixHidden(SortCase::ABCabc))
);
}
#[test]
fn deduce_sort_field_size() {
assert_eq!(
mock_cli(vec!["--sort", "size"]).get_one::<SortField>("sort"),
Some(&SortField::Size)
);
}
#[test]
fn deduce_sort_field_extension() {
assert_eq!(
mock_cli(vec!["--sort", "ext"]).get_one::<SortField>("sort"),
Some(&SortField::Extension(SortCase::AaBbCc))
);
}
#[test]
fn deduce_sort_field_extension_case() {
assert_eq!(
mock_cli(vec!["--sort", "Ext"]).get_one::<SortField>("sort"),
Some(&SortField::Extension(SortCase::ABCabc))
);
}
#[test]
fn deduce_sort_field_date() {
assert_eq!(
mock_cli(vec!["--sort", "date"]).get_one::<SortField>("sort"),
Some(&SortField::ModifiedDate)
);
}
#[test]
fn deduce_sort_field_time() {
assert_eq!(
mock_cli(vec!["--sort", "time"]).get_one::<SortField>("sort"),
Some(&SortField::ModifiedDate)
);
}
#[test]
fn deduce_sort_field_age() {
assert_eq!(
mock_cli(vec!["--sort", "age"]).get_one::<SortField>("sort"),
Some(&SortField::ModifiedAge)
);
}
#[test]
fn deduce_sort_field_old() {
assert_eq!(
mock_cli(vec!["--sort", "old"]).get_one::<SortField>("sort"),
Some(&SortField::ModifiedAge)
);
}
#[test]
fn deduce_sort_field_ch() {
assert_eq!(
mock_cli(vec!["--sort", "ch"]).get_one::<SortField>("sort"),
Some(&SortField::ChangedDate)
);
}
#[test]
fn deduce_sort_field_acc() {
assert_eq!(
mock_cli(vec!["--sort", "acc"]).get_one::<SortField>("sort"),
Some(&SortField::AccessedDate)
);
}
#[test]
fn deduce_sort_field_cr() {
assert_eq!(
mock_cli(vec!["--sort", "cr"]).get_one::<SortField>("sort"),
Some(&SortField::CreatedDate)
);
}
#[test]
fn deduce_sort_field_err() {
assert!(mock_cli_try(vec!["--sort", "foo"]).is_err());
}
#[test]
fn deduce_file_filter_default() {
assert_eq!(
FileFilter::deduce(&mock_cli(vec![""]), false),
Ok(FileFilter {
flags: vec![],
sort_field: SortField::default(),
dot_filter: DotFilter::JustFiles,
ignore_patterns: IgnorePatterns::empty(),
git_ignore: GitIgnore::Off,
no_symlinks: false,
show_symlinks: false,
})
);
}
#[test]
fn deduce_file_filter_reverse() {
assert_eq!(
FileFilter::deduce(&mock_cli(vec!["--reverse"]), false),
Ok(FileFilter {
flags: vec![FileFilterFlags::Reverse],
sort_field: SortField::default(),
dot_filter: DotFilter::JustFiles,
ignore_patterns: IgnorePatterns::empty(),
git_ignore: GitIgnore::Off,
no_symlinks: false,
show_symlinks: false,
})
);
}
#[test]
fn deduce_file_filter_only_dirs() {
assert_eq!(
FileFilter::deduce(&mock_cli(vec!["--only-dirs"]), false),
Ok(FileFilter {
flags: vec![FileFilterFlags::OnlyDirs],
sort_field: SortField::default(),
dot_filter: DotFilter::JustFiles,
ignore_patterns: IgnorePatterns::empty(),
git_ignore: GitIgnore::Off,
no_symlinks: false,
show_symlinks: false,
})
);
}
#[test]
fn deduce_file_filter_only_files() {
assert_eq!(
FileFilter::deduce(&mock_cli(vec!["--only-files"]), false),
Ok(FileFilter {
flags: vec![FileFilterFlags::OnlyFiles],
sort_field: SortField::default(),
dot_filter: DotFilter::JustFiles,
ignore_patterns: IgnorePatterns::empty(),
git_ignore: GitIgnore::Off,
no_symlinks: false,
show_symlinks: false,
})
);
}
}