Make edit diffs more robust (#493)
This commit is contained in:
@@ -82,10 +82,19 @@ pub fn extract_unified_diff_hunks(unified_diff: &str) -> Vec<String> {
|
||||
.filter(|line| line.starts_with([' ', '+', '-']))
|
||||
.collect::<String>();
|
||||
|
||||
let old_count = lines
|
||||
.iter()
|
||||
.filter(|line| line.starts_with(['-', ' ']))
|
||||
.count();
|
||||
let new_count = lines
|
||||
.iter()
|
||||
.filter(|line| line.starts_with(['+', ' ']))
|
||||
.count();
|
||||
|
||||
return if hunk.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
vec!["@@\n".to_string() + &hunk]
|
||||
vec![format!("@@ -0,{old_count} +0,{new_count} @@\n{hunk}")]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -185,7 +194,12 @@ pub fn concatenate_diff_hunks(file_path: &str, hunks: &[String]) -> String {
|
||||
unified_diff.push_str(&header);
|
||||
|
||||
if !hunks.is_empty() {
|
||||
unified_diff.push_str(hunks.join("\n").as_str());
|
||||
let lines = hunks
|
||||
.iter()
|
||||
.flat_map(|hunk| hunk.lines())
|
||||
.filter(|line| line.starts_with("@@ ") || line.starts_with([' ', '+', '-']))
|
||||
.collect::<Vec<_>>();
|
||||
unified_diff.push_str(lines.join("\n").as_str());
|
||||
if !unified_diff.ends_with('\n') {
|
||||
unified_diff.push('\n');
|
||||
}
|
||||
|
||||
@@ -25,12 +25,9 @@ type Props = {
|
||||
* - Decide whether to hide line numbers based on backend data
|
||||
*/
|
||||
function processUnifiedDiff(unifiedDiff: string, hasLineNumbers: boolean) {
|
||||
const totalHunks = unifiedDiff
|
||||
.split('\n')
|
||||
.filter((line) => line.startsWith('@@ ')).length;
|
||||
|
||||
// Hide line numbers when backend says they are unreliable
|
||||
const hideNums = !hasLineNumbers;
|
||||
let isValidDiff;
|
||||
|
||||
// Pre-compute additions/deletions using the library parser so counts are available while collapsed
|
||||
let additions = 0;
|
||||
@@ -43,16 +40,18 @@ function processUnifiedDiff(unifiedDiff: string, hasLineNumbers: boolean) {
|
||||
else if (line.type === DiffLineType.Delete) deletions++;
|
||||
}
|
||||
}
|
||||
isValidDiff = parsed.hunks.length > 0;
|
||||
} catch (err) {
|
||||
console.error('Failed to parse diff hunks:', err);
|
||||
isValidDiff = false;
|
||||
}
|
||||
|
||||
return {
|
||||
hunks: [unifiedDiff],
|
||||
hideLineNumbers: hideNums,
|
||||
totalHunks,
|
||||
additions,
|
||||
deletions,
|
||||
isValidDiff,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -65,7 +64,7 @@ function EditDiffRenderer({ path, unifiedDiff, hasLineNumbers }: Props) {
|
||||
theme = 'dark';
|
||||
}
|
||||
|
||||
const { hunks, hideLineNumbers, totalHunks, additions, deletions } = useMemo(
|
||||
const { hunks, hideLineNumbers, additions, deletions, isValidDiff } = useMemo(
|
||||
() => processUnifiedDiff(unifiedDiff, hasLineNumbers),
|
||||
[path, unifiedDiff, hasLineNumbers]
|
||||
);
|
||||
@@ -112,16 +111,27 @@ function EditDiffRenderer({ path, unifiedDiff, hasLineNumbers }: Props) {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{expanded && totalHunks > 0 && (
|
||||
{expanded && (
|
||||
<div className={'mt-2' + hideLineNumbersClass}>
|
||||
<DiffView
|
||||
data={diffData}
|
||||
diffViewWrap={false}
|
||||
diffViewTheme={theme}
|
||||
diffViewHighlight
|
||||
diffViewMode={DiffModeEnum.Unified}
|
||||
diffViewFontSize={12}
|
||||
/>
|
||||
{isValidDiff ? (
|
||||
<DiffView
|
||||
data={diffData}
|
||||
diffViewWrap={false}
|
||||
diffViewTheme={theme}
|
||||
diffViewHighlight
|
||||
diffViewMode={DiffModeEnum.Unified}
|
||||
diffViewFontSize={12}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<pre
|
||||
className="px-4 pb-4 text-xs font-mono overflow-x-auto whitespace-pre-wrap"
|
||||
style={{ color: 'hsl(var(--muted-foreground) / 0.9)' }}
|
||||
>
|
||||
{unifiedDiff}
|
||||
</pre>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user