Skip to content

Commit 047d4ce

Browse files
committed
feat: add convenience helpers for formatted JS and raw slices
Reduce repetitive buffer formatting and response parsing when running JavaScript or replying from event handlers. - Add `runFmt`, `scriptResult`, `runClientFmt`, `scriptClientResult`, and `returnFmt` to streamline common call patterns. - Add `getRawSlice` and `getRawSliceAt` to expose size-aware raw argument access without manual pointer slicing. - Add tests to ensure these helper APIs stay publicly exposed.
1 parent d900c81 commit 047d4ce

2 files changed

Lines changed: 64 additions & 1 deletion

File tree

src/tests.zig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ test "constants" {
4040
try std.testing.expectEqual(@as(usize, 16), webui.WEBUI_MAX_ARG);
4141
}
4242

43+
test "convenience helpers are exposed" {
44+
try std.testing.expect(@hasDecl(webui, "runFmt"));
45+
try std.testing.expect(@hasDecl(webui, "scriptResult"));
46+
try std.testing.expect(@hasDecl(webui.Event, "runClientFmt"));
47+
try std.testing.expect(@hasDecl(webui.Event, "scriptClientResult"));
48+
try std.testing.expect(@hasDecl(webui.Event, "returnFmt"));
49+
try std.testing.expect(@hasDecl(webui.Event, "getRawSlice"));
50+
try std.testing.expect(@hasDecl(webui.Event, "getRawSliceAt"));
51+
}
52+
4353
test "Browser enum integer values match C ABI" {
4454
try std.testing.expectEqual(@as(usize, 0), @intFromEnum(webui.Browser.NoBrowser));
4555
try std.testing.expectEqual(@as(usize, 1), @intFromEnum(webui.Browser.AnyBrowser));

src/webui.zig

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,9 +585,14 @@ pub fn run(self: webui, script_content: [:0]const u8) void {
585585
c.webui_run(self.window_handle, script_content.ptr);
586586
}
587587

588+
/// Format JavaScript into `buffer`, then run it without waiting for a response.
589+
pub fn runFmt(self: webui, buffer: []u8, comptime fmt: []const u8, args: anytype) !void {
590+
const script_content = try std.fmt.bufPrintZ(buffer, fmt, args);
591+
self.run(script_content);
592+
}
593+
588594
/// Run JavaScript and get the response back. Work only in single client mode.
589595
/// Make sure your local buffer can hold the response.
590-
/// Return True if there is no execution error
591596
pub fn script(self: webui, script_content: [:0]const u8, timeout: usize, buffer: []u8) !void {
592597
const success = c.webui_script(
593598
self.window_handle,
@@ -599,6 +604,19 @@ pub fn script(self: webui, script_content: [:0]const u8, timeout: usize, buffer:
599604
if (!success) return WebUIError.ScriptError;
600605
}
601606

607+
/// Run JavaScript and return the written response slice.
608+
pub fn scriptResult(self: webui, script_content: [:0]const u8, timeout: usize, buffer: []u8) ![:0]u8 {
609+
try self.script(script_content, timeout, buffer);
610+
return responseSlice(buffer);
611+
}
612+
613+
fn responseSlice(buffer: []u8) WebUIError![:0]u8 {
614+
for (buffer, 0..) |byte, i| {
615+
if (byte == 0) return buffer[0..i :0];
616+
}
617+
return WebUIError.ScriptError;
618+
}
619+
602620
/// Chose between Deno and Nodejs as runtime for .js and .ts files.
603621
pub fn setRuntime(self: webui, runtime: Runtime) void {
604622
c.webui_set_runtime(self.window_handle, runtime);
@@ -1120,6 +1138,12 @@ pub const Event = extern struct {
11201138
c.webui_run_client(self, script_content.ptr);
11211139
}
11221140

1141+
/// Format JavaScript into `buffer`, then run it on the event client.
1142+
pub fn runClientFmt(self: *Event, buffer: []u8, comptime fmt: []const u8, args: anytype) !void {
1143+
const script_content = try std.fmt.bufPrintZ(buffer, fmt, args);
1144+
self.runClient(script_content);
1145+
}
1146+
11231147
/// Run JavaScript and get the response back. Single client.
11241148
/// Make sure your local buffer can hold the response.
11251149
pub fn scriptClient(
@@ -1138,6 +1162,17 @@ pub const Event = extern struct {
11381162
if (!success) return WebUIError.ScriptError;
11391163
}
11401164

1165+
/// Run JavaScript on the event client and return the written response slice.
1166+
pub fn scriptClientResult(
1167+
self: *Event,
1168+
script_content: [:0]const u8,
1169+
timeout: usize,
1170+
buffer: []u8,
1171+
) ![:0]u8 {
1172+
try self.scriptClient(script_content, timeout, buffer);
1173+
return responseSlice(buffer);
1174+
}
1175+
11411176
/// Return the response to JavaScript as integer.
11421177
pub fn returnInt(e: *Event, n: i64) void {
11431178
c.webui_return_int(e, n);
@@ -1153,6 +1188,12 @@ pub const Event = extern struct {
11531188
c.webui_return_string(e, str.ptr);
11541189
}
11551190

1191+
/// Format a string response into `buffer`, then return it to JavaScript.
1192+
pub fn returnFmt(e: *Event, buffer: []u8, comptime fmt: []const u8, args: anytype) !void {
1193+
const response = try std.fmt.bufPrintZ(buffer, fmt, args);
1194+
e.returnString(response);
1195+
}
1196+
11561197
/// Return the response to JavaScript as boolean.
11571198
pub fn returnBool(e: *Event, b: bool) void {
11581199
c.webui_return_bool(e, b);
@@ -1242,12 +1283,24 @@ pub const Event = extern struct {
12421283
return @ptrCast(ptr);
12431284
}
12441285

1286+
/// Get an argument as a raw byte slice at a specific index.
1287+
pub fn getRawSliceAt(e: *Event, index: usize) ![]const u8 {
1288+
const size = try e.getSizeAt(index);
1289+
return e.getRawAt(index)[0..size];
1290+
}
1291+
12451292
// Get the first argument raw buffer
12461293
pub fn getRaw(e: *Event) [*]const u8 {
12471294
const ptr = c.webui_get_string(e);
12481295
return @ptrCast(ptr);
12491296
}
12501297

1298+
/// Get the first argument as a raw byte slice.
1299+
pub fn getRawSlice(e: *Event) ![]const u8 {
1300+
const size = try e.getSize();
1301+
return e.getRaw()[0..size];
1302+
}
1303+
12511304
/// Get an argument as boolean at a specific index
12521305
pub fn getBoolAt(e: *Event, index: usize) bool {
12531306
return c.webui_get_bool_at(e, index);

0 commit comments

Comments
 (0)