fix: don't leak Buffer.file_path

This commit is contained in:
CJ van den Berg 2025-08-05 15:24:18 +02:00
parent 886a2582a3
commit c88e2dd975
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
5 changed files with 28 additions and 16 deletions

View file

@ -33,7 +33,7 @@ external_allocator: Allocator,
root: Root,
leaves_buf: ?[]Node = null,
file_buf: ?[]const u8 = null,
file_path: []const u8 = "",
file_path_buf: std.ArrayListUnmanaged(u8) = .empty,
last_save: ?Root = null,
file_exists: bool = true,
file_eol_mode: EolMode = .lf,
@ -1084,6 +1084,7 @@ pub fn deinit(self: *Self) void {
if (self.meta) |buf| self.external_allocator.free(buf);
if (self.file_buf) |buf| self.external_allocator.free(buf);
if (self.leaves_buf) |buf| self.external_allocator.free(buf);
self.file_path_buf.deinit(self.external_allocator);
self.arena.deinit();
self.external_allocator.destroy(self);
}
@ -1098,6 +1099,17 @@ pub fn get_meta(self: *Self) ?[]const u8 {
return self.meta;
}
pub fn set_file_path(self: *Self, file_path: []const u8) void {
self.file_path_buf.clearRetainingCapacity();
self.file_path_buf.appendSlice(self.external_allocator, file_path) catch |e| switch (e) {
error.OutOfMemory => @panic("OOM in Buffer.set_file_path"),
};
}
pub inline fn get_file_path(self: *const Self) []const u8 {
return self.file_path_buf.items;
}
pub fn update_last_used_time(self: *Self) void {
self.utime = std.time.milliTimestamp();
}
@ -1177,7 +1189,7 @@ pub fn load_from_string(self: *const Self, s: []const u8, eol_mode: *EolMode, ut
pub fn load_from_string_and_update(self: *Self, file_path: []const u8, s: []const u8) LoadFromStringError!void {
self.root = try self.load_from_string(s, &self.file_eol_mode, &self.file_utf8_sanitized);
self.file_path = try self.allocator.dupe(u8, file_path);
self.set_file_path(file_path);
self.last_save = self.root;
self.last_save_eol_mode = self.file_eol_mode;
self.file_exists = false;
@ -1257,7 +1269,7 @@ pub fn load_from_file_and_update(self: *Self, file_path: []const u8) LoadFromFil
var eol_mode: EolMode = .lf;
var utf8_sanitized: bool = false;
self.root = try self.load_from_file(file_path, &file_exists, &eol_mode, &utf8_sanitized);
self.file_path = try self.allocator.dupe(u8, file_path);
self.set_file_path(file_path);
self.last_save = self.root;
self.file_exists = file_exists;
self.file_eol_mode = eol_mode;
@ -1276,7 +1288,7 @@ pub fn reset_to_last_saved(self: *Self) void {
}
pub fn refresh_from_file(self: *Self) LoadFromFileError!void {
try self.load_from_file_and_update(self.file_path);
try self.load_from_file_and_update(self.get_file_path());
self.update_last_used_time();
}
@ -1366,7 +1378,7 @@ pub fn store_to_file_and_clean(self: *Self, file_path: []const u8) StoreToFileEr
self.file_utf8_sanitized = false;
if (self.ephemeral) {
self.ephemeral = false;
self.file_path = try self.allocator.dupe(u8, file_path);
self.set_file_path(file_path);
}
}

View file

@ -64,15 +64,15 @@ pub fn delete_buffer(self: *Self, file_path: []const u8) bool {
pub fn retire(_: *Self, buffer: *Buffer, meta: ?[]const u8) void {
if (meta) |buf| buffer.set_meta(buf) catch {};
tp.trace(tp.channel.debug, .{ "buffer", "retire", buffer.file_path, "hidden", buffer.hidden, "ephemeral", buffer.ephemeral });
tp.trace(tp.channel.debug, .{ "buffer", "retire", buffer.get_file_path(), "hidden", buffer.hidden, "ephemeral", buffer.ephemeral });
if (meta) |buf| tp.trace(tp.channel.debug, tp.message{ .buf = buf });
}
pub fn close_buffer(self: *Self, buffer: *Buffer) void {
buffer.hidden = true;
tp.trace(tp.channel.debug, .{ "buffer", "close", buffer.file_path, "hidden", buffer.hidden, "ephemeral", buffer.ephemeral });
tp.trace(tp.channel.debug, .{ "buffer", "close", buffer.get_file_path(), "hidden", buffer.hidden, "ephemeral", buffer.ephemeral });
if (buffer.is_ephemeral()) {
_ = self.buffers.remove(buffer.file_path);
_ = self.buffers.remove(buffer.get_file_path());
buffer.deinit();
}
}
@ -116,7 +116,7 @@ pub fn save_all(self: *const Self) Buffer.StoreToFileError!void {
if (buffer.is_ephemeral())
buffer.mark_clean()
else
try buffer.store_to_file_and_clean(buffer.file_path);
try buffer.store_to_file_and_clean(buffer.get_file_path());
}
}

View file

@ -1316,11 +1316,11 @@ fn get_next_mru_buffer(self: *Self) ?[]const u8 {
defer self.allocator.free(buffers);
const active_file_path = self.get_active_file_path();
for (buffers) |buffer| {
if (active_file_path) |fp| if (std.mem.eql(u8, fp, buffer.file_path))
if (active_file_path) |fp| if (std.mem.eql(u8, fp, buffer.get_file_path()))
continue;
if (buffer.hidden)
continue;
return buffer.file_path;
return buffer.get_file_path();
}
return null;
}

View file

@ -34,7 +34,7 @@ pub fn load_entries(palette: *Type) !usize {
else
"";
(try palette.entries.addOne()).* = .{
.label = buffer.file_path,
.label = buffer.get_file_path(),
.icon = buffer.file_type_icon orelse "",
.color = buffer.file_type_color,
.indicator = indicator,

View file

@ -265,7 +265,7 @@ const TabBar = struct {
fn navigate_to_tab(tab: *const TabBarTab) void {
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
if (buffer_manager.buffer_from_ref(tab.buffer_ref)) |buffer|
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = buffer.file_path } }) catch {};
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = buffer.get_file_path() } }) catch {};
}
};
@ -298,13 +298,13 @@ const Tab = struct {
fn on_click(self: *@This(), _: *Button.State(@This())) void {
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
if (buffer_manager.buffer_from_ref(self.buffer_ref)) |buffer|
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = buffer.file_path } }) catch {};
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = buffer.get_file_path() } }) catch {};
}
fn on_click2(self: *@This(), _: *Button.State(@This())) void {
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
if (buffer_manager.buffer_from_ref(self.buffer_ref)) |buffer|
tp.self_pid().send(.{ "cmd", "close_buffer", .{buffer.file_path} }) catch {};
tp.self_pid().send(.{ "cmd", "close_buffer", .{buffer.get_file_path()} }) catch {};
}
fn render(self: *@This(), btn: *Button.State(@This()), theme: *const Widget.Theme) bool {
@ -450,7 +450,7 @@ const Tab = struct {
}
fn name_from_buffer(buffer: *Buffer) []const u8 {
const file_path = buffer.file_path;
const file_path = buffer.get_file_path();
if (file_path.len > 0 and file_path[0] == '*')
return file_path;
const basename_begin = std.mem.lastIndexOfScalar(u8, file_path, std.fs.path.sep);