From 91288fa6a136e45bedaee6da0ac0648e492aba13 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 13 Jan 2026 20:36:11 +0100 Subject: [PATCH] fix: gutters should only accept diff updates for their attached editor --- src/diffz.zig | 20 ++++++++++++-------- src/tui/editor_gutter.zig | 37 +++++++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/diffz.zig b/src/diffz.zig index b6383fe..ffa27a7 100644 --- a/src/diffz.zig +++ b/src/diffz.zig @@ -32,9 +32,9 @@ pub const AsyncDiffer = struct { return text.toOwnedSlice(); } - pub const CallBack = fn (from: tp.pid_ref, edits: []Diff) void; + pub const CallBack = fn (from: tp.pid_ref, data: usize, edits: []Diff) void; - pub fn diff_buffer(self: @This(), cb: *const CallBack, buffer: *const Buffer) tp.result { + pub fn diff_buffer(self: @This(), cb: *const CallBack, cb_data: usize, buffer: *const Buffer) tp.result { const eol_mode = buffer.file_eol_mode; const text_dst = text_from_root(buffer.root, eol_mode) catch |e| return tp.exit_error(e, @errorReturnTrace()); errdefer std.heap.c_allocator.free(text_dst); @@ -45,7 +45,7 @@ pub const AsyncDiffer = struct { errdefer std.heap.c_allocator.free(text_src); const text_dst_ptr: usize = if (text_dst.len > 0) @intFromPtr(text_dst.ptr) else 0; const text_src_ptr: usize = if (text_src.len > 0) @intFromPtr(text_src.ptr) else 0; - if (self.pid) |pid| try pid.send(.{ "D", @intFromPtr(cb), text_dst_ptr, text_dst.len, text_src_ptr, text_src.len }); + if (self.pid) |pid| try pid.send(.{ "D", @intFromPtr(cb), cb_data, text_dst_ptr, text_dst.len, text_src_ptr, text_src.len }); } }; @@ -77,30 +77,34 @@ const Process = struct { errdefer self.deinit(); var cb: usize = 0; + var cb_data: usize = 0; var text_dst_ptr: usize = 0; var text_dst_len: usize = 0; var text_src_ptr: usize = 0; var text_src_len: usize = 0; - return if (try m.match(.{ "D", tp.extract(&cb), tp.extract(&text_dst_ptr), tp.extract(&text_dst_len), tp.extract(&text_src_ptr), tp.extract(&text_src_len) })) blk: { + return if (try m.match(.{ "D", tp.extract(&cb), tp.extract(&cb_data), tp.extract(&text_dst_ptr), tp.extract(&text_dst_len), tp.extract(&text_src_ptr), tp.extract(&text_src_len) })) blk: { const text_dst = if (text_dst_len > 0) @as([*]const u8, @ptrFromInt(text_dst_ptr))[0..text_dst_len] else ""; const text_src = if (text_src_len > 0) @as([*]const u8, @ptrFromInt(text_src_ptr))[0..text_src_len] else ""; - break :blk do_diff_async(from, cb, text_dst, text_src) catch |e| tp.exit_error(e, @errorReturnTrace()); + const cb_: *AsyncDiffer.CallBack = if (cb == 0) return else @ptrFromInt(cb); + break :blk do_diff_async(from, cb_, cb_data, text_dst, text_src) catch |e| { + cb_(from, cb_data, &.{}); + break :blk tp.exit_error(e, @errorReturnTrace()); + }; } else if (try m.match(.{"shutdown"})) tp.exit_normal(); } - fn do_diff_async(from_: tp.pid_ref, cb_addr: usize, text_dst: []const u8, text_src: []const u8) !void { + fn do_diff_async(from: tp.pid_ref, cb: *AsyncDiffer.CallBack, cb_data: usize, text_dst: []const u8, text_src: []const u8) !void { defer std.heap.c_allocator.free(text_dst); defer std.heap.c_allocator.free(text_src); - const cb_: *AsyncDiffer.CallBack = if (cb_addr == 0) return else @ptrFromInt(cb_addr); var arena_ = std.heap.ArenaAllocator.init(allocator); defer arena_.deinit(); const arena = arena_.allocator(); const edits = try diff(arena, text_dst, text_src); - cb_(from_, edits); + cb(from, cb_data, edits); } }; diff --git a/src/tui/editor_gutter.zig b/src/tui/editor_gutter.zig index b7f9dc3..edff20c 100644 --- a/src/tui/editor_gutter.zig +++ b/src/tui/editor_gutter.zig @@ -368,18 +368,36 @@ fn diff_update(self: *Self, clear: bool) !void { self.diff_symbols_clear(); return; } - return self.differ.diff_buffer(diff_result, self.editor.buffer orelse return); + const ctx = try self.allocator.create(DiffContext); + ctx.* = .{ + .allocator = self.allocator, + .file_path = try self.allocator.dupe(u8, self.editor.file_path orelse ""), + }; + return self.differ.diff_buffer(diff_result, @intFromPtr(ctx), self.editor.buffer orelse return); } -fn diff_result(from: tp.pid_ref, edits: []Diff) void { - diff_result_send(from, edits) catch |e| @import("log").err(@typeName(Self), "diff", e); +const DiffContext = struct { + allocator: std.mem.Allocator, + file_path: []u8, + + fn deinit(self: *@This()) void { + self.allocator.free(self.file_path); + self.allocator.destroy(self); + } +}; + +fn diff_result(from: tp.pid_ref, data: usize, edits: []Diff) void { + const ctx: *DiffContext = @ptrFromInt(data); + defer ctx.deinit(); + diff_result_send(from, ctx, edits) catch |e| @import("log").err(@typeName(Self), "diff", e); } -fn diff_result_send(from: tp.pid_ref, edits: []Diff) !void { +fn diff_result_send(from: tp.pid_ref, ctx: *DiffContext, edits: []Diff) !void { var buf: std.Io.Writer.Allocating = .init(std.heap.c_allocator); defer buf.deinit(); - try cbor.writeArrayHeader(&buf.writer, 2); + try cbor.writeArrayHeader(&buf.writer, 3); try cbor.writeValue(&buf.writer, "DIFF"); + try cbor.writeValue(&buf.writer, ctx.file_path); try cbor.writeArrayHeader(&buf.writer, edits.len); for (edits) |edit| { try cbor.writeArrayHeader(&buf.writer, 3); @@ -421,10 +439,13 @@ fn process_edit(self: *Self, kind: Kind, line: usize, lines: usize) !void { } pub fn filter_receive(self: *Self, _: tp.pid_ref, m: tp.message) MessageFilter.Error!bool { + var file_path: []const u8 = undefined; var cb: []const u8 = undefined; - if (cbor.match(m.buf, .{ "DIFF", tp.extract_cbor(&cb) }) catch false) { - try self.process_diff(cb); - return true; + if (cbor.match(m.buf, .{ "DIFF", tp.extract(&file_path), tp.extract_cbor(&cb) }) catch false) { + if (std.mem.eql(u8, file_path, self.editor.file_path orelse return false)) { + try self.process_diff(cb); + return true; + } } return false; }