fix: correct diff parsing for better gutter representation of changes

This commit is contained in:
Miguel Granero 2026-01-30 16:51:10 +01:00 committed by CJ van den Berg
parent f65082bea9
commit 674c1b0a83

View file

@ -120,7 +120,7 @@ pub fn diff(allocator: std.mem.Allocator, dst: []const u8, src: []const u8) erro
const dmp = diffz.default; const dmp = diffz.default;
var diff_list = try diffz.diff(&dmp, arena, src, dst, false); var diff_list = try diffz.diff(&dmp, arena, src, dst, false);
try diffz.diffCleanupSemantic(arena, &diff_list); try diffz.diffCleanupSemanticLossless(arena, &diff_list);
if (diff_list.items.len > 2) if (diff_list.items.len > 2)
try diffs.ensureTotalCapacity(allocator, (diff_list.items.len - 1) / 2); try diffs.ensureTotalCapacity(allocator, (diff_list.items.len - 1) / 2);
@ -128,53 +128,89 @@ pub fn diff(allocator: std.mem.Allocator, dst: []const u8, src: []const u8) erro
var lines_dst: usize = 0; var lines_dst: usize = 0;
var pos_dst: usize = 0; var pos_dst: usize = 0;
var last_offset: usize = 0; var last_offset: usize = 0;
var last_equal_char: u8 = 0;
for (diff_list.items) |diffz_diff| { for (diff_list.items) |diffz_diff| {
switch (diffz_diff.operation) { switch (diffz_diff.operation) {
.equal => { .equal => {
const dist = diffz_diff.text.len; const dist = diffz_diff.text.len;
pos_dst += dist; pos_dst += dist;
scan_eol(diffz_diff.text, &lines_dst, &last_offset); scan_eol(diffz_diff.text, &lines_dst, &last_offset);
last_equal_char = diffz_diff.text[diffz_diff.text.len - 1];
}, },
.insert => { .insert => {
const dist = diffz_diff.text.len; const dist = diffz_diff.text.len;
pos_dst += dist; pos_dst += dist;
const line_start_dst: usize = lines_dst; var line_start_dst: usize = lines_dst;
scan_eol(diffz_diff.text, &lines_dst, &last_offset); scan_eol(diffz_diff.text, &lines_dst, &last_offset);
(try diffs.addOne(allocator)).* = .{ const n_lines = lines_dst - line_start_dst;
.kind = .insert,
.line = line_start_dst, if (n_lines == 0) {
.lines = lines_dst - line_start_dst,
};
if (last_offset > 0)
(try diffs.addOne(allocator)).* = .{ (try diffs.addOne(allocator)).* = .{
.kind = .modify, .kind = .modify,
.line = line_start_dst, .line = line_start_dst,
.lines = 1, .lines = 1,
}; };
} else {
if (diffz_diff.text[0] != '\n') {
(try diffs.addOne(allocator)).* = .{
.kind = .modify,
.line = line_start_dst,
.lines = 1,
};
line_start_dst += 1;
}
(try diffs.addOne(allocator)).* = .{
.kind = .insert,
.line = line_start_dst,
.lines = n_lines,
};
line_start_dst += n_lines;
if (last_offset > 0) {
(try diffs.addOne(allocator)).* = .{
.kind = .modify,
.line = line_start_dst,
.lines = 1,
};
}
}
}, },
.delete => { .delete => {
pos_dst += 0; pos_dst += 0;
var lines: usize = 0; var lines: usize = 0;
var diff_offset: usize = 0; var diff_offset: usize = 0;
var line_start_dst: usize = lines_dst;
scan_eol(diffz_diff.text, &lines, &diff_offset); scan_eol(diffz_diff.text, &lines, &diff_offset);
if (lines == 0) {
(try diffs.addOne(allocator)).* = .{ (try diffs.addOne(allocator)).* = .{
.kind = .modify, .kind = .modify,
.line = lines_dst, .line = line_start_dst,
.lines = 1, .lines = 1,
}; };
if (lines > 0) } else {
if (last_equal_char != '\n') {
// Deleting starts in previous line
(try diffs.addOne(allocator)).* = .{
.kind = .modify,
.line = line_start_dst,
.lines = 1,
};
line_start_dst += 1;
}
(try diffs.addOne(allocator)).* = .{ (try diffs.addOne(allocator)).* = .{
.kind = .delete, .kind = .delete,
.line = lines_dst, .line = line_start_dst,
.lines = lines,
};
if (lines > 0 and diff_offset > 0)
(try diffs.addOne(allocator)).* = .{
.kind = .modify,
.line = lines_dst,
.lines = 1, .lines = 1,
}; };
if (diff_offset > 0 and last_equal_char == '\n') {
(try diffs.addOne(allocator)).* = .{
.kind = .modify,
.line = line_start_dst,
.lines = 1,
};
}
}
}, },
} }
} }