forked from mirrors/jj
gitignore: any character can be backslash-escaped
You may use "abc\\" in .gitignore to ignore a file named "abc\". In this case, removing training spaces on "abc\\ " must result in "abc\\" as the trailing space is not escaped, the preceeding backslash being part of the previous "\\" escaping sequence.
This commit is contained in:
parent
60d1537731
commit
84fc66fe50
2 changed files with 17 additions and 21 deletions
|
@ -74,6 +74,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
the jj repo from a Git repo. They will now be considered as non-existent if
|
||||
referenced explicitly instead of crashing.
|
||||
|
||||
* Fixed handling of escaped characters in .gitignore (only keep trailing spaces
|
||||
if escaped properly).
|
||||
|
||||
### Contributors
|
||||
|
||||
Thanks to the people who made this release happen!
|
||||
|
|
|
@ -27,33 +27,23 @@ struct GitIgnoreLine {
|
|||
}
|
||||
|
||||
impl GitIgnoreLine {
|
||||
// Remove trailing spaces (unless backslash-escaped)
|
||||
// Remove trailing spaces (unless backslash-escaped). Any character
|
||||
// can be backslash-escaped as well.
|
||||
fn remove_trailing_space(input: &str) -> &str {
|
||||
let mut trimmed_len = 0;
|
||||
let mut non_space_seen = false;
|
||||
let mut prev_was_space = false;
|
||||
let mut in_escape = false;
|
||||
let input = input.strip_suffix('\r').unwrap_or(input);
|
||||
for (i, c) in input.char_indices() {
|
||||
if !prev_was_space && non_space_seen {
|
||||
trimmed_len = i;
|
||||
let mut it = input.char_indices().rev().peekable();
|
||||
while let Some((i, c)) = it.next() {
|
||||
if c != ' ' {
|
||||
return &input[..i + c.len_utf8()];
|
||||
}
|
||||
if c == ' ' {
|
||||
if in_escape {
|
||||
in_escape = false;
|
||||
} else {
|
||||
prev_was_space = true;
|
||||
if matches!(it.peek(), Some((_, '\\'))) {
|
||||
if it.skip(1).take_while(|(_, b)| *b == '\\').count() % 2 == 1 {
|
||||
return &input[..i];
|
||||
}
|
||||
} else {
|
||||
non_space_seen = true;
|
||||
prev_was_space = false;
|
||||
in_escape = c == '\\'
|
||||
return &input[..i + 1];
|
||||
}
|
||||
}
|
||||
if !prev_was_space && non_space_seen {
|
||||
trimmed_len = input.len();
|
||||
}
|
||||
input.split_at(trimmed_len).0
|
||||
""
|
||||
}
|
||||
|
||||
fn parse(prefix: &str, input: &str) -> Option<GitIgnoreLine> {
|
||||
|
@ -347,6 +337,9 @@ mod tests {
|
|||
fn test_gitignore_whitespace() {
|
||||
assert!(!matches_file(b" \n", " "));
|
||||
assert!(matches_file(b"\\ \n", " "));
|
||||
assert!(matches_file(b"\\\\ \n", "\\"));
|
||||
assert!(!matches_file(b"\\\\ \n", " "));
|
||||
assert!(matches_file(b"\\\\\\ \n", "\\ "));
|
||||
assert!(matches_file(b" a\n", " a"));
|
||||
assert!(matches_file(b"a b\n", "a b"));
|
||||
assert!(matches_file(b"a b \n", "a b"));
|
||||
|
|
Loading…
Reference in a new issue