feat(render): direct renderer #2

Merged
yves-biener merged 6 commits from non-alternate-screen-rendering into main 2026-01-20 23:15:26 +01:00
2 changed files with 65 additions and 14 deletions
Showing only changes of commit c29c60bd89 - Show all commits

View File

@@ -11,6 +11,9 @@ pub fn main() !void {
defer renderer.deinit();
var container: App.Container = try .init(gpa, .{
.border = .{
.sides = .all,
},
.layout = .{
.direction = .horizontal,
.separator = .{ .enabled = true },
@@ -30,10 +33,58 @@ pub fn main() !void {
.rectangle = .{ .fill = .green },
}, .{}));
container.resize(&app.model, try renderer.resize());
container.reposition(&app.model, .{});
try renderer.render(@TypeOf(container), &container, App.Model, &app.model);
try renderer.flush();
try app.start(); // needs to become configurable, as what should be enabled / disabled (i.e. show cursor, hide cursor, use alternate screen, etc.)
defer app.stop() catch |err| log.err("Failed to stop application: {any}", .{err});
// event loop
event: 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();
//log.debug("received event: {s}", .{@tagName(event)});
// pre event handling
switch (event) {
// NOTE maybe I want to decouple the `key`s from the user input too? i.e. this only makes sense if the output is not echoed!
// otherwise just use gnu's `readline`?
.key => |key| {
if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit();
},
// NOTE errors could be displayed in another container in case one was received, etc. to provide the user with feedback
.err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }),
else => {},
}
// NOTE returned errors should be propagated back to the application
container.handle(&app.model, event) catch |err| app.postEvent(.{
.err = .{
.err = err,
.msg = "Container Event handling failed",
},
});
// post event handling
switch (event) {
.quit => break :event,
else => {},
}
}
// if there are more events to process continue handling them otherwise I can render the next frame
if (app.queue.len() > 0) continue :event;
container.resize(&app.model, try renderer.resize());
container.reposition(&app.model, .{});
try renderer.render(@TypeOf(container), &container, App.Model, &app.model);
try renderer.flush();
}
}
pub const panic = App.panic_handler;

View File

@@ -71,21 +71,21 @@ pub fn App(comptime M: type, comptime E: type) type {
this.quit_event.reset();
this.thread = try Thread.spawn(.{}, @This().run, .{this});
var termios: posix.termios = undefined;
try terminal.enableRawMode(&termios);
if (this.termios) |_| {} else this.termios = termios;
//var termios: posix.termios = undefined;
//try terminal.enableRawMode(&termios);
//if (this.termios) |_| {} else this.termios = termios;
try terminal.enterAltScreen();
try terminal.saveScreen();
try terminal.hideCursor();
try terminal.enableMouseSupport();
//try terminal.enterAltScreen();
//try terminal.saveScreen();
//try terminal.hideCursor();
//try terminal.enableMouseSupport();
}
pub fn interrupt(this: *@This()) !void {
this.quit_event.set();
try terminal.disableMouseSupport();
try terminal.restoreScreen();
try terminal.exitAltScreen();
//try terminal.disableMouseSupport();
//try terminal.restoreScreen();
//try terminal.exitAltScreen();
if (this.thread) |*thread| {
thread.join();
this.thread = null;