1mod convert;
2mod path;
3
4use std::fmt;
5
6#[derive(Debug)]
7pub enum Error {
8 Parse(Vec<String>), Regex(regex::Error),
10}
11
12impl From<regex::Error> for Error {
13 fn from(e: regex::Error) -> Self {
14 Error::Regex(e)
15 }
16}
17
18impl fmt::Display for Error {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 match self {
21 Error::Parse(msgs) => write!(f, "{}", msgs.join("; ")),
22 Error::Regex(e) => write!(f, "{}", e),
23 }
24 }
25}
26
27impl std::error::Error for Error {
28 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
29 match self {
30 Error::Regex(e) => Some(e),
31 _ => None,
32 }
33 }
34}
35
36pub fn path_matches(path: &str, files: &[&str]) -> Result<Option<usize>, Error> {
37 if files.is_empty() {
38 return Ok(None);
39 }
40
41 let pattern = match path.chars().next() {
43 Some(c) if matches!(c, '?' | '+' | '!') => &path[c.len_utf8()..],
44 _ => path,
45 };
46
47 let parsed_path = match path::parse(pattern) {
49 Ok(p) => p,
50 Err(errs) => {
51 let msgs = errs.into_iter().map(|e| e.to_string()).collect();
52 return Err(Error::Parse(msgs));
53 }
54 };
55
56 let re = convert::path_to_regex(&parsed_path)?;
58
59 Ok(files.iter().enumerate().find(|(_, file)| re.is_match(file)).map(|(i, _)| i))
61}