From 4f737e4019d637dc62da05f4953eac06bb43c9ab Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Fri, 26 Dec 2025 14:25:03 +0100 Subject: [PATCH] refactor: add lsp_info to mainview --- src/tui/lsp_info.zig | 93 ++++++++++++++++++++++++++++++++++++++++++++ src/tui/mainview.zig | 9 +++++ 2 files changed, 102 insertions(+) create mode 100644 src/tui/lsp_info.zig diff --git a/src/tui/lsp_info.zig b/src/tui/lsp_info.zig new file mode 100644 index 0000000..d44039a --- /dev/null +++ b/src/tui/lsp_info.zig @@ -0,0 +1,93 @@ +allocator: std.mem.Allocator, +table: Table, + +const Table = std.StringHashMapUnmanaged(Info); + +pub fn init(allocator: std.mem.Allocator) @This() { + return .{ + .allocator = allocator, + .table = .empty, + }; +} + +pub fn deinit(self: *@This()) void { + var iter = self.table.iterator(); + while (iter.next()) |item| { + for (item.value_ptr.trigger_characters.items) |char| + self.allocator.free(char); + item.value_ptr.trigger_characters.deinit(self.allocator); + self.allocator.free(item.key_ptr.*); + } + self.table.deinit(self.allocator); +} + +pub fn add_from_event(self: *@This(), cbor_buf: []const u8) error{ InvalidTriggersArray, OutOfMemory }!void { + var iter = cbor_buf; + var project: []const u8 = undefined; + var lsp_arg0: []const u8 = undefined; + var trigger_characters: []const u8 = undefined; + if (!(cbor.matchValue(&iter, .{ + cbor.any, + cbor.any, + cbor.extract(&project), + .{ cbor.extract(&lsp_arg0), cbor.more }, + cbor.extract_cbor(&trigger_characters), + }) catch return)) return; + const value = try self.add(lsp_arg0, &trigger_characters); + std.log.debug("{s} triggers: {any}", .{ lsp_arg0, value.trigger_characters.items }); +} + +pub fn add(self: *@This(), lsp_arg0: []const u8, iter: *[]const u8) error{ InvalidTriggersArray, OutOfMemory }!*Info { + const key = try self.allocator.dupe(u8, lsp_arg0); + errdefer self.allocator.free(key); + + const p = try self.table.getOrPut(self.allocator, key); + const value = p.value_ptr; + if (p.found_existing) { + for (value.trigger_characters.items) |char| + self.allocator.free(char); + value.trigger_characters.clearRetainingCapacity(); + } else { + value.* = .{}; + } + + var len = cbor.decodeArrayHeader(iter) catch return error.InvalidTriggersArray; + while (len > 0) : (len -= 1) { + var char: []const u8 = undefined; + if (!(cbor.matchValue(iter, cbor.extract(&char)) catch return error.InvalidTriggersArray)) return error.InvalidTriggersArray; + (try value.trigger_characters.addOne(self.allocator)).* = try self.allocator.dupe(u8, char); + } + return value; +} + +pub const Info = struct { + trigger_characters: std.ArrayList([]const u8) = .empty, +}; + +pub fn write_state(self: *@This(), writer: *std.Io.Writer) error{WriteFailed}!void { + try cbor.writeArrayHeader(writer, self.table.count()); + var iter = self.table.iterator(); + while (iter.next()) |item| { + try cbor.writeArrayHeader(writer, 2); + try cbor.writeValue(writer, item.key_ptr.*); + try cbor.writeArrayHeader(writer, item.value_ptr.trigger_characters.items.len); + for (item.value_ptr.trigger_characters.items) |char| try cbor.writeValue(writer, char); + } +} + +pub fn extract_state(self: *@This(), iter: *[]const u8) error{ InvalidTriggersArray, OutOfMemory }!void { + var lsp_arg0: []const u8 = undefined; + var trigger_characters: []const u8 = undefined; + var len = cbor.decodeArrayHeader(iter) catch return; + while (len > 0) : (len -= 1) { + if (cbor.matchValue(iter, .{ cbor.extract(&lsp_arg0), cbor.extract_cbor(&trigger_characters) }) catch false) { + const value = try self.add(lsp_arg0, &trigger_characters); + std.log.debug("restored {s} triggers: {any}", .{ lsp_arg0, value.trigger_characters.items }); + } else { + cbor.skipValue(iter) catch return error.InvalidTriggersArray; + } + } +} + +const std = @import("std"); +const cbor = @import("cbor"); diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index d0a3430..da49c62 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -27,6 +27,7 @@ const WidgetList = @import("WidgetList.zig"); const WidgetStack = @import("WidgetStack.zig"); const ed = @import("editor.zig"); const home = @import("home.zig"); +const LspInfo = @import("lsp_info.zig"); const logview = @import("logview.zig"); const filelist_view = @import("filelist_view.zig"); @@ -61,6 +62,7 @@ panel_height: ?usize = null, symbols: std.ArrayListUnmanaged(u8) = .empty, symbols_complete: bool = true, closing_project: bool = false, +lsp_info: LspInfo, const FileListType = enum { diagnostics, @@ -85,6 +87,7 @@ pub fn create(allocator: std.mem.Allocator) CreateError!Widget { .panes = undefined, .panes_widget = undefined, .buffer_manager = Buffer.Manager.init(allocator), + .lsp_info = .init(allocator), }; try self.commands.init(self); const w = Widget.to(self); @@ -126,6 +129,7 @@ pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { self.symbols.deinit(allocator); self.floating_views.deinit(); self.buffer_manager.deinit(); + self.lsp_info.deinit(); allocator.destroy(self); } @@ -1773,6 +1777,8 @@ pub fn write_state(self: *Self, writer: *std.Io.Writer) WriteStateError!void { if (self.widgets.get("tabs")) |tabs_widget| if (tabs_widget.dynamic_cast(@import("status/tabs.zig").TabBar)) |tabs| try tabs.write_state(writer); + + self.lsp_info.write_state(writer) catch return error.WriteFailed; } fn read_restore_info(self: *Self) !void { @@ -1850,6 +1856,9 @@ fn extract_state(self: *Self, iter: *[]const u8, mode: enum { no_project, with_p logger.print_err("mainview", "failed to restore tabs: {}", .{e}); logger.print("restored tabs ({d} bytes)", .{prev_len - iter.len}); + self.lsp_info.extract_state(iter) catch |e| + logger.print_err("mainview", "failed to restore LSP info: {}", .{e}); + const buffers = try self.buffer_manager.list_unordered(self.allocator); defer self.allocator.free(buffers); for (buffers) |buffer| if (!buffer.is_ephemeral())