Skip to content

Commit 2b48686

Browse files
committed
feat: add Pattern::from_bytes_without_negation()
1 parent f564fed commit 2b48686

File tree

3 files changed

+33
-8
lines changed

3 files changed

+33
-8
lines changed

gix-glob/src/parse.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,23 @@ use crate::{pattern, pattern::Mode};
66
/// A sloppy parser that performs only the most basic checks, providing additional information
77
/// using `pattern::Mode` flags.
88
///
9+
/// If `may_alter` is `false`, we won't parse leading `!` or its escaped form.
10+
///
911
/// Returns `(pattern, mode, no_wildcard_len)`
10-
pub fn pattern(mut pat: &[u8]) -> Option<(&[u8], pattern::Mode, Option<usize>)> {
12+
pub fn pattern(mut pat: &[u8], may_alter: bool) -> Option<(&[u8], pattern::Mode, Option<usize>)> {
1113
let mut mode = Mode::empty();
1214
if pat.is_empty() {
1315
return None;
1416
};
15-
if pat.first() == Some(&b'!') {
16-
mode |= Mode::NEGATIVE;
17-
pat = &pat[1..];
18-
} else if pat.first() == Some(&b'\\') {
19-
let second = pat.get(1);
20-
if second == Some(&b'!') || second == Some(&b'#') {
17+
if may_alter {
18+
if pat.first() == Some(&b'!') {
19+
mode |= Mode::NEGATIVE;
2120
pat = &pat[1..];
21+
} else if pat.first() == Some(&b'\\') {
22+
let second = pat.get(1);
23+
if second == Some(&b'!') || second == Some(&b'#') {
24+
pat = &pat[1..];
25+
}
2226
}
2327
}
2428
if pat.iter().all(u8::is_ascii_whitespace) {

gix-glob/src/pattern.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,18 @@ pub enum Case {
4444
impl Pattern {
4545
/// Parse the given `text` as pattern, or return `None` if `text` was empty.
4646
pub fn from_bytes(text: &[u8]) -> Option<Self> {
47-
crate::parse::pattern(text).map(|(text, mode, first_wildcard_pos)| Pattern {
47+
crate::parse::pattern(text, true).map(|(text, mode, first_wildcard_pos)| Pattern {
48+
text: text.into(),
49+
mode,
50+
first_wildcard_pos,
51+
})
52+
}
53+
54+
/// Parse the given `text` as pattern without supporting leading `!` or `\\!` , or return `None` if `text` was empty.
55+
///
56+
/// This assures that `text` remains entirely unaltered, but removes built-in support for negation as well.
57+
pub fn from_bytes_without_negation(text: &[u8]) -> Option<Self> {
58+
crate::parse::pattern(text, false).map(|(text, mode, first_wildcard_pos)| Pattern {
4859
text: text.into(),
4960
mode,
5061
first_wildcard_pos,

gix-glob/tests/parse/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,21 @@ fn leading_exclamation_mark_negates_pattern() {
6666
gix_glob::parse(b"!hello"),
6767
pat("hello", Mode::NEGATIVE | Mode::NO_SUB_DIR, None)
6868
);
69+
assert_eq!(
70+
gix_glob::Pattern::from_bytes_without_negation(b"!hello"),
71+
pat("!hello", Mode::NO_SUB_DIR, None),
72+
"negation can be disabled entirely"
73+
);
6974
}
7075

7176
#[test]
7277
fn leading_exclamation_marks_can_be_escaped_with_backslash() {
7378
assert_eq!(gix_glob::parse(br"\!hello"), pat("!hello", Mode::NO_SUB_DIR, None));
79+
assert_eq!(
80+
gix_glob::Pattern::from_bytes_without_negation(br"\!hello"),
81+
pat("\\!hello", Mode::NO_SUB_DIR, Some(0)),
82+
"negation can be disabled entirely, leaving escapes in place"
83+
);
7484
}
7585

7686
#[test]

0 commit comments

Comments
 (0)