Skip to content

Commit

Permalink
greatly improve brace handling (#427)
Browse files Browse the repository at this point in the history
It's more consistent, convenient and powerful.
  • Loading branch information
Byron committed Jun 7, 2022
1 parent 1bbd3f4 commit 546f4df
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 14 deletions.
10 changes: 8 additions & 2 deletions git-revision/src/spec/parse/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,20 @@ fn parens(input: &[u8]) -> Result<Option<InsideParensRestConsumed<'_>>, Error> {
}
}
b'\\' => {
skip_list.push(idx);
if ignore_next {
skip_list.pop();
ignore_next = false;
skip_list.push(idx);
} else {
ignore_next = true;
}
}
_ => ignore_next = false,
_ => {
if ignore_next {
skip_list.pop();
};
ignore_next = false
}
}
if open_braces == 0 {
let inner: std::borrow::Cow<'_, _> = if skip_list.is_empty() {
Expand Down
67 changes: 55 additions & 12 deletions git-revision/tests/spec/parse/navigate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,22 +104,56 @@ mod caret_symbol {
}

#[test]
fn backslashes_can_be_used_for_escaping_within_regexes() {
for (spec, regex) in [
(r#"@^{/with count\{1\}}"#, r#"with count\{1\}"#),
(r#"@^{/a1\}}"#, r#"a1\}"#),
(r#"@^{/a2\\}"#, r#"a2\"#),
(r#"@^{/a\\b\\c}"#, r#"a\b\c"#),
(r#"@^{/a\\b\\hello}"#, r#"a\b\hello"#),
(r#"@^{/a\\b\\{\\}}"#, r#"a\b\{\}"#),
(r#"@^{/a\\b\{\}}"#, r#"a\b\{\}"#),
(r#"@^{/c\\b{b{a}b}}"#, r#"c\b{b{a}b}"#),
fn regex_backslash_rules() {
for (spec, regex, msg) in [
(
r#"@^{/with count{1}}"#,
r#"with count{1}"#,
"matching inner parens do not need escaping",
),
(
r#"@^{/with count\{1\}}"#,
r#"with count{1}"#,
"escaped parens are entirely ignored",
),
(r#"@^{/1\}}"#, r#"1}"#, "unmatched closing parens need to be escaped"),
(r#"@^{/2\{}"#, r#"2{"#, "unmatched opening parens need to be escaped"),
(
r#"@^{/3{\{}}"#,
r#"3{{}"#,
"unmatched nested opening parens need to be escaped",
),
(
r#"@^{/4{\}}}"#,
r#"4{}}"#,
"unmatched nested closing parens need to be escaped",
),
(
r#"@^{/a\b\c}"#,
r#"a\b\c"#,
"single backslashes do not need to be escaped",
),
(
r#"@^{/a\b\c\\}"#,
r#"a\b\c\"#,
"single backslashes do not need to be escaped, trailing",
),
(
r#"@^{/a\\b\\c\\}"#,
r#"a\b\c\"#,
"backslashes can be escaped nonetheless, trailing",
),
(
r#"@^{/5\\{}}"#,
r#"5\{}"#,
"backslashes in front of parens must be escaped or they would unbalance the brace pair",
),
] {
let rec = parse(spec);
let rec = try_parse(spec).expect(msg);

assert!(rec.kind.is_none());
assert!(rec.find_ref[0].as_ref().is_some() || rec.prefix[0].is_some());
assert_eq!(rec.patterns, vec![(regex.into(), false)]);
assert_eq!(rec.patterns, vec![(regex.into(), false)], "{}", msg);
assert_eq!(rec.calls, 2);
}
}
Expand Down Expand Up @@ -182,6 +216,15 @@ mod caret_symbol {
assert!(matches!(err, spec::parse::Error::UnspecifiedRegexModifier {regex} if regex == "/!hello"));
}

#[test]
fn bad_escapes_can_cause_brace_mismatch() {
let err = try_parse(r#"@^{\}"#).unwrap_err();
assert!(matches!(err, spec::parse::Error::UnclosedBracePair {input} if input == r#"{\}"#));

let err = try_parse(r#"@^{{\}}"#).unwrap_err();
assert!(matches!(err, spec::parse::Error::UnclosedBracePair {input} if input == r#"{{\}}"#));
}

#[test]
fn empty_top_revision_regex_are_skipped_as_they_match_everything() {
let rec = parse("@^{/}");
Expand Down

0 comments on commit 546f4df

Please sign in to comment.