1use std::path::Path;
2
3use anyhow::Result;
4use regex::Regex;
5
6use crate::common::filename_from_path;
7use crate::modes::Flagged;
8
9pub fn regex_flagger(input_string: &str, paths: &[&Path], flagged: &mut Flagged) -> Result<()> {
16 let Ok(regex) = CaseDependantRegex::new(input_string) else {
17 return Ok(());
18 };
19 flagged.clear();
20 for path in paths {
21 if regex.is_match(filename_from_path(path)?) {
22 flagged.push(path.to_path_buf());
23 }
24 }
25
26 Ok(())
27}
28
29#[derive(Clone)]
40pub struct CaseDependantRegex {
41 input_string: String,
42 regex: Regex,
43}
44
45impl CaseDependantRegex {
46 pub fn new(input_string: &str) -> Result<Self> {
52 Ok(Self {
53 input_string: input_string.to_string(),
54 regex: Self::complete_regex(input_string)?,
55 })
56 }
57
58 pub fn is_empty(&self) -> bool {
60 self.input_string.is_empty()
61 }
62
63 pub fn is_match(&self, haystack: &str) -> bool {
65 self.regex.is_match(haystack)
66 }
67
68 fn complete_regex(input_string: &str) -> Result<Regex> {
69 let re = if Self::has_uppercase(input_string) {
70 input_string
71 } else {
72 &format!("(?i){input_string}")
73 };
74 Ok(Regex::new(re)?)
75 }
76
77 fn has_uppercase(input_string: &str) -> bool {
78 input_string.chars().any(|c| c.is_uppercase())
79 }
80}
81
82impl std::fmt::Display for CaseDependantRegex {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 f.write_str(&self.input_string)
85 }
86}