"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "crates/globset/src/glob.rs" between
ripgrep-12.1.1.tar.gz and ripgrep-13.0.0.tar.gz

About: ripgrep is a command line search tool ("rg") that tries to combine the usability of "ag" (an "ack" clone) with the raw speed of GNU "grep" (written in "Rust").

glob.rs  (ripgrep-12.1.1):glob.rs  (ripgrep-13.0.0)
use std::fmt; use std::fmt;
use std::hash; use std::hash;
use std::iter; use std::iter;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::path::{is_separator, Path}; use std::path::{is_separator, Path};
use std::str; use std::str;
use regex; use regex;
use regex::bytes::Regex; use regex::bytes::Regex;
use {new_regex, Candidate, Error, ErrorKind}; use crate::{new_regex, Candidate, Error, ErrorKind};
/// Describes a matching strategy for a particular pattern. /// Describes a matching strategy for a particular pattern.
/// ///
/// This provides a way to more quickly determine whether a pattern matches /// This provides a way to more quickly determine whether a pattern matches
/// a particular file path in a way that scales with a large number of /// a particular file path in a way that scales with a large number of
/// patterns. For example, if many patterns are of the form `*.ext`, then it's /// patterns. For example, if many patterns are of the form `*.ext`, then it's
/// possible to test whether any of those patterns matches by looking up a /// possible to test whether any of those patterns matches by looking up a
/// file path's extension in a hash table. /// file path's extension in a hash table.
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum MatchStrategy { pub enum MatchStrategy {
skipping to change at line 101 skipping to change at line 101
} }
impl hash::Hash for Glob { impl hash::Hash for Glob {
fn hash<H: hash::Hasher>(&self, state: &mut H) { fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.glob.hash(state); self.glob.hash(state);
self.opts.hash(state); self.opts.hash(state);
} }
} }
impl fmt::Display for Glob { impl fmt::Display for Glob {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.glob.fmt(f) self.glob.fmt(f)
} }
} }
impl str::FromStr for Glob { impl str::FromStr for Glob {
type Err = Error; type Err = Error;
fn from_str(glob: &str) -> Result<Self, Self::Err> { fn from_str(glob: &str) -> Result<Self, Self::Err> {
Self::new(glob) Self::new(glob)
} }
skipping to change at line 130 skipping to change at line 130
re: Regex, re: Regex,
} }
impl GlobMatcher { impl GlobMatcher {
/// Tests whether the given path matches this pattern or not. /// Tests whether the given path matches this pattern or not.
pub fn is_match<P: AsRef<Path>>(&self, path: P) -> bool { pub fn is_match<P: AsRef<Path>>(&self, path: P) -> bool {
self.is_match_candidate(&Candidate::new(path.as_ref())) self.is_match_candidate(&Candidate::new(path.as_ref()))
} }
/// Tests whether the given path matches this pattern or not. /// Tests whether the given path matches this pattern or not.
pub fn is_match_candidate(&self, path: &Candidate) -> bool { pub fn is_match_candidate(&self, path: &Candidate<'_>) -> bool {
self.re.is_match(&path.path) self.re.is_match(&path.path)
} }
/// Returns the `Glob` used to compile this matcher. /// Returns the `Glob` used to compile this matcher.
pub fn glob(&self) -> &Glob { pub fn glob(&self) -> &Glob {
&self.pat &self.pat
} }
} }
/// A strategic matcher for a single pattern. /// A strategic matcher for a single pattern.
skipping to change at line 160 skipping to change at line 160
} }
#[cfg(test)] #[cfg(test)]
impl GlobStrategic { impl GlobStrategic {
/// Tests whether the given path matches this pattern or not. /// Tests whether the given path matches this pattern or not.
fn is_match<P: AsRef<Path>>(&self, path: P) -> bool { fn is_match<P: AsRef<Path>>(&self, path: P) -> bool {
self.is_match_candidate(&Candidate::new(path.as_ref())) self.is_match_candidate(&Candidate::new(path.as_ref()))
} }
/// Tests whether the given path matches this pattern or not. /// Tests whether the given path matches this pattern or not.
fn is_match_candidate(&self, candidate: &Candidate) -> bool { fn is_match_candidate(&self, candidate: &Candidate<'_>) -> bool {
let byte_path = &*candidate.path; let byte_path = &*candidate.path;
match self.strategy { match self.strategy {
MatchStrategy::Literal(ref lit) => lit.as_bytes() == byte_path, MatchStrategy::Literal(ref lit) => lit.as_bytes() == byte_path,
MatchStrategy::BasenameLiteral(ref lit) => { MatchStrategy::BasenameLiteral(ref lit) => {
lit.as_bytes() == &*candidate.basename lit.as_bytes() == &*candidate.basename
} }
MatchStrategy::Extension(ref ext) => { MatchStrategy::Extension(ref ext) => {
ext.as_bytes() == &*candidate.ext ext.as_bytes() == &*candidate.ext
} }
skipping to change at line 370 skipping to change at line 370
_ => return None, _ => return None,
} }
} }
if lit.is_empty() { if lit.is_empty() {
None None
} else { } else {
Some(lit) Some(lit)
} }
} }
/// This is like `ext`, but returns an extension even if it isn't sufficent /// This is like `ext`, but returns an extension even if it isn't sufficient
/// to imply a match. Namely, if an extension is returned, then it is /// to imply a match. Namely, if an extension is returned, then it is
/// necessary but not sufficient for a match. /// necessary but not sufficient for a match.
fn required_ext(&self) -> Option<String> { fn required_ext(&self) -> Option<String> {
if self.opts.case_insensitive { if self.opts.case_insensitive {
return None; return None;
} }
// We don't care at all about the beginning of this pattern. All we // We don't care at all about the beginning of this pattern. All we
// need to check for is if it ends with a literal of the form `.ext`. // need to check for is if it ends with a literal of the form `.ext`.
let mut ext: Vec<char> = vec![]; // built in reverse let mut ext: Vec<char> = vec![]; // built in reverse
for t in self.tokens.iter().rev() { for t in self.tokens.iter().rev() {
skipping to change at line 406 skipping to change at line 406
Some(ext.into_iter().collect()) Some(ext.into_iter().collect())
} }
} }
/// Returns a literal prefix of this pattern if the entire pattern matches /// Returns a literal prefix of this pattern if the entire pattern matches
/// if the literal prefix matches. /// if the literal prefix matches.
fn prefix(&self) -> Option<String> { fn prefix(&self) -> Option<String> {
if self.opts.case_insensitive { if self.opts.case_insensitive {
return None; return None;
} }
let end = match self.tokens.last() { let (end, need_sep) = match self.tokens.last() {
Some(&Token::ZeroOrMore) => { Some(&Token::ZeroOrMore) => {
if self.opts.literal_separator { if self.opts.literal_separator {
// If a trailing `*` can't match a `/`, then we can't // If a trailing `*` can't match a `/`, then we can't
// assume a match of the prefix corresponds to a match // assume a match of the prefix corresponds to a match
// of the overall pattern. e.g., `foo/*` with // of the overall pattern. e.g., `foo/*` with
// `literal_separator` enabled matches `foo/bar` but not // `literal_separator` enabled matches `foo/bar` but not
// `foo/bar/baz`, even though `foo/bar/baz` has a `foo/` // `foo/bar/baz`, even though `foo/bar/baz` has a `foo/`
// literal prefix. // literal prefix.
return None; return None;
} }
self.tokens.len() - 1 (self.tokens.len() - 1, false)
} }
_ => self.tokens.len(), Some(&Token::RecursiveSuffix) => (self.tokens.len() - 1, true),
_ => (self.tokens.len(), false),
}; };
let mut lit = String::new(); let mut lit = String::new();
for t in &self.tokens[0..end] { for t in &self.tokens[0..end] {
match *t { match *t {
Token::Literal(c) => lit.push(c), Token::Literal(c) => lit.push(c),
_ => return None, _ => return None,
} }
} }
if need_sep {
lit.push('/');
}
if lit.is_empty() { if lit.is_empty() {
None None
} else { } else {
Some(lit) Some(lit)
} }
} }
/// Returns a literal suffix of this pattern if the entire pattern matches /// Returns a literal suffix of this pattern if the entire pattern matches
/// if the literal suffix matches. /// if the literal suffix matches.
/// ///
skipping to change at line 615 skipping to change at line 619
/// Toggle whether the pattern matches case insensitively or not. /// Toggle whether the pattern matches case insensitively or not.
/// ///
/// This is disabled by default. /// This is disabled by default.
pub fn case_insensitive(&mut self, yes: bool) -> &mut GlobBuilder<'a> { pub fn case_insensitive(&mut self, yes: bool) -> &mut GlobBuilder<'a> {
self.opts.case_insensitive = yes; self.opts.case_insensitive = yes;
self self
} }
/// Toggle whether a literal `/` is required to match a path separator. /// Toggle whether a literal `/` is required to match a path separator.
///
/// By default this is false: `*` and `?` will match `/`.
pub fn literal_separator(&mut self, yes: bool) -> &mut GlobBuilder<'a> { pub fn literal_separator(&mut self, yes: bool) -> &mut GlobBuilder<'a> {
self.opts.literal_separator = yes; self.opts.literal_separator = yes;
self self
} }
/// When enabled, a back slash (`\`) may be used to escape /// When enabled, a back slash (`\`) may be used to escape
/// special characters in a glob pattern. Additionally, this will /// special characters in a glob pattern. Additionally, this will
/// prevent `\` from being interpreted as a path separator on all /// prevent `\` from being interpreted as a path separator on all
/// platforms. /// platforms.
/// ///
skipping to change at line 686 skipping to change at line 692
if options.literal_separator { if options.literal_separator {
re.push_str("[^/]*"); re.push_str("[^/]*");
} else { } else {
re.push_str(".*"); re.push_str(".*");
} }
} }
Token::RecursivePrefix => { Token::RecursivePrefix => {
re.push_str("(?:/?|.*/)"); re.push_str("(?:/?|.*/)");
} }
Token::RecursiveSuffix => { Token::RecursiveSuffix => {
re.push_str("(?:/?|/.*)"); re.push_str("/.*");
} }
Token::RecursiveZeroOrMore => { Token::RecursiveZeroOrMore => {
re.push_str("(?:/|/.*/)"); re.push_str("(?:/|/.*/)");
} }
Token::Class { negated, ref ranges } => { Token::Class { negated, ref ranges } => {
re.push('['); re.push('[');
if negated { if negated {
re.push('^'); re.push('^');
} }
for r in ranges { for r in ranges {
skipping to change at line 1012 skipping to change at line 1018
if needle.len() > haystack.len() { if needle.len() > haystack.len() {
return false; return false;
} }
needle == &haystack[haystack.len() - needle.len()..] needle == &haystack[haystack.len() - needle.len()..]
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Token::*; use super::Token::*;
use super::{Glob, GlobBuilder, Token}; use super::{Glob, GlobBuilder, Token};
use {ErrorKind, GlobSetBuilder}; use crate::{ErrorKind, GlobSetBuilder};
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
struct Options { struct Options {
casei: Option<bool>, casei: Option<bool>,
litsep: Option<bool>, litsep: Option<bool>,
bsesc: Option<bool>, bsesc: Option<bool>,
} }
macro_rules! syntax { macro_rules! syntax {
($name:ident, $pat:expr, $tokens:expr) => { ($name:ident, $pat:expr, $tokens:expr) => {
skipping to change at line 1225 skipping to change at line 1231
toregex!(re9, "[+]", r"^[\+]$"); toregex!(re9, "[+]", r"^[\+]$");
toregex!(re10, "+", r"^\+$"); toregex!(re10, "+", r"^\+$");
toregex!(re11, "☃", r"^\xe2\x98\x83$"); toregex!(re11, "☃", r"^\xe2\x98\x83$");
toregex!(re12, "**", r"^.*$"); toregex!(re12, "**", r"^.*$");
toregex!(re13, "**/", r"^.*$"); toregex!(re13, "**/", r"^.*$");
toregex!(re14, "**/*", r"^(?:/?|.*/).*$"); toregex!(re14, "**/*", r"^(?:/?|.*/).*$");
toregex!(re15, "**/**", r"^.*$"); toregex!(re15, "**/**", r"^.*$");
toregex!(re16, "**/**/*", r"^(?:/?|.*/).*$"); toregex!(re16, "**/**/*", r"^(?:/?|.*/).*$");
toregex!(re17, "**/**/**", r"^.*$"); toregex!(re17, "**/**/**", r"^.*$");
toregex!(re18, "**/**/**/*", r"^(?:/?|.*/).*$"); toregex!(re18, "**/**/**/*", r"^(?:/?|.*/).*$");
toregex!(re19, "a/**", r"^a(?:/?|/.*)$"); toregex!(re19, "a/**", r"^a/.*$");
toregex!(re20, "a/**/**", r"^a(?:/?|/.*)$"); toregex!(re20, "a/**/**", r"^a/.*$");
toregex!(re21, "a/**/**/**", r"^a(?:/?|/.*)$"); toregex!(re21, "a/**/**/**", r"^a/.*$");
toregex!(re22, "a/**/b", r"^a(?:/|/.*/)b$"); toregex!(re22, "a/**/b", r"^a(?:/|/.*/)b$");
toregex!(re23, "a/**/**/b", r"^a(?:/|/.*/)b$"); toregex!(re23, "a/**/**/b", r"^a(?:/|/.*/)b$");
toregex!(re24, "a/**/**/**/b", r"^a(?:/|/.*/)b$"); toregex!(re24, "a/**/**/**/b", r"^a(?:/|/.*/)b$");
toregex!(re25, "**/b", r"^(?:/?|.*/)b$"); toregex!(re25, "**/b", r"^(?:/?|.*/)b$");
toregex!(re26, "**/**/b", r"^(?:/?|.*/)b$"); toregex!(re26, "**/**/b", r"^(?:/?|.*/)b$");
toregex!(re27, "**/**/**/b", r"^(?:/?|.*/)b$"); toregex!(re27, "**/**/**/b", r"^(?:/?|.*/)b$");
toregex!(re28, "a**", r"^a.*.*$"); toregex!(re28, "a**", r"^a.*.*$");
toregex!(re29, "**a", r"^.*.*a$"); toregex!(re29, "**a", r"^.*.*a$");
toregex!(re30, "a**b", r"^a.*.*b$"); toregex!(re30, "a**b", r"^a.*.*b$");
toregex!(re31, "***", r"^.*.*.*$"); toregex!(re31, "***", r"^.*.*.*$");
skipping to change at line 1273 skipping to change at line 1279
matches!(matchrec11, "some/**/**/needle.txt", "some/one/two/needle.txt"); matches!(matchrec11, "some/**/**/needle.txt", "some/one/two/needle.txt");
matches!(matchrec12, "some/**/**/needle.txt", "some/other/needle.txt"); matches!(matchrec12, "some/**/**/needle.txt", "some/other/needle.txt");
matches!(matchrec13, "**/test", "one/two/test"); matches!(matchrec13, "**/test", "one/two/test");
matches!(matchrec14, "**/test", "one/test"); matches!(matchrec14, "**/test", "one/test");
matches!(matchrec15, "**/test", "test"); matches!(matchrec15, "**/test", "test");
matches!(matchrec16, "/**/test", "/one/two/test"); matches!(matchrec16, "/**/test", "/one/two/test");
matches!(matchrec17, "/**/test", "/one/test"); matches!(matchrec17, "/**/test", "/one/test");
matches!(matchrec18, "/**/test", "/test"); matches!(matchrec18, "/**/test", "/test");
matches!(matchrec19, "**/.*", ".abc"); matches!(matchrec19, "**/.*", ".abc");
matches!(matchrec20, "**/.*", "abc/.abc"); matches!(matchrec20, "**/.*", "abc/.abc");
matches!(matchrec21, ".*/**", ".abc"); matches!(matchrec21, "**/foo/bar", "foo/bar");
matches!(matchrec22, ".*/**", ".abc/abc"); matches!(matchrec22, ".*/**", ".abc/abc");
matches!(matchrec23, "foo/**", "foo"); matches!(matchrec23, "test/**", "test/");
matches!(matchrec24, "**/foo/bar", "foo/bar"); matches!(matchrec24, "test/**", "test/one");
matches!(matchrec25, "some/*/needle.txt", "some/one/needle.txt"); matches!(matchrec25, "test/**", "test/one/two");
matches!(matchrec26, "some/*/needle.txt", "some/one/needle.txt");
matches!(matchrange1, "a[0-9]b", "a0b"); matches!(matchrange1, "a[0-9]b", "a0b");
matches!(matchrange2, "a[0-9]b", "a9b"); matches!(matchrange2, "a[0-9]b", "a9b");
matches!(matchrange3, "a[!0-9]b", "a_b"); matches!(matchrange3, "a[!0-9]b", "a_b");
matches!(matchrange4, "[a-z123]", "1"); matches!(matchrange4, "[a-z123]", "1");
matches!(matchrange5, "[1a-z23]", "1"); matches!(matchrange5, "[1a-z23]", "1");
matches!(matchrange6, "[123a-z]", "1"); matches!(matchrange6, "[123a-z]", "1");
matches!(matchrange7, "[abc-]", "-"); matches!(matchrange7, "[abc-]", "-");
matches!(matchrange8, "[-abc]", "-"); matches!(matchrange8, "[-abc]", "-");
matches!(matchrange9, "[-a-c]", "b"); matches!(matchrange9, "[-a-c]", "b");
skipping to change at line 1403 skipping to change at line 1410
"some/*/needle.txt", "some/*/needle.txt",
"some/one/two/needle.txt", "some/one/two/needle.txt",
SLASHLIT SLASHLIT
); );
nmatches!( nmatches!(
matchrec32, matchrec32,
"some/*/needle.txt", "some/*/needle.txt",
"some/one/two/three/needle.txt", "some/one/two/three/needle.txt",
SLASHLIT SLASHLIT
); );
nmatches!(matchrec33, ".*/**", ".abc");
nmatches!(matchrec34, "foo/**", "foo");
macro_rules! extract { macro_rules! extract {
($which:ident, $name:ident, $pat:expr, $expect:expr) => { ($which:ident, $name:ident, $pat:expr, $expect:expr) => {
extract!($which, $name, $pat, $expect, Options::default()); extract!($which, $name, $pat, $expect, Options::default());
}; };
($which:ident, $name:ident, $pat:expr, $expect:expr, $options:expr) => { ($which:ident, $name:ident, $pat:expr, $expect:expr, $options:expr) => {
#[test] #[test]
fn $name() { fn $name() {
let mut builder = GlobBuilder::new($pat); let mut builder = GlobBuilder::new($pat);
if let Some(casei) = $options.casei { if let Some(casei) = $options.casei {
skipping to change at line 1507 skipping to change at line 1516
required_ext!(extract_req_ext4, "/foo/bar/.rs", Some(s(".rs"))); required_ext!(extract_req_ext4, "/foo/bar/.rs", Some(s(".rs")));
required_ext!(extract_req_ext5, ".rs", Some(s(".rs"))); required_ext!(extract_req_ext5, ".rs", Some(s(".rs")));
required_ext!(extract_req_ext6, "./rs", None); required_ext!(extract_req_ext6, "./rs", None);
required_ext!(extract_req_ext7, "foo", None); required_ext!(extract_req_ext7, "foo", None);
required_ext!(extract_req_ext8, ".foo/", None); required_ext!(extract_req_ext8, ".foo/", None);
required_ext!(extract_req_ext9, "foo/", None); required_ext!(extract_req_ext9, "foo/", None);
prefix!(extract_prefix1, "/foo", Some(s("/foo"))); prefix!(extract_prefix1, "/foo", Some(s("/foo")));
prefix!(extract_prefix2, "/foo/*", Some(s("/foo/"))); prefix!(extract_prefix2, "/foo/*", Some(s("/foo/")));
prefix!(extract_prefix3, "**/foo", None); prefix!(extract_prefix3, "**/foo", None);
prefix!(extract_prefix4, "foo/**", None); prefix!(extract_prefix4, "foo/**", Some(s("foo/")));
suffix!(extract_suffix1, "**/foo/bar", Some((s("/foo/bar"), true))); suffix!(extract_suffix1, "**/foo/bar", Some((s("/foo/bar"), true)));
suffix!(extract_suffix2, "*/foo/bar", Some((s("/foo/bar"), false))); suffix!(extract_suffix2, "*/foo/bar", Some((s("/foo/bar"), false)));
suffix!(extract_suffix3, "*/foo/bar", None, SLASHLIT); suffix!(extract_suffix3, "*/foo/bar", None, SLASHLIT);
suffix!(extract_suffix4, "foo/bar", Some((s("foo/bar"), false))); suffix!(extract_suffix4, "foo/bar", Some((s("foo/bar"), false)));
suffix!(extract_suffix5, "*.foo", Some((s(".foo"), false))); suffix!(extract_suffix5, "*.foo", Some((s(".foo"), false)));
suffix!(extract_suffix6, "*.foo", None, SLASHLIT); suffix!(extract_suffix6, "*.foo", None, SLASHLIT);
suffix!(extract_suffix7, "**/*_test", Some((s("_test"), false))); suffix!(extract_suffix7, "**/*_test", Some((s("_test"), false)));
baseliteral!(extract_baselit1, "**/foo", Some(s("foo"))); baseliteral!(extract_baselit1, "**/foo", Some(s("foo")));
 End of changes. 17 change blocks. 
18 lines changed or deleted 27 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)