Files
zterm/src/event.zig
Yves Biener e9a9c2b680 feat(app): signal WINCH for .resize system event
This allows the application to automatically re-draw and resize if the
application receives the signal by the terminal emulator.
2025-05-21 22:49:08 +02:00

98 lines
3.3 KiB
Zig

//! Events which are defined by the library. They might be extended by user
//! events. See `App` for more details about user defined events.
/// System events available to every `zterm.App`
pub const SystemEvent = union(enum) {
/// Initialize event, which is send once at the beginning of the event loop and before the first render loop
/// TODO not sure if this is necessary or if there is an actual usecase for this - for now it will remain
init,
/// Quit event to signify the end of the event loop (rendering should stop afterwards)
quit,
/// Resize event to signify that the application should re-draw to resize
resize,
/// Error event to notify other containers about a recoverable error
err: struct {
/// actual error
err: anyerror,
/// associated error message
msg: []const u8,
},
/// Input key event received from the user
key: Key,
/// Mouse input event
mouse: Mouse,
/// Focus event for mouse interaction
/// TODO this should instead be a union with a `Size` to derive which container / element the focus meant for
focus: bool,
};
pub fn mergeTaggedUnions(comptime A: type, comptime B: type) type {
if (!isTaggedUnion(A) or !isTaggedUnion(B)) {
@compileError("Both types for merging tagged unions need to be of type `union(enum)`.");
}
const a_fields = @typeInfo(A).@"union".fields;
const a_fields_tag = @typeInfo(A).@"union".tag_type.?;
const a_enum_fields = @typeInfo(a_fields_tag).@"enum".fields;
const b_fields = @typeInfo(B).@"union".fields;
const b_fields_tag = @typeInfo(B).@"union".tag_type.?;
const b_enum_fields = @typeInfo(b_fields_tag).@"enum".fields;
var fields: [a_fields.len + b_fields.len]std.builtin.Type.UnionField = undefined;
var enum_fields: [a_fields.len + b_fields.len]std.builtin.Type.EnumField = undefined;
var i: usize = 0;
for (a_fields, a_enum_fields) |field, enum_field| {
fields[i] = field;
var enum_f = enum_field;
enum_f.value = i;
enum_fields[i] = enum_f;
i += 1;
}
for (b_fields, b_enum_fields) |field, enum_field| {
fields[i] = field;
var enum_f = enum_field;
enum_f.value = i;
enum_fields[i] = enum_f;
i += 1;
}
const log2_i = @bitSizeOf(@TypeOf(i)) - @clz(i);
const EventType = @Type(.{ .int = .{
.signedness = .unsigned,
.bits = log2_i,
} });
const Event = @Type(.{ .@"enum" = .{
.tag_type = EventType,
.fields = enum_fields[0..],
.decls = &.{},
.is_exhaustive = true,
} });
return @Type(.{ .@"union" = .{
.layout = .auto,
.tag_type = Event,
.fields = fields[0..],
.decls = &.{},
} });
}
// Determine at `comptime` whether the provided type `E` is an `union(enum)`.
pub fn isTaggedUnion(comptime E: type) bool {
switch (@typeInfo(E)) {
.@"union" => |u| {
if (u.tag_type) |_| {} else {
return false;
}
},
else => return false,
}
return true;
}
const std = @import("std");
const input = @import("input.zig");
const terminal = @import("terminal.zig");
const Key = input.Key;
const Mouse = input.Mouse;
const Point = @import("point.zig").Point;