feat: change event system
this fixes a common use-after-free footgun and removes the need for a global allocator
This commit is contained in:
parent
97be1d863a
commit
a62e77483b
|
@ -22,7 +22,9 @@ pub fn init() void {
|
||||||
// do initialization stuff
|
// do initialization stuff
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(ev: zz.Event) void {
|
pub fn update() void {
|
||||||
|
var event = zz.getEvent(my_allocator) catch return;
|
||||||
|
defer event.deinit();
|
||||||
// handle events
|
// handle events
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,6 @@ var mode: ?zz.types.InputMode = null;
|
||||||
|
|
||||||
// called on startup
|
// called on startup
|
||||||
pub fn init() void {
|
pub fn init() void {
|
||||||
// set zellzig's allocator
|
|
||||||
// This is required to receive events.
|
|
||||||
zz.allocator = gpa.allocator();
|
|
||||||
|
|
||||||
// This is required to make zellij close once everything but our plugin is gone.
|
// This is required to make zellij close once everything but our plugin is gone.
|
||||||
zz.api.setSelectable(false);
|
zz.api.setSelectable(false);
|
||||||
|
|
||||||
|
@ -28,8 +24,11 @@ pub fn init() void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// called on every event
|
// called on every event
|
||||||
pub fn update(ev: zz.Event) void {
|
pub fn update() void {
|
||||||
switch (ev) {
|
var ev = zz.getEvent(gpa.allocator()) catch return;
|
||||||
|
defer ev.deinit();
|
||||||
|
|
||||||
|
switch (ev.data) {
|
||||||
.ModeUpdate => |mode_info| mode = mode_info.mode,
|
.ModeUpdate => |mode_info| mode = mode_info.mode,
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
16
src/api.zig
16
src/api.zig
|
@ -15,17 +15,17 @@ pub fn sendObj(data: anytype) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receives a JSON object from zellij
|
/// Receives a JSON object from zellij
|
||||||
pub fn recvObj(comptime T: type) !zz.OwnedDeserData(T) {
|
pub fn recvObj(comptime T: type, alloc: std.mem.Allocator) !zz.OwnedDeserData(T) {
|
||||||
var stdin = std.io.getStdIn();
|
var stdin = std.io.getStdIn();
|
||||||
|
|
||||||
const data = (try stdin.reader().readUntilDelimiterOrEofAlloc(
|
const data = (try stdin.reader().readUntilDelimiterOrEofAlloc(
|
||||||
zz.allocator.?,
|
alloc,
|
||||||
'\n',
|
'\n',
|
||||||
std.math.maxInt(usize),
|
std.math.maxInt(usize),
|
||||||
)) orelse unreachable;
|
)) orelse unreachable;
|
||||||
defer zz.allocator.?.free(data);
|
defer alloc.free(data);
|
||||||
|
|
||||||
return zz.OwnedDeserData(T).deserialize(zz.allocator.?, data);
|
return zz.OwnedDeserData(T).deserialize(alloc, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Subscribes to the given events.
|
/// Subscribes to the given events.
|
||||||
|
@ -49,15 +49,15 @@ pub fn setSelectable(selectable: bool) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the ID of this plugin, and zellij's PID.
|
/// Returns the ID of this plugin, and zellij's PID.
|
||||||
pub fn getPluginIds() !zz.OwnedDeserData(types.PluginIds) {
|
pub fn getPluginIds(alloc: std.mem.Allocator) !zz.OwnedDeserData(types.PluginIds) {
|
||||||
zapi.host_get_plugin_ids();
|
zapi.host_get_plugin_ids();
|
||||||
return try recvObj(types.PluginIds);
|
return try recvObj(types.PluginIds, alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns zellij's version string.
|
/// Returns zellij's version string.
|
||||||
pub fn getZellijVersion() !zz.OwnedDeserData([]const u8) {
|
pub fn getZellijVersion(alloc: std.mem.Allocator) !zz.OwnedDeserData([]const u8) {
|
||||||
zapi.host_get_zellij_version();
|
zapi.host_get_zellij_version();
|
||||||
return try recvObj([]const u8);
|
return try recvObj([]const u8, alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn openFile(path: []const u8) !void {
|
pub fn openFile(path: []const u8) !void {
|
||||||
|
|
30
src/main.zig
30
src/main.zig
|
@ -19,22 +19,26 @@ test {
|
||||||
/// ```zig
|
/// ```zig
|
||||||
/// // main.zig
|
/// // main.zig
|
||||||
/// const zz = @import("zellzig");
|
/// const zz = @import("zellzig");
|
||||||
|
///
|
||||||
|
/// const gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
///
|
||||||
/// comptime {
|
/// comptime {
|
||||||
/// zz.createPlugin(@This());
|
/// zz.createPlugin(@This());
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// pub fn init() void {
|
/// pub fn init() void {}
|
||||||
/// const alloc = std.heap.GeneralPurposeAllocator(.{}){};
|
/// pub fn update(event: zz.Event) void {
|
||||||
/// zz.allocator = alloc.allocator();
|
/// var event = zz.getEvent(gpa.allocator()) catch return;
|
||||||
|
/// defer event.deinit();
|
||||||
|
/// // use event
|
||||||
/// }
|
/// }
|
||||||
/// pub fn update(event: zz.Event) void {}
|
|
||||||
/// pub fn render(rows: i32, cols: i32) void {}
|
/// pub fn render(rows: i32, cols: i32) void {}
|
||||||
/// ```
|
/// ```
|
||||||
pub fn createPlugin(comptime Plugin: type) void {
|
pub fn createPlugin(comptime Plugin: type) void {
|
||||||
if (@TypeOf(Plugin.init) != fn () void)
|
if (@TypeOf(Plugin.init) != fn () void)
|
||||||
@compileError("Function 'init' has invalid signature!");
|
@compileError("Function 'init' has invalid signature!");
|
||||||
|
|
||||||
if (@TypeOf(Plugin.update) != fn (Event) void)
|
if (@TypeOf(Plugin.update) != fn () void)
|
||||||
@compileError("Function 'update' has invalid signature!");
|
@compileError("Function 'update' has invalid signature!");
|
||||||
|
|
||||||
if (@TypeOf(Plugin.render) != fn (i32, i32) void)
|
if (@TypeOf(Plugin.render) != fn (i32, i32) void)
|
||||||
|
@ -50,17 +54,11 @@ pub fn createPlugin(comptime Plugin: type) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn update() void {
|
export fn update() void {
|
||||||
if (allocator == null) {
|
Plugin.update();
|
||||||
@panic("Got event while allocator is null! Did you forget to set it?");
|
|
||||||
}
|
|
||||||
|
|
||||||
var ev = api.recvObj(types.Event) catch |err| {
|
|
||||||
std.log.err("Deserialize error: {}", .{err});
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
defer ev.deinit();
|
|
||||||
|
|
||||||
Plugin.update(ev.data);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getEvent(alloc: std.mem.Allocator) !OwnedDeserData(types.Event) {
|
||||||
|
return try api.recvObj(types.Event, alloc);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue