nextest_filtering/parsing/
glob.rsuse super::{Error, Span, parse_matcher_text};
use crate::{
NameMatcher,
errors::{GlobConstructError, ParseSingleError},
};
use winnow::{ModalParser, Parser, combinator::trace, stream::Location};
#[derive(Clone, Debug)]
pub struct GenericGlob {
glob_str: String,
regex: regex::bytes::Regex,
}
impl GenericGlob {
pub(crate) fn new(glob_str: String) -> Result<Self, GlobConstructError> {
let glob = globset::GlobBuilder::new(&glob_str)
.backslash_escape(false)
.empty_alternates(true)
.build()
.map_err(GlobConstructError::InvalidGlob)?;
let regex = regex::bytes::Regex::new(glob.regex())
.map_err(|error| GlobConstructError::RegexError(error.to_string()))?;
Ok(Self { glob_str, regex })
}
pub fn as_str(&self) -> &str {
&self.glob_str
}
pub fn regex(&self) -> ®ex::bytes::Regex {
&self.regex
}
pub fn is_match(&self, s: &str) -> bool {
self.regex.is_match(s.as_bytes())
}
}
pub(super) fn parse_glob<'i>(
implicit: bool,
) -> impl ModalParser<Span<'i>, Option<NameMatcher>, Error> {
trace("parse_glob", move |input: &mut Span<'i>| {
let start = input.current_token_start();
let res = match parse_matcher_text.parse_next(input) {
Ok(res) => res,
Err(_) => {
unreachable!("parse_matcher_text should never fail")
}
};
let Some(parsed_value) = res else {
return Ok(None);
};
match GenericGlob::new(parsed_value) {
Ok(glob) => Ok(Some(NameMatcher::Glob { glob, implicit })),
Err(error) => {
let end = input.current_token_start();
let err = ParseSingleError::InvalidGlob {
span: (start, end - start).into(),
error,
};
input.state.report_error(err);
Ok(None)
}
}
})
}