From 2d1cb201ab1e3c6ebd8f5a6e9209ec5bdcb4d39a Mon Sep 17 00:00:00 2001 From: Thomas Otto Date: Mon, 2 Sep 2024 23:12:19 +0200 Subject: [PATCH] Handle quoted file paths in hunk headers When core.quotepath is true (the default) then non-ASCII chars in a file name are quoted. These quotes hide the DIFF_PREFIXES and "a/1" "b/1" remains as such, instead of becoming "1" "1". This was interpreted by delta as renamed file. Now these quotes are removed before the DIFF_PREFIXES are searched. --- src/handlers/diff_header.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/handlers/diff_header.rs b/src/handlers/diff_header.rs index fed515251..99da998da 100644 --- a/src/handlers/diff_header.rs +++ b/src/handlers/diff_header.rs @@ -374,7 +374,11 @@ fn remove_surrounding_quotes(path: &str) -> &str { } } -fn _parse_file_path(s: &str, git_diff_name: bool) -> String { +fn _parse_file_path(path: &str, git_diff_name: bool) -> String { + // When git config 'core.quotepath = true' (the default), and `path` contains + // non-ASCII characters, a backslash, or a quote; then it is quoted, so remove + // these quotes. Characters may also be escaped, but these are left as-is. + let path = remove_surrounding_quotes(path); // It appears that, if the file name contains a space, git appends a tab // character in the diff metadata lines, e.g. // $ git diff --no-index "a b" "c d" | cat -A @@ -382,15 +386,13 @@ fn _parse_file_path(s: &str, git_diff_name: bool) -> String { // index·d00491f..0cfbf08·100644␊ // ---·a/a·b├──┤␊ // +++·b/c·d├──┤␊ - let path = match s.strip_suffix('\t').unwrap_or(s) { + match path.strip_suffix('\t').unwrap_or(path) { "/dev/null" => "/dev/null", path if git_diff_name && DIFF_PREFIXES.iter().any(|s| path.starts_with(s)) => &path[2..], path if git_diff_name => path, path => path.split('\t').next().unwrap_or(""), - }; - // When a path contains non-ASCII characters, a backslash, or a quote then it is quoted, - // so remove these quotes. Characters may also be escaped, but these are left as-is. - remove_surrounding_quotes(path).to_string() + } + .to_string() } pub fn get_file_change_description_from_file_paths( @@ -638,6 +640,10 @@ mod tests { "diff --git a/.config/Code - Insiders/User/settings.json b/.config/Code - Insiders/User/settings.json"), Some(".config/Code - Insiders/User/settings.json".to_string()) ); + assert_eq!( + get_repeated_file_path_from_diff_line(r#"diff --git "a/quoted" "b/quoted""#), + Some("quoted".to_string()) + ); } pub const BIN_AND_TXT_FILE_ADDED: &str = "\