unmanage diff.zig (#680)
This commit is contained in:
parent
a70beba6d2
commit
8eeae02865
@ -1993,7 +1993,7 @@ fn formattingHandler(server: *Server, writer: anytype, id: types.RequestId, req:
|
|||||||
.Exited => |code| if (code == 0) {
|
.Exited => |code| if (code == 0) {
|
||||||
if (std.mem.eql(u8, handle.document.text, stdout_bytes)) return try respondGeneric(writer, id, null_result_response);
|
if (std.mem.eql(u8, handle.document.text, stdout_bytes)) return try respondGeneric(writer, id, null_result_response);
|
||||||
|
|
||||||
var edits = diff.edits(server.allocator, handle.document.text, stdout_bytes) catch {
|
var edits = diff.edits(server.arena.allocator(), handle.document.text, stdout_bytes) catch {
|
||||||
const range = offsets.locToRange(handle.document.text, .{ .start = 0, .end = handle.document.text.len }, server.offset_encoding);
|
const range = offsets.locToRange(handle.document.text, .{ .start = 0, .end = handle.document.text.len }, server.offset_encoding);
|
||||||
// If there was an error trying to diff the text, return the formatted response
|
// If there was an error trying to diff the text, return the formatted response
|
||||||
// as the new text for the entire range of the document
|
// as the new text for the entire range of the document
|
||||||
@ -2009,18 +2009,11 @@ fn formattingHandler(server: *Server, writer: anytype, id: types.RequestId, req:
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
defer {
|
|
||||||
for (edits.items) |item| item.newText.deinit();
|
|
||||||
edits.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert from `[]diff.Edit` to `[]types.TextEdit`
|
// Convert from `[]diff.Edit` to `[]types.TextEdit`
|
||||||
var text_edits = try std
|
var text_edits = try std.ArrayListUnmanaged(types.TextEdit).initCapacity(server.arena.allocator(), edits.items.len);
|
||||||
.ArrayList(types.TextEdit)
|
|
||||||
.initCapacity(server.allocator, edits.items.len);
|
|
||||||
defer text_edits.deinit();
|
|
||||||
for (edits.items) |edit| {
|
for (edits.items) |edit| {
|
||||||
try text_edits.append(.{
|
text_edits.appendAssumeCapacity(.{
|
||||||
.range = edit.range,
|
.range = edit.range,
|
||||||
.newText = edit.newText.items,
|
.newText = edit.newText.items,
|
||||||
});
|
});
|
||||||
|
53
src/diff.zig
53
src/diff.zig
@ -1,11 +1,13 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const types = @import("types.zig");
|
const types = @import("types.zig");
|
||||||
|
|
||||||
|
pub const Error = error{ OutOfMemory, InvalidRange };
|
||||||
|
|
||||||
// This is essentially the same as `types.TextEdit`, but we use an
|
// This is essentially the same as `types.TextEdit`, but we use an
|
||||||
// ArrayList(u8) here to be able to clean up the memory later on
|
// ArrayList(u8) here to be able to clean up the memory later on
|
||||||
pub const Edit = struct {
|
pub const Edit = struct {
|
||||||
range: types.Range,
|
range: types.Range,
|
||||||
newText: std.ArrayList(u8),
|
newText: std.ArrayListUnmanaged(u8),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Whether the `Change` is an addition, deletion, or no change from the
|
// Whether the `Change` is an addition, deletion, or no change from the
|
||||||
@ -25,7 +27,7 @@ pub fn edits(
|
|||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
a: []const u8,
|
a: []const u8,
|
||||||
b: []const u8,
|
b: []const u8,
|
||||||
) !std.ArrayList(Edit) {
|
) Error!std.ArrayListUnmanaged(Edit) {
|
||||||
// Given the input strings A and B, we skip over the first N characters
|
// Given the input strings A and B, we skip over the first N characters
|
||||||
// where A[0..N] == B[0..N]. We want to trim the start (and end) of the
|
// where A[0..N] == B[0..N]. We want to trim the start (and end) of the
|
||||||
// strings that have the same text. This decreases the size of the LCS
|
// strings that have the same text. This decreases the size of the LCS
|
||||||
@ -122,7 +124,7 @@ pub const Array2D = struct {
|
|||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
rows: usize,
|
rows: usize,
|
||||||
cols: usize,
|
cols: usize,
|
||||||
) !Self {
|
) error{OutOfMemory}!Self {
|
||||||
const data = try allocator.alloc(usize, rows * cols);
|
const data = try allocator.alloc(usize, rows * cols);
|
||||||
|
|
||||||
return Self{
|
return Self{
|
||||||
@ -183,11 +185,11 @@ pub fn get_changes(
|
|||||||
a_trim: []const u8,
|
a_trim: []const u8,
|
||||||
b_trim: []const u8,
|
b_trim: []const u8,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
) !std.ArrayList(Edit) {
|
) Error!std.ArrayListUnmanaged(Edit) {
|
||||||
// First we get a list of changes between strings at the character level:
|
// First we get a list of changes between strings at the character level:
|
||||||
// "addition", "deletion", and "no change" for each character
|
// "addition", "deletion", and "no change" for each character
|
||||||
var changes = try std.ArrayList(Change).initCapacity(allocator, a_trim.len);
|
var changes = try std.ArrayListUnmanaged(Change).initCapacity(allocator, a_trim.len);
|
||||||
defer changes.deinit();
|
defer changes.deinit(allocator);
|
||||||
try recur_changes(
|
try recur_changes(
|
||||||
lcs,
|
lcs,
|
||||||
&changes,
|
&changes,
|
||||||
@ -195,13 +197,15 @@ pub fn get_changes(
|
|||||||
b_trim,
|
b_trim,
|
||||||
@intCast(i64, a_trim.len),
|
@intCast(i64, a_trim.len),
|
||||||
@intCast(i64, b_trim.len),
|
@intCast(i64, b_trim.len),
|
||||||
|
allocator,
|
||||||
);
|
);
|
||||||
|
|
||||||
// We want to group runs of deletions and additions, and separate them by
|
// We want to group runs of deletions and additions, and separate them by
|
||||||
// runs of `.Nothing` changes. This will allow us to calculate the
|
// runs of `.Nothing` changes. This will allow us to calculate the
|
||||||
// `TextEdit` ranges
|
// `TextEdit` ranges
|
||||||
var groups = std.ArrayList([]Change).init(allocator);
|
var groups = std.ArrayListUnmanaged([]Change){};
|
||||||
defer groups.deinit();
|
defer groups.deinit(allocator);
|
||||||
|
|
||||||
var active_change: ?[]Change = null;
|
var active_change: ?[]Change = null;
|
||||||
for (changes.items) |ch, i| {
|
for (changes.items) |ch, i| {
|
||||||
switch (ch.operation) {
|
switch (ch.operation) {
|
||||||
@ -213,7 +217,7 @@ pub fn get_changes(
|
|||||||
.Nothing => {
|
.Nothing => {
|
||||||
if (active_change) |*ac| {
|
if (active_change) |*ac| {
|
||||||
ac.* = ac.*[0..(i - (changes.items.len - ac.*.len))];
|
ac.* = ac.*[0..(i - (changes.items.len - ac.*.len))];
|
||||||
try groups.append(ac.*);
|
try groups.append(allocator, ac.*);
|
||||||
active_change = null;
|
active_change = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -221,7 +225,7 @@ pub fn get_changes(
|
|||||||
}
|
}
|
||||||
if (active_change) |*ac| {
|
if (active_change) |*ac| {
|
||||||
ac.* = ac.*[0..(changes.items.len - (changes.items.len - ac.*.len))];
|
ac.* = ac.*[0..(changes.items.len - (changes.items.len - ac.*.len))];
|
||||||
try groups.append(ac.*);
|
try groups.append(allocator, ac.*);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The LCS algorithm works "in reverse", so we're putting everything back
|
// The LCS algorithm works "in reverse", so we're putting everything back
|
||||||
@ -230,17 +234,17 @@ pub fn get_changes(
|
|||||||
std.mem.reverse([]Change, groups.items);
|
std.mem.reverse([]Change, groups.items);
|
||||||
for (groups.items) |group| std.mem.reverse(Change, group);
|
for (groups.items) |group| std.mem.reverse(Change, group);
|
||||||
|
|
||||||
var edit_results = std.ArrayList(Edit).init(allocator);
|
var edit_results = std.ArrayListUnmanaged(Edit){};
|
||||||
errdefer edit_results.deinit();
|
errdefer edit_results.deinit(allocator);
|
||||||
|
|
||||||
// Convert our grouped changes into `Edit`s
|
// Convert our grouped changes into `Edit`s
|
||||||
for (groups.items) |group| {
|
for (groups.items) |group| {
|
||||||
var range_start = group[0].pos;
|
var range_start = group[0].pos;
|
||||||
var range_len: usize = 0;
|
var range_len: usize = 0;
|
||||||
var newText = std.ArrayList(u8).init(allocator);
|
var newText = std.ArrayListUnmanaged(u8){};
|
||||||
for (group) |ch| {
|
for (group) |ch| {
|
||||||
switch (ch.operation) {
|
switch (ch.operation) {
|
||||||
.Addition => try newText.append(ch.value.?),
|
.Addition => try newText.append(allocator, ch.value.?),
|
||||||
.Deletion => range_len += 1,
|
.Deletion => range_len += 1,
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@ -251,7 +255,7 @@ pub fn get_changes(
|
|||||||
a_trim_offset + range_start + range_len,
|
a_trim_offset + range_start + range_len,
|
||||||
);
|
);
|
||||||
a_lines.reset();
|
a_lines.reset();
|
||||||
try edit_results.append(Edit{
|
try edit_results.append(allocator, Edit{
|
||||||
.range = range,
|
.range = range,
|
||||||
.newText = newText,
|
.newText = newText,
|
||||||
});
|
});
|
||||||
@ -262,12 +266,13 @@ pub fn get_changes(
|
|||||||
|
|
||||||
fn recur_changes(
|
fn recur_changes(
|
||||||
lcs: *Array2D,
|
lcs: *Array2D,
|
||||||
changes: *std.ArrayList(Change),
|
changes: *std.ArrayListUnmanaged(Change),
|
||||||
a: []const u8,
|
a: []const u8,
|
||||||
b: []const u8,
|
b: []const u8,
|
||||||
i: i64,
|
i: i64,
|
||||||
j: i64,
|
j: i64,
|
||||||
) anyerror!void {
|
allocator: std.mem.Allocator,
|
||||||
|
) error{OutOfMemory}!void {
|
||||||
// This function recursively works backwards through the LCS table in
|
// This function recursively works backwards through the LCS table in
|
||||||
// order to figure out what kind of changes took place to transform `a`
|
// order to figure out what kind of changes took place to transform `a`
|
||||||
// into `b`
|
// into `b`
|
||||||
@ -276,26 +281,26 @@ fn recur_changes(
|
|||||||
const jj = @intCast(usize, j);
|
const jj = @intCast(usize, j);
|
||||||
|
|
||||||
if (i > 0 and j > 0 and a[ii - 1] == b[jj - 1]) {
|
if (i > 0 and j > 0 and a[ii - 1] == b[jj - 1]) {
|
||||||
try changes.append(.{
|
try changes.append(allocator, .{
|
||||||
.operation = .Nothing,
|
.operation = .Nothing,
|
||||||
.pos = ii - 1,
|
.pos = ii - 1,
|
||||||
.value = null,
|
.value = null,
|
||||||
});
|
});
|
||||||
try recur_changes(lcs, changes, a, b, i - 1, j - 1);
|
try recur_changes(lcs, changes, a, b, i - 1, j - 1, allocator);
|
||||||
} else if (j > 0 and (i == 0 or lcs.get(ii, jj - 1).* >= lcs.get(ii - 1, jj).*)) {
|
} else if (j > 0 and (i == 0 or lcs.get(ii, jj - 1).* >= lcs.get(ii - 1, jj).*)) {
|
||||||
try changes.append(.{
|
try changes.append(allocator, .{
|
||||||
.operation = .Addition,
|
.operation = .Addition,
|
||||||
.pos = ii,
|
.pos = ii,
|
||||||
.value = b[jj - 1],
|
.value = b[jj - 1],
|
||||||
});
|
});
|
||||||
try recur_changes(lcs, changes, a, b, i, j - 1);
|
try recur_changes(lcs, changes, a, b, i, j - 1, allocator);
|
||||||
} else if (i > 0 and (j == 0 or lcs.get(ii, jj - 1).* < lcs.get(ii - 1, jj).*)) {
|
} else if (i > 0 and (j == 0 or lcs.get(ii, jj - 1).* < lcs.get(ii - 1, jj).*)) {
|
||||||
try changes.append(.{
|
try changes.append(allocator, .{
|
||||||
.operation = .Deletion,
|
.operation = .Deletion,
|
||||||
.pos = ii - 1,
|
.pos = ii - 1,
|
||||||
.value = a[ii - 1],
|
.value = a[ii - 1],
|
||||||
});
|
});
|
||||||
try recur_changes(lcs, changes, a, b, i - 1, j);
|
try recur_changes(lcs, changes, a, b, i - 1, j, allocator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +310,7 @@ fn char_pos_to_range(
|
|||||||
lines: *std.mem.SplitIterator(u8),
|
lines: *std.mem.SplitIterator(u8),
|
||||||
start: usize,
|
start: usize,
|
||||||
end: usize,
|
end: usize,
|
||||||
) !types.Range {
|
) Error!types.Range {
|
||||||
var char_pos: usize = 0;
|
var char_pos: usize = 0;
|
||||||
var line_pos: usize = 0;
|
var line_pos: usize = 0;
|
||||||
var result_start_pos: ?types.Position = null;
|
var result_start_pos: ?types.Position = null;
|
||||||
|
Loading…
Reference in New Issue
Block a user