refactor: improve create pattern to avoid leaks

This commit is contained in:
CJ van den Berg 2025-07-19 00:03:30 +02:00
parent de68c1a5d4
commit efdad96054
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
46 changed files with 90 additions and 30 deletions

View file

@ -48,6 +48,7 @@ pub fn Options(context: type) type {
pub fn create(ctx_type: type, allocator: std.mem.Allocator, parent: Plane, opts: Options(ctx_type)) error{OutOfMemory}!*State(ctx_type) {
const Self = State(ctx_type);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
var n = try Plane.init(&opts.pos.opts(@typeName(Self)), parent);
errdefer n.deinit();
self.* = .{
@ -57,6 +58,7 @@ pub fn create(ctx_type: type, allocator: std.mem.Allocator, parent: Plane, opts:
.opts = opts,
};
self.opts.label = try self.allocator.dupe(u8, opts.label);
errdefer allocator.free(self.opts.label);
try self.init();
return self;
}

View file

@ -58,9 +58,10 @@ pub fn Options(context: type) type {
pub fn create(ctx_type: type, allocator: std.mem.Allocator, parent: Plane, opts: Options(ctx_type)) !Widget {
const Self = State(ctx_type);
const self = try allocator.create(Self);
var n = try Plane.init(&opts.pos.opts(@typeName(Self)), parent);
errdefer n.deinit();
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.parent = parent,
.plane = n,

View file

@ -56,6 +56,7 @@ pub fn Options(context: type) type {
pub fn create(ctx_type: type, allocator: std.mem.Allocator, parent: Plane, opts: Options(ctx_type)) !*State(ctx_type) {
const self = try allocator.create(State(ctx_type));
errdefer allocator.destroy(self);
const container = try WidgetList.createH(allocator, parent, @typeName(@This()), .dynamic);
self.* = .{
.allocator = allocator,

View file

@ -59,6 +59,7 @@ pub fn Options(context: type) type {
pub fn create(ctx_type: type, allocator: std.mem.Allocator, parent: Widget, opts: Options(ctx_type)) !*State(ctx_type) {
const self = try allocator.create(State(ctx_type));
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.plane = parent.plane.*,

View file

@ -224,6 +224,7 @@ pub fn hover(self: *Self) bool {
pub fn empty(allocator: Allocator, parent: Plane, layout_: Layout) !Self {
const child: type = struct { plane: Plane, layout: Layout };
const widget = try allocator.create(child);
errdefer allocator.destroy(widget);
const n = try Plane.init(&(Box{}).opts("empty"), parent);
widget.* = .{ .plane = n, .layout = layout_ };
return .{

View file

@ -32,21 +32,24 @@ after_render: *const fn (ctx: ?*anyopaque, theme: *const Widget.Theme) void = on
on_resize: *const fn (ctx: ?*anyopaque, self: *Self, pos_: Widget.Box) void = on_resize_default,
pub fn createH(allocator: Allocator, parent: Plane, name: [:0]const u8, layout_: Layout) error{OutOfMemory}!*Self {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = try init(allocator, parent, name, .horizontal, layout_, Box{});
self.plane.hide();
return self;
}
pub fn createV(allocator: Allocator, parent: Plane, name: [:0]const u8, layout_: Layout) !*Self {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = try init(allocator, parent, name, .vertical, layout_, Box{});
self.plane.hide();
return self;
}
pub fn createBox(allocator: Allocator, parent: Plane, name: [:0]const u8, dir: Direction, layout_: Layout, box: Box) !*Self {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = try init(allocator, parent, name, dir, layout_, box);
self.plane.hide();
return self;

View file

@ -5941,7 +5941,8 @@ pub const EditorWidget = struct {
fn create(allocator: Allocator, parent: Plane, buffer_manager: *Buffer.Manager) !Widget {
const container = try WidgetList.createH(allocator, parent, "editor.container", .dynamic);
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
try self.init(allocator, container.plane, buffer_manager);
try self.commands.init(&self.editor);
const editorWidget = Widget.to(self);

View file

@ -43,7 +43,8 @@ const Kind = enum { insert, modified, delete };
const Symbol = struct { kind: Kind, line: usize };
pub fn create(allocator: Allocator, parent: Widget, event_source: Widget, editor: *ed.Editor) !Widget {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent.plane.*),

View file

@ -47,7 +47,8 @@ const Entry = struct {
};
pub fn create(allocator: Allocator, parent: Plane) !Widget {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.plane = try Plane.init(&(Widget.Box{}).opts(name), parent),

View file

@ -81,7 +81,8 @@ const Self = @This();
pub fn create(allocator: std.mem.Allocator, parent: Widget) !Widget {
const logger = log.logger("home");
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
var n = try Plane.init(&(Widget.Box{}).opts("editor"), parent.plane.*);
errdefer n.deinit();
@ -303,6 +304,8 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
self.position_menu(self.v_center(5, self.menu_len, 5), self.center(x, self.menu_w));
}
if (self.plane.dim_y() < 3 or self.plane.dim_x() < root.version.len + 4) return false;
self.plane.cursor_move_yx(
@intCast(self.plane.dim_y() - 2),
@intCast(@max(self.plane.dim_x(), root.version.len + 3) - root.version.len - 3),
@ -311,6 +314,7 @@ pub fn render(self: *Self, theme: *const Widget.Theme) bool {
_ = self.plane.print("{s}", .{root.version}) catch return false;
if (builtin.mode == .Debug) {
const debug_warning_text = "debug build";
if (self.plane.dim_y() < 4 or self.plane.dim_x() < debug_warning_text.len + 4) return false;
self.plane.cursor_move_yx(
@intCast(self.plane.dim_y() - 3),
@intCast(@max(self.plane.dim_x(), debug_warning_text.len + 3) - debug_warning_text.len - 3),

View file

@ -14,7 +14,8 @@ view_rows: usize = 0,
lines: std.ArrayList([]const u8),
pub fn create(allocator: Allocator, parent: Plane) !Widget {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.plane = try Plane.init(&(Widget.Box{}).opts(name), parent),

View file

@ -30,9 +30,10 @@ const Entry = struct {
const Buffer = ArrayList(Entry);
pub fn create(allocator: Allocator, parent: Plane) !Widget {
const self: *Self = try allocator.create(Self);
var n = try Plane.init(&(Widget.Box{}).opts_vscroll(@typeName(Self)), parent);
errdefer n.deinit();
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.parent = parent,

View file

@ -26,7 +26,8 @@ const Self = @This();
pub fn create(allocator: Allocator, parent: Plane) !Widget {
const editor = tui.get_active_editor() orelse return error.NotFound;
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.plane = try Plane.init(&(Widget.Box{}).opts_vscroll(name), parent),
.editor = editor,

View file

@ -38,7 +38,8 @@ const Level = enum {
};
pub fn create(allocator: Allocator, parent: Plane) !Widget {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{ .plane = try Plane.init(&(Widget.Box{}).opts(name), parent) };
return Widget.to(self);
}

View file

@ -66,6 +66,7 @@ pub const CreateError = error{ OutOfMemory, ThespianSpawnFailed };
pub fn create(allocator: std.mem.Allocator) CreateError!Widget {
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.plane = tui.plane(),

View file

@ -21,7 +21,8 @@ pub fn Create(options: type) type {
const Self = @This();
pub fn create(allocator: std.mem.Allocator, _: command.Context) !struct { tui.Mode, tui.MiniMode } {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.input = std.ArrayList(u8).init(allocator),

View file

@ -35,7 +35,8 @@ pub fn Create(options: type) type {
};
pub fn create(allocator: std.mem.Allocator, _: command.Context) !struct { tui.Mode, tui.MiniMode } {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.file_path = std.ArrayList(u8).init(allocator),

View file

@ -28,7 +28,8 @@ commands: Commands = undefined,
pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui.MiniMode } {
const editor = tui.get_active_editor() orelse return error.NotFound;
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.input_ = ArrayList(u8).init(allocator),

View file

@ -25,7 +25,8 @@ last_input: []u8 = "",
commands: Commands = undefined,
pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui.MiniMode } {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{ .allocator = allocator };
try self.commands.init(self);
if (tui.get_active_selection(self.allocator)) |text| {

View file

@ -24,8 +24,9 @@ start: usize,
commands: Commands = undefined,
pub fn create(allocator: Allocator, _: command.Context) !struct { tui.Mode, tui.MiniMode } {
const self: *Self = try allocator.create(Self);
const editor = tui.get_active_editor() orelse return error.NotFound;
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.start = editor.get_primary().cursor.row + 1,

View file

@ -38,7 +38,8 @@ pub fn create(allocator: Allocator, ctx: command.Context) !struct { tui.Mode, tu
const direction: Direction = if (std.mem.indexOf(u8, operation_command, "_left")) |_| .left else .right;
const operation: Operation = if (tui.get_active_editor()) |editor| if (editor.get_primary().selection) |_| .select else .move else .move;
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.direction = direction,

View file

@ -38,7 +38,8 @@ buffer_manager: ?*BufferManager,
pub fn create(allocator: std.mem.Allocator) !tui.Mode {
const mv = tui.mainview() orelse return error.NotFound;
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.modal = try ModalBackground.create(*Self, allocator, tui.mainview_widget(), .{ .ctx = self }),

View file

@ -47,7 +47,8 @@ pub fn Create(options: type) type {
pub fn create(allocator: std.mem.Allocator) !tui.Mode {
const mv = tui.mainview() orelse return error.NotFound;
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.modal = try ModalBackground.create(*Self, allocator, tui.mainview_widget(), .{

View file

@ -27,7 +27,8 @@ style_factory: ?*const fn (self: *Self, theme: *const Widget.Theme) Widget.Theme
const Self = @This();
pub fn create(allocator: Allocator, parent: Plane, event_source: ?Widget, event_sink: EventHandler) !Widget {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
.event_sink = event_sink,

View file

@ -20,7 +20,8 @@ pub fn Create(comptime layout_: Widget.Layout) @import("widget.zig").CreateFunct
break :blk Widget.Layout{ .static = size };
} else break :blk layout_;
} else layout_;
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
.layout_ = layout__,

View file

@ -30,7 +30,8 @@ pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?Event
return error.WidgetInitFailed;
};
defer env.deinit();
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),

View file

@ -12,7 +12,8 @@ plane: Plane,
const Self = @This();
pub fn create(allocator: std.mem.Allocator, parent: Plane, _: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),

View file

@ -31,7 +31,8 @@ pub const width = idle_msg.len + 20;
pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
const frame_rate = tp.env.get().num("frame-rate");
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
.wipe_after_frames = @divTrunc(frame_rate, 2),

View file

@ -27,7 +27,8 @@ const Level = enum {
};
pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
.msg = std.ArrayList(u8).init(allocator),

View file

@ -20,7 +20,8 @@ const Self = @This();
pub const width = 8;
pub fn create(allocator: Allocator, parent: Plane, _: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
};

View file

@ -19,7 +19,8 @@ on_event: ?EventHandler,
const Self = @This();
pub fn create(allocator: Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
const self: *Self = try allocator.create(Self);
const self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
.on_event = event_handler,

View file

@ -54,6 +54,7 @@ pub const Style = @"style.config";
pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?EventHandler, _: ?[]const u8) @import("widget.zig").CreateError!Widget {
const self = try allocator.create(TabBar);
errdefer allocator.destroy(self);
self.* = try TabBar.init(allocator, parent, event_handler);
return Widget.to(self);
}
@ -447,6 +448,7 @@ const spacer = struct {
event_handler: ?EventHandler,
) @import("widget.zig").CreateError!Widget {
const self: *Self = try allocator.create(Self);
errdefer allocator.destroy(self);
self.* = .{
.plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
.layout_ = .{ .static = self.plane.egc_chunk_width(content, 0, 1) },

View file

@ -120,6 +120,9 @@ fn init(allocator: Allocator) InitError!*Self {
const frame_clock = try tp.metronome.init(frame_time);
var self = try allocator.create(Self);
// don't destroy
// if tui fails it is catastrophic anyway and we don't want to cause nock-on errors
// errdefer allocator.destroy(self);
self.* = .{
.allocator = allocator,
.config_ = conf,