From 3d5119c3354ea9cac08893d82749c6d85348e6d5 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Sun, 31 Mar 2024 21:01:31 +0200 Subject: [PATCH] fix: stop leaking command IDs Command IDs are supposed to be unique for each command name and we should not generate new IDs each time an editor is loaded. --- src/tui/command.zig | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/tui/command.zig b/src/tui/command.zig index 97f8412..46fad8e 100644 --- a/src/tui/command.zig +++ b/src/tui/command.zig @@ -5,6 +5,7 @@ const log = @import("log"); const tui = @import("tui.zig"); pub const ID = usize; +pub const ID_unknown = std.math.maxInt(ID); pub const Context = struct { args: tp.message = .{}, @@ -17,7 +18,7 @@ threadlocal var context_buffer: [tp.max_message_size]u8 = undefined; pub const fmt = Context.fmt; const Vtable = struct { - id: ID = 0, + id: ID = ID_unknown, name: []const u8, run: *const fn (self: *Vtable, ctx: Context) tp.result, }; @@ -43,8 +44,15 @@ pub fn Closure(comptime T: type) type { } pub fn register(self: *Self) !void { - self.vtbl.id = try addCommand(&self.vtbl); - // try log.logger("cmd").print("addCommand({s}) => {d}", .{ self.vtbl.name, self.vtbl.id }); + if (command_names.get(self.vtbl.name)) |id| { + self.vtbl.id = id; + reAddCommand(&self.vtbl) catch |e| return log.logger("cmd").err("reAddCommand", e); + // log.logger("cmd").print("reAddCommand({s}) => {d}", .{ self.vtbl.name, self.vtbl.id }); + } else { + self.vtbl.id = try addCommand(&self.vtbl); + command_names.put(self.vtbl.name, self.vtbl.id) catch |e| return log.logger("cmd").err("addCommand", e); + // log.logger("cmd").print("addCommand({s}) => {d}", .{ self.vtbl.name, self.vtbl.id }); + } } pub fn unregister(self: *Self) void { @@ -63,13 +71,20 @@ pub fn Closure(comptime T: type) type { } const CommandTable = std.ArrayList(?*Vtable); -var commands: CommandTable = CommandTable.init(std.heap.page_allocator); +var commands: CommandTable = CommandTable.init(command_table_allocator); +var command_names: std.StringHashMap(ID) = std.StringHashMap(ID).init(command_table_allocator); +const command_table_allocator = std.heap.c_allocator; fn addCommand(cmd: *Vtable) !ID { try commands.append(cmd); return commands.items.len - 1; } +fn reAddCommand(cmd: *Vtable) !void { + if (commands.items[cmd.id] != null) return error.DuplicateCommand; + commands.items[cmd.id] = cmd; +} + pub fn removeCommand(id: ID) void { commands.items[id] = null; }