mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-05-19 09:40:22 -07:00
globset: fix repeated use of **
This fixes a bug where repeated use of ** didn't behave as it should. In particular, each use of `**` added a new requirement directory depth requirement. For example, something like `**/**/b` would match `foo/bar/b`, but it wouldn't match `foo/b` even though it should. In particular, `**` semantics demand "infinite" depth, so repeated uses of `**` should just coalesce as if only one was given. We do this coalescing in the parser. It's a little tricky because we treat `**/a`, `a/**` and `a/**/b` as distinct tokens with their own regex conversions. We also test the crap out of it. Fixes #1174
This commit is contained in:
parent
7048a06c31
commit
aeaa5fc1b1
@ -850,27 +850,44 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.pop_token()?;
|
|
||||||
if !prev.map(is_separator).unwrap_or(false) {
|
if !prev.map(is_separator).unwrap_or(false) {
|
||||||
if self.stack.len() <= 1
|
if self.stack.len() <= 1
|
||||||
|| (prev != Some(',') && prev != Some('{')) {
|
|| (prev != Some(',') && prev != Some('{')) {
|
||||||
return Err(self.error(ErrorKind::InvalidRecursive));
|
return Err(self.error(ErrorKind::InvalidRecursive));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let is_suffix =
|
||||||
match self.chars.peek() {
|
match self.chars.peek() {
|
||||||
None => {
|
None => {
|
||||||
assert!(self.bump().is_none());
|
assert!(self.bump().is_none());
|
||||||
self.push_token(Token::RecursiveSuffix)
|
true
|
||||||
}
|
}
|
||||||
Some(&',') | Some(&'}') if self.stack.len() >= 2 => {
|
Some(&',') | Some(&'}') if self.stack.len() >= 2 => {
|
||||||
self.push_token(Token::RecursiveSuffix)
|
true
|
||||||
}
|
}
|
||||||
Some(&c) if is_separator(c) => {
|
Some(&c) if is_separator(c) => {
|
||||||
assert!(self.bump().map(is_separator).unwrap_or(false));
|
assert!(self.bump().map(is_separator).unwrap_or(false));
|
||||||
self.push_token(Token::RecursiveZeroOrMore)
|
false
|
||||||
}
|
}
|
||||||
_ => Err(self.error(ErrorKind::InvalidRecursive)),
|
_ => return Err(self.error(ErrorKind::InvalidRecursive)),
|
||||||
|
};
|
||||||
|
match self.pop_token()? {
|
||||||
|
Token::RecursivePrefix => {
|
||||||
|
self.push_token(Token::RecursivePrefix)?;
|
||||||
}
|
}
|
||||||
|
Token::RecursiveSuffix => {
|
||||||
|
self.push_token(Token::RecursiveSuffix)?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if is_suffix {
|
||||||
|
self.push_token(Token::RecursiveSuffix)?;
|
||||||
|
} else {
|
||||||
|
self.push_token(Token::RecursiveZeroOrMore)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_class(&mut self) -> Result<(), Error> {
|
fn parse_class(&mut self) -> Result<(), Error> {
|
||||||
@ -1194,8 +1211,23 @@ mod tests {
|
|||||||
toregex!(re8, "[*]", r"^[\*]$");
|
toregex!(re8, "[*]", r"^[\*]$");
|
||||||
toregex!(re9, "[+]", r"^[\+]$");
|
toregex!(re9, "[+]", r"^[\+]$");
|
||||||
toregex!(re10, "+", r"^\+$");
|
toregex!(re10, "+", r"^\+$");
|
||||||
toregex!(re11, "**", r"^.*$");
|
toregex!(re11, "☃", r"^\xe2\x98\x83$");
|
||||||
toregex!(re12, "☃", r"^\xe2\x98\x83$");
|
toregex!(re12, "**", r"^.*$");
|
||||||
|
toregex!(re13, "**/", r"^.*$");
|
||||||
|
toregex!(re14, "**/*", r"^(?:/?|.*/).*$");
|
||||||
|
toregex!(re15, "**/**", r"^.*$");
|
||||||
|
toregex!(re16, "**/**/*", r"^(?:/?|.*/).*$");
|
||||||
|
toregex!(re17, "**/**/**", r"^.*$");
|
||||||
|
toregex!(re18, "**/**/**/*", r"^(?:/?|.*/).*$");
|
||||||
|
toregex!(re19, "a/**", r"^a(?:/?|/.*)$");
|
||||||
|
toregex!(re20, "a/**/**", r"^a(?:/?|/.*)$");
|
||||||
|
toregex!(re21, "a/**/**/**", r"^a(?:/?|/.*)$");
|
||||||
|
toregex!(re22, "a/**/b", r"^a(?:/|/.*/)b$");
|
||||||
|
toregex!(re23, "a/**/**/b", r"^a(?:/|/.*/)b$");
|
||||||
|
toregex!(re24, "a/**/**/**/b", r"^a(?:/|/.*/)b$");
|
||||||
|
toregex!(re25, "**/b", r"^(?:/?|.*/)b$");
|
||||||
|
toregex!(re26, "**/**/b", r"^(?:/?|.*/)b$");
|
||||||
|
toregex!(re27, "**/**/**/b", r"^(?:/?|.*/)b$");
|
||||||
|
|
||||||
matches!(match1, "a", "a");
|
matches!(match1, "a", "a");
|
||||||
matches!(match2, "a*b", "a_b");
|
matches!(match2, "a*b", "a_b");
|
||||||
|
@ -710,6 +710,7 @@ mod tests {
|
|||||||
ignored!(ig41, ROOT, "\\a", "a");
|
ignored!(ig41, ROOT, "\\a", "a");
|
||||||
ignored!(ig42, ROOT, "s*.rs", "sfoo.rs");
|
ignored!(ig42, ROOT, "s*.rs", "sfoo.rs");
|
||||||
ignored!(ig43, ROOT, "**", "foo.rs");
|
ignored!(ig43, ROOT, "**", "foo.rs");
|
||||||
|
ignored!(ig44, ROOT, "**/**/*", "a/foo.rs");
|
||||||
|
|
||||||
not_ignored!(ignot1, ROOT, "amonths", "months");
|
not_ignored!(ignot1, ROOT, "amonths", "months");
|
||||||
not_ignored!(ignot2, ROOT, "monthsa", "months");
|
not_ignored!(ignot2, ROOT, "monthsa", "months");
|
||||||
|
@ -604,3 +604,12 @@ rgtest!(r1173, |dir: Dir, mut cmd: TestCommand| {
|
|||||||
dir.create("foo", "test");
|
dir.create("foo", "test");
|
||||||
cmd.arg("test").assert_err();
|
cmd.arg("test").assert_err();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// See: https://github.com/BurntSushi/ripgrep/issues/1174
|
||||||
|
rgtest!(r1174, |dir: Dir, mut cmd: TestCommand| {
|
||||||
|
dir.create_dir(".git");
|
||||||
|
dir.create(".gitignore", "**/**/*");
|
||||||
|
dir.create_dir("a");
|
||||||
|
dir.create("a/foo", "test");
|
||||||
|
cmd.arg("test").assert_err();
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user