feat(element/input): make accept event agnostic to u8 and u21 slices
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 50s

There are now comptime checks in place an the corresponding triggered
event will be automatically converted to the correct type to support
simple ascii strings (`[]u8`) or utf-8 strings (`[]u21`).
This commit is contained in:
2025-06-30 22:03:59 +02:00
parent 7595e3b5bb
commit 7875db0aea
2 changed files with 44 additions and 19 deletions

View File

@@ -127,10 +127,7 @@ pub fn main() !void {
.key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(),
.accept => |input| {
defer allocator.free(input);
var string = try allocator.alloc(u8, input.len);
defer allocator.free(string);
for (0.., input) |i, char| string[i] = @intCast(char);
log.debug("Accepted input '{s}'", .{string});
log.debug("Accepted input '{s}'", .{input});
},
.err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }),
else => {},
@@ -165,5 +162,5 @@ const zterm = @import("zterm");
const Color = zterm.Color;
const App = zterm.App(union(enum) {
accept: []u21,
accept: []u8,
});

View File

@@ -365,11 +365,31 @@ pub fn Scrollable(Event: type) type {
};
}
pub fn Input(Event: type, Queue: type) fn (accept_event: meta.FieldEnum(Event)) type {
pub fn Input(Event: type, Queue: type) fn (meta.FieldEnum(Event)) type {
// NOTE the struct is necessary, as otherwise I cannot point to the function I want to return
const input_struct = struct {
pub fn input_fn(accept_event: meta.FieldEnum(Event)) type {
// TODO create `comptime` check for `accept_event` that checks for the associated type of the field (of the `App.Event` union) which would need to be a `[]u8` or `[]u21`
// -> for the corresponding type generate the corresponding conversion calls to trigger the correct event automatically!
const event_type: enum { ascii, utf8 } = blk: { // check for type correctness and the associated type to use for the passed `accept_event`
const t = @FieldType(Event, @tagName(accept_event));
const err_msg = "Unexpected type for the associated input completion event to trigger. Only `[]u8` or `[]u21` are allowed.";
switch (@typeInfo(t)) {
.pointer => |pointer| {
if (pointer.size != .slice) @compileError(err_msg);
switch (@typeInfo(pointer.child)) {
.int => |num| {
if (num.signedness != .unsigned) @compileError(err_msg);
switch (num.bits) {
8 => break :blk .ascii,
21 => break :blk .utf8,
else => @compileError(err_msg),
}
},
else => @compileError(err_msg),
}
},
else => @compileError(err_msg),
}
};
return struct {
/// Offset from the end describing the current position of the cursor.
cursor_offset: usize = 0,
@@ -385,15 +405,10 @@ pub fn Input(Event: type, Queue: type) fn (accept_event: meta.FieldEnum(Event))
color: Color,
pub fn init(color: Color) @This() {
return .{
.color = color,
};
return .{ .color = color };
}
};
// TODO make the event to trigger user defined (needs to be `comptime`)
// - can this even be agnostic to `u8` / `u21`?
pub fn init(allocator: std.mem.Allocator, queue: *Queue, configuration: Configuration) @This() {
return .{
.configuration = configuration,
@@ -505,11 +520,24 @@ pub fn Input(Event: type, Queue: type) fn (accept_event: meta.FieldEnum(Event))
// TODO enter to accept?
// - shift+enter is not recognized by the input reader of `zterm`, so currently it is not possible to add newlines into the text box?
if (key.eql(.{ .cp = input.Enter }) or key.eql(.{ .cp = input.KpEnter })) {
this.queue.push(@unionInit(
Event,
@tagName(accept_event),
try this.input.toOwnedSlice(),
));
switch (event_type) {
.ascii => {
// NOTE convert unicode characters to ascii characters; if non ascii characters are found this is will fail!
var slice = try this.input.allocator.alloc(u8, this.input.items.len);
for (0.., this.input.items) |i, c| slice[i] = @intCast(c);
this.input.clearAndFree();
this.queue.push(@unionInit(
Event,
@tagName(accept_event),
slice,
));
},
.utf8 => this.queue.push(@unionInit(
Event,
@tagName(accept_event),
try this.input.toOwnedSlice(),
)),
}
this.cursor_offset = 0;
}
},