146 lines
5.7 KiB
Zig
146 lines
5.7 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,
|
|
/// Cancel event to signify that the user provided an EOF
|
|
///
|
|
/// Usually this event is only triggered by the system in *non raw mode*
|
|
/// renderings otherwise the corresponding `.key` event would be fired instead.
|
|
cancel,
|
|
/// Resize event to signify that the application should re-draw to resize
|
|
///
|
|
/// Usually no `Container` nor `Element` should act on that event, as it
|
|
/// only serves for event based loops to force a re-draw with a new `Event`.
|
|
resize,
|
|
/// Ring the terminal bell to notify the user. This `Event` is handled by
|
|
/// every `Container` and will not be passed through the container tree.
|
|
bell,
|
|
/// Error event to notify other containers about a recoverable error
|
|
err: struct {
|
|
/// actual error
|
|
err: anyerror,
|
|
/// associated error message
|
|
msg: []const u8,
|
|
},
|
|
/// Input line event received in *non raw mode* (instead of individual `key` events)
|
|
///
|
|
/// This event contains the entire line until the ending newline character
|
|
/// (which is included in the payload of this event).
|
|
line: []const u8,
|
|
/// Input key event received from the user
|
|
key: Key,
|
|
/// Mouse input event
|
|
mouse: Mouse,
|
|
/// Focus event indicating that the application has gained the focus of the user
|
|
focus: bool,
|
|
};
|
|
|
|
/// Merge the two provided `union(enum)` `A` and `B` to a tagged union containing all fields of both tagged unions in `comptime`.
|
|
/// Declarations are not supported for `comptime` created types, see https://github.com/ziglang/zig/issues/6709 for details.
|
|
pub fn mergeTaggedUnions(comptime A: type, comptime B: type) type {
|
|
// TODO maybe it makes sense to have a nested tagged union type (i.e. system: union(enum) and event: union(enum))
|
|
// - allows re-definition of system / built-in events
|
|
// - clearly shows which events are system / built-in ones and which are user defined events
|
|
// - the memory footprint for the nesting is not really harmful
|
|
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 field_names: [a_fields.len + b_fields.len][:0]const u8 = undefined;
|
|
var field_types: [a_fields.len + b_fields.len]type = undefined;
|
|
var enum_names: [a_fields.len + b_fields.len][:0]const u8 = undefined;
|
|
// FIX can I not use `comptime_int`? `u4` would be actually incorrect!
|
|
// can I get the correct size through the length of the fields?
|
|
var enum_values: [a_fields.len + b_fields.len]u4 = undefined;
|
|
var i: usize = 0;
|
|
for (a_fields, a_enum_fields) |field, enum_field| {
|
|
field_names[i] = field.name;
|
|
field_types[i] = field.type;
|
|
var enum_f = enum_field;
|
|
enum_f.value = i;
|
|
enum_names[i] = enum_f.name;
|
|
enum_values[i] = i;
|
|
i += 1;
|
|
}
|
|
for (b_fields, b_enum_fields) |field, enum_field| {
|
|
field_names[i] = field.name;
|
|
field_types[i] = field.type;
|
|
var enum_f = enum_field;
|
|
enum_f.value = i;
|
|
enum_names[i] = enum_f.name;
|
|
enum_values[i] = i;
|
|
i += 1;
|
|
}
|
|
|
|
// NOTE declarations are not supported for `comptime` types: https://github.com/ziglang/zig/issues/6709
|
|
// -> will lead to a compilation error when constructing the tagged union
|
|
// at the end of this function in case at least one of the provided tagged
|
|
// unions to merge contains declarations (which in this case can only be the
|
|
// user provided one)
|
|
const a_enum_decls = @typeInfo(A).@"union".decls;
|
|
const b_enum_decls = @typeInfo(B).@"union".decls;
|
|
var decls: [a_enum_decls.len + b_enum_decls.len]std.builtin.Type.Declaration = undefined;
|
|
var j: usize = 0;
|
|
for (a_enum_decls) |decl| {
|
|
decls[j] = decl;
|
|
j += 1;
|
|
}
|
|
for (b_enum_decls) |decl| {
|
|
decls[j] = decl;
|
|
j += 1;
|
|
}
|
|
|
|
const EventType = @Int(.unsigned, @bitSizeOf(@TypeOf(i)) - @clz(i));
|
|
|
|
const Event = @Enum(
|
|
EventType,
|
|
.exhaustive,
|
|
&enum_names,
|
|
&enum_values,
|
|
);
|
|
|
|
return @Union(
|
|
.auto,
|
|
Event,
|
|
&field_names,
|
|
&field_types,
|
|
&@splat(.{}),
|
|
);
|
|
}
|
|
|
|
/// Determine whether the provided type `T` is a tagged union: `union(enum)`.
|
|
pub fn isTaggedUnion(comptime T: type) bool {
|
|
switch (@typeInfo(T)) {
|
|
.@"union" => |u| if (u.tag_type) |_| {} else {
|
|
return false;
|
|
},
|
|
else => return false,
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// Determine whether the provided type `T` is a `struct`.
|
|
pub fn isStruct(comptime T: type) bool {
|
|
return switch (@typeInfo(T)) {
|
|
.@"struct" => true,
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
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;
|