// TODO planned features: // FIX known issues: pub fn main() !void { // argument handling var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init; defer if (gpa.deinit() == .leak) std.log.err("memory leak", .{}); var area: std.heap.ArenaAllocator = .init(gpa.allocator()); defer area.deinit(); // NOTE current setup // - in debug builds use the gpa (to identify leaks!) // - in other builds use the area to free all memory! const allocator = switch (builtin.mode) { .Debug => gpa.allocator(), else => area.allocator(), }; // argument handling { var arg_it = try std.process.argsWithAllocator(allocator); defer arg_it.deinit(); // TODO may there be other options? // usage: tui-diff // skip own executable name _ = arg_it.skip(); } // tui creation errdefer |err| log.err("Application Error: {any}", .{err}); var threaded_io: std.Io.Threaded = .init(allocator); errdefer threaded_io.deinit(); const io = threaded_io.io(); var renderer = zterm.Renderer.Buffered.init(allocator); defer renderer.deinit(); var app: App = .init(io, .init); var element_root: tui_diff.elements.Root(App) = .init; var element_tree: tui_diff.elements.Tree(App) = .init; var changes: [3]tui_diff.elements.Change(App) = @splat(.init); var scrollable_diffs = try tui_diff.elements.Diff(App, allocator, &changes); // NOTE scrollable should provide deinit function (*zterm*) // -> `Container` of `Scrollable` does not pass through the `minSize` request to its children! var root = try tui_diff.Container(App, allocator, &element_root, &element_tree, &scrollable_diffs); defer root.deinit(); // also de-initializes the children try app.start(); defer app.stop() catch |err| log.err("Failed to stop application: {any}", .{err}); // defer app.model.deinit(); // event loop loop: while (true) { // batch events since last iteration const len = blk: { app.queue.poll(); app.queue.lock(); defer app.queue.unlock(); break :blk app.queue.len(); }; // handle events for (0..len) |_| { const event = app.queue.pop(); // pre event handling switch (event) { .key => |key| if (key.eql(.{ .cp = 'q' })) app.quit(), else => {}, } // NOTE returned errors should be propagated back to the application root.handle(&app.model, event) catch |err| app.postEvent(.{ .err = .{ .err = err, .msg = "Container Event handling failed", }, }); // post event handling switch (event) { .quit => break :loop, else => {}, } } root.resize(&app.model, try renderer.resize()); root.reposition(&app.model, .{}); try renderer.render(@TypeOf(root), &root, App.Model, &app.model); try renderer.flush(); } threaded_io.deinit(); } const log = std.log.scoped(.default); const App = zterm.App(Model, Event); pub const panic = App.panic_handler; const std = @import("std"); const builtin = @import("builtin"); const tui_diff = @import("tui-diff"); const zterm = @import("zterm"); const Event = tui_diff.Event; const Model = tui_diff.Model;