From 6a2228e19d52fb589bf34afc9491826832492c10 Mon Sep 17 00:00:00 2001 From: xdBronch <51252236+xdBronch@users.noreply.github.com> Date: Sat, 10 Jan 2026 20:48:22 -0500 Subject: [PATCH] fix documentHighlight missing references --- src/Project.zig | 135 +++++++++++++++++++++++++++++++------------ src/tui/editor.zig | 1 + src/tui/mainview.zig | 2 +- 3 files changed, 101 insertions(+), 37 deletions(-) diff --git a/src/Project.zig b/src/Project.zig index 0948544..46c72d9 100644 --- a/src/Project.zig +++ b/src/Project.zig @@ -1082,42 +1082,6 @@ pub fn references(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usi }, handler) catch return error.LspFailed; } -pub fn highlight_references(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) SendGotoRequestError!void { - const lsp = try self.get_language_server(file_path); - const uri = try self.make_URI(file_path); - defer self.allocator.free(uri); - - const handler: struct { - from: tp.pid, - name: []const u8, - project: *Self, - - pub fn deinit(self_: *@This()) void { - std.heap.c_allocator.free(self_.name); - self_.from.deinit(); - } - - pub fn receive(self_: @This(), response: tp.message) !void { - var locations: []const u8 = undefined; - if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) { - return; - } else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.extract_cbor(&locations) })) { - _ = try send_reference_list("HREF", self_.from.ref(), locations, self_.name); - } - } - } = .{ - .from = from.clone(), - .name = try std.heap.c_allocator.dupe(u8, self.name), - .project = self, - }; - - lsp.send_request(self.allocator, "textDocument/references", .{ - .textDocument = .{ .uri = uri }, - .position = .{ .line = row, .character = col }, - .context = .{ .includeDeclaration = true }, - }, handler) catch return error.LspFailed; -} - fn send_reference_list(tag: []const u8, to: tp.pid_ref, locations: []const u8, name: []const u8) (error{ InvalidTargetURI, InvalidReferenceList, @@ -1161,6 +1125,105 @@ fn send_reference(tag: []const u8, to: tp.pid_ref, location_: []const u8, name: }; } +pub fn highlight_references(self: *Self, from: tp.pid_ref, file_path: []const u8, row: usize, col: usize) SendGotoRequestError!void { + const lsp = try self.get_language_server(file_path); + const uri = try self.make_URI(file_path); + defer self.allocator.free(uri); + + const handler: struct { + from: tp.pid, + + pub fn deinit(self_: *@This()) void { + self_.from.deinit(); + } + + pub fn receive(self_: @This(), response: tp.message) !void { + var highlights: []const u8 = undefined; + if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.null_ })) { + return; + } else if (try cbor.match(response.buf, .{ "child", tp.string, "result", tp.extract_cbor(&highlights) })) { + _ = try send_highlight_list(self_.from.ref(), highlights); + } + } + } = .{ + .from = from.clone(), + }; + + lsp.send_request(self.allocator, "textDocument/documentHighlight", .{ + .textDocument = .{ .uri = uri }, + .position = .{ .line = row, .character = col }, + .context = .{ .includeDeclaration = true }, + }, handler) catch return error.LspFailed; +} + +fn send_highlight_list(to: tp.pid_ref, highlights: []const u8) (error{InvalidDocumentHighlightList} || DocumentHighlightError)!usize { + defer to.send(.{ "HREF", "done" }) catch {}; + var iter = highlights; + var len = try cbor.decodeArrayHeader(&iter); + const count = len; + while (len > 0) : (len -= 1) { + var highlight: []const u8 = undefined; + if (try cbor.matchValue(&iter, cbor.extract_cbor(&highlight))) { + try send_highlight(to, highlight); + } else return error.InvalidDocumentHighlightList; + } + return count; +} + +fn send_highlight(to: tp.pid_ref, highlight_: []const u8) DocumentHighlightError!void { + const highlight = try read_document_highlight(highlight_); + to.send(.{ + "HREF", + highlight.range.start.line + 1, + highlight.range.start.character, + highlight.range.end.line + 1, + highlight.range.end.character, + }) catch |e| { + std.log.err("send HREF (in send_highlight) failed: {t}", .{e}); + return; + }; +} + +const DocumentHighlight = struct { + range: Range, + kind: ?Kind, + + const Kind = enum(u8) { + Text = 1, + Read = 2, + Write = 3, + }; +}; + +const DocumentHighlightError = error{ + InvalidDocumentHighlight, + InvalidDocumentHighlightField, + InvalidDocumentHighlightFieldName, +} || RangeError || cbor.Error; +fn read_document_highlight(document_highlight: []const u8) DocumentHighlightError!DocumentHighlight { + var iter = document_highlight; + var range: ?Range = null; + var kind: ?DocumentHighlight.Kind = null; + var len = try cbor.decodeMapHeader(&iter); + while (len > 0) : (len -= 1) { + var field_name: []const u8 = undefined; + if (!(try cbor.matchString(&iter, &field_name))) return error.InvalidDocumentHighlightFieldName; + if (std.mem.eql(u8, field_name, "range")) { + var range_: []const u8 = undefined; + if (!(try cbor.matchValue(&iter, cbor.extract_cbor(&range_)))) return error.InvalidDocumentHighlightField; + range = try read_range(range_); + } else if (std.mem.eql(u8, field_name, "kind")) { + var kind_: u8 = undefined; + if (!(try cbor.matchValue(&iter, cbor.extract(&kind_)))) return error.InvalidDocumentHighlightField; + kind = std.enums.fromInt(DocumentHighlight.Kind, kind_) orelse return error.InvalidDocumentHighlightField; + } else { + try cbor.skipValue(&iter); + } + } + if (range == null) return error.InvalidDocumentHighlight; + return .{ .range = range.?, .kind = kind }; +} + pub const CompletionError = error{ InvalidTargetURI, } || CompletionListError || CompletionItemError || TextEditError || cbor.Error; diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 305a3e6..e19df25 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -6200,6 +6200,7 @@ pub const Editor = struct { } pub fn done_highlight_reference(self: *Self) void { + self.sort_matches(); self.highlight_references_state = .done; } diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index 9e16fb8..7b3a2dc 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -165,7 +165,7 @@ pub fn receive(self: *Self, from_: tp.pid_ref, m: tp.message) error{Exit}!bool { } self.find_in_files_state = .done; return true; - } else if (try m.match(.{ "HREF", tp.extract(&path), tp.extract(&begin_line), tp.extract(&begin_pos), tp.extract(&end_line), tp.extract(&end_pos), tp.extract(&lines) })) { + } else if (try m.match(.{ "HREF", tp.extract(&begin_line), tp.extract(&begin_pos), tp.extract(&end_line), tp.extract(&end_pos) })) { if (self.get_active_editor()) |editor| editor.add_highlight_reference(.{ .begin = .{ .row = begin_line, .col = begin_pos }, .end = .{ .row = end_line, .col = end_pos },