1use std::{borrow::Borrow, fmt::Display};
2
3use regex::Regex;
4
5use crate::modes::{FileInfo, FileKind};
6
7#[derive(Clone)]
10pub enum FilterKind {
11 Extension(String),
12 Name(String),
13 Directory,
14 All,
15}
16
17impl FilterKind {
18 #[must_use]
21 pub fn from_input(input: &str) -> Self {
22 let words: Vec<&str> = input.split_whitespace().collect();
23 match words.first() {
24 Some(&"d") => Self::Directory,
25 Some(&"e") if words.len() > 1 => Self::Extension(words[1].to_owned()),
26 Some(&"n") if words.len() > 1 => Self::Name(words[1].to_owned()),
27 _ => Self::All,
28 }
29 }
30
31 #[must_use]
35 pub fn filter_by(&self, fileinfo: &FileInfo, keep_dirs: bool) -> bool {
36 match self {
37 Self::Extension(ext) => Self::filter_by_extension(fileinfo, ext, keep_dirs),
38 Self::Name(filename) => Self::filter_by_name(fileinfo, filename, keep_dirs),
39 Self::Directory => Self::filter_directory(fileinfo),
40 Self::All => true,
41 }
42 }
43
44 fn filter_by_extension(fileinfo: &FileInfo, ext: &str, keep_dirs: bool) -> bool {
45 let file_ext: &str = fileinfo.extension.borrow();
46 file_ext == ext || keep_dirs && fileinfo.is_dir()
47 }
48
49 fn filter_by_name(fileinfo: &FileInfo, filename: &str, keep_dirs: bool) -> bool {
50 if keep_dirs && fileinfo.is_dir() {
51 true
52 } else {
53 let Ok(re) = Regex::new(filename) else {
54 return false;
55 };
56 re.is_match(&fileinfo.filename)
57 }
58 }
59
60 fn filter_directory(fileinfo: &FileInfo) -> bool {
61 matches!(fileinfo.file_kind, FileKind::Directory)
62 }
63}
64
65impl Display for FilterKind {
68 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
69 match self {
70 Self::Directory => write!(f, "Filter: Directory only"),
71 Self::Extension(s) => write!(f, "Filter: by extension \"{s}\""),
72 Self::Name(s) => write!(f, "Filter: by name \"{s}\""),
73 Self::All => write!(f, ""),
74 }
75 }
76}