Something went wrong. Try again.
A charm-like tui library
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596const std = @import("std");const Io = std.Io;const Msg = @import("root.zig").Msg;const Allocator = std.mem.Allocator;
const Cmd = @This();
ctx: ?*anyopaque = null,run_fn: *const fn (allocator: Allocator, io: Io, ctx: ?*anyopaque) ?Msg,free_ctx: ?*const fn (allocator: Allocator, ctx: *anyopaque) void = null,
pub fn run(self: Cmd, allocator: Allocator, io: Io) ?Msg { const result = self.run_fn(allocator, io, self.ctx); if (self.free_ctx) |free| if (self.ctx) |c| free(allocator, c); return result;}
pub fn pure(comptime msg: Msg) Cmd { const Inner = struct { fn run(_: ?*anyopaque, _: Allocator, _: Io) ?Msg { return msg; } }; return .{ .run_fn = Inner.run };}
pub const quit: Cmd = .{ .run_fn = quitFn };
fn quitFn(_: Allocator, _: Io, _: ?*anyopaque) ?Msg { return .quit;}
const TickCtx = struct { duration_ns: u64, msg: Msg,};
/// Returns a Cmd that sleeps for `duration_ns` and then emits `msg`. The/// caller's allocator (typically `model.gpa`) backs the ctx — the Cmd's/// `free_ctx` releases it after run completes.////// Sleep is performed via `Io.sleep`, so a shutdown that wakes the io/// can cancel it.pub fn tick(allocator: Allocator, duration_ns: u64, msg: Msg) Allocator.Error!Cmd { const ctx = try allocator.create(TickCtx); ctx.* = .{ .duration_ns = duration_ns, .msg = msg }; return .{ .run_fn = tickRun, .ctx = ctx, .free_ctx = tickFree, };}
fn tickRun(_: Allocator, io: Io, ctx: ?*anyopaque) ?Msg { const tc: *TickCtx = @ptrCast(@alignCast(ctx.?)); Io.sleep(io, .fromNanoseconds(@intCast(tc.duration_ns)), .awake) catch return null; return tc.msg;}
fn tickFree(allocator: Allocator, ctx: *anyopaque) void { const tc: *TickCtx = @ptrCast(@alignCast(ctx)); allocator.destroy(tc);}
const BatchCtx = struct { cmds: []Cmd,};
/// Returns a Cmd that, when run, dispatches every Cmd in `cmds` through/// the program's cmd queue. The slice is duped with `allocator`; the/// Program loop frees it after it pushes the children.pub fn batch(allocator: Allocator, cmds: []const Cmd) Allocator.Error!Cmd { const dup = try allocator.dupe(Cmd, cmds); const ctx = try allocator.create(BatchCtx); ctx.* = .{ .cmds = dup }; return .{ .run_fn = batchRun, .ctx = ctx, .free_ctx = batchFreeCtx, };}
fn batchRun(_: Allocator, _: Io, ctx: ?*anyopaque) ?Msg { const bc: *BatchCtx = @ptrCast(@alignCast(ctx.?)); return .{ .batch = bc.cmds };}
fn batchFreeCtx(allocator: Allocator, ctx: *anyopaque) void { // Only free the struct; the cmds slice is owned by the produced Msg // and is freed by `Program.run` after the loop pushes each child Cmd. const bc: *BatchCtx = @ptrCast(@alignCast(ctx)); allocator.destroy(bc);}