use regex::Regex;
use serde::Deserialize;
use crate::git::{FileInfo, FileType};
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MatchExpression {
#[serde(with = "crate::serde_glob")]
Glob(glob::Pattern),
#[serde(with = "crate::serde_regex")]
Regex(Regex),
Type(FileType),
#[serde(with = "crate::serde_regex")]
ShebangRegex(Regex),
Not(Box<MatchExpression>),
Or(Vec<MatchExpression>),
And(Vec<MatchExpression>),
Bool(bool),
}
fn file_matches(file: &FileInfo, expr: &MatchExpression) -> bool {
match expr {
MatchExpression::Glob(glob_pattern) => file
.path
.to_str()
.map_or(false, |path| glob_pattern.matches(path)),
MatchExpression::Regex(re) => file.path.to_str().map_or(false, |path| re.is_match(path)),
MatchExpression::Type(ty) => ty == &file.ty,
MatchExpression::ShebangRegex(re) => file
.shebang
.as_ref()
.map_or(false, |shebang| re.is_match(shebang)),
MatchExpression::Not(inner) => !file_matches(file, inner),
MatchExpression::Or(inner) => inner.iter().any(|inner| file_matches(file, inner)),
MatchExpression::And(inner) => inner.iter().all(|inner| file_matches(file, inner)),
MatchExpression::Bool(b) => *b,
}
}
pub fn matching_files<'a>(files: &'a [FileInfo], expr: &MatchExpression) -> Vec<&'a FileInfo> {
files.iter().filter(|f| file_matches(f, expr)).collect()
}
pub fn retain_matching_files<'a>(files: &mut Vec<FileInfo>, expr: &MatchExpression) {
files.retain(|f| file_matches(f, expr))
}