summaryrefslogtreecommitdiff
path: root/src/web.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-08-03 00:32:11 -0300
committerGabriel Schneider <[email protected]>2026-08-10 09:17:07 -0300
commit6a43880a7ef6899f0d66c1b0a63a7e7b5610236a (patch)
tree2fc12106e0b5f0eb0abcaa345eaa85b39b5bcdd7 /src/web.zig
parentc86d3bb210822b3128a0759533f1bec3654364b7 (diff)
downloadpardes-6a43880a7ef6899f0d66c1b0a63a7e7b5610236a.tar.gz
pardes-6a43880a7ef6899f0d66c1b0a63a7e7b5610236a.zip
pipe selections through shell commands
Diffstat (limited to 'src/web.zig')
-rw-r--r--src/web.zig47
1 files changed, 47 insertions, 0 deletions
diff --git a/src/web.zig b/src/web.zig
index 6ceca904..42359329 100644
--- a/src/web.zig
+++ b/src/web.zig
@@ -188,6 +188,37 @@ export fn pardes_lsp_response(id: u32, len_arg: u32) void {
s.core.update(.{ .lsp_resp = .{ .id = id, .rows = input[0..len] } });
}
+/// Complete host-handled effect kind 12. On success `input` is
+/// `[count:u32][count * output_len:u32][output bytes...]`, little-endian.
+/// A static browser has no process host and simply never calls this; an
+/// embedding such as Electron can run the request without another WASM ABI.
+export fn pardes_pipe_response(id: u32, success_arg: u32, len_arg: u32) void {
+ const s = &(state orelse return);
+ if (success_arg == 0) {
+ s.core.update(.{ .pipe_resp = .{ .id = id, .success = false, .outputs = &.{} } });
+ return;
+ }
+ const len: usize = @min(len_arg, input.len);
+ if (len < 4) return;
+ const count: usize = std.mem.readInt(u32, input[0..4], .little);
+ if (count == 0 or count > pardes.MAX_SELS) return;
+ const header_len = std.math.add(usize, 4, std.math.mul(usize, count, 4) catch return) catch return;
+ if (header_len > len) return;
+ var outputs: [pardes.MAX_SELS][]const u8 = undefined;
+ var at = header_len;
+ for (0..count) |i| {
+ const off = 4 + i * 4;
+ const encoded_len: *const [4]u8 = @ptrCast(&input[off]);
+ const output_len: usize = std.mem.readInt(u32, encoded_len, .little);
+ const end = std.math.add(usize, at, output_len) catch return;
+ if (end > len) return;
+ outputs[i] = input[at..end];
+ at = end;
+ }
+ if (at != len) return;
+ s.core.update(.{ .pipe_resp = .{ .id = id, .success = true, .outputs = outputs[0..count] } });
+}
+
export fn pardes_file_changed(pane: u32, len_arg: u32) void {
const s = &(state orelse return);
if (pane >= pardes.MAX_PANES) return;
@@ -369,6 +400,22 @@ export fn pardes_effect_next() u32 {
putEffect(s, e.arg.slice());
break :blk 8;
},
+ // Process-capable embeddings receive exact command/cwd/input bytes:
+ // [command_len][cwd_len][count][input lengths...][all payloads...].
+ // The ordinary static browser surfaces this as `pardes-io` and stays
+ // inert because it has no process authority.
+ .pipe => |e| blk: {
+ effect_aux0 = e.id;
+ const request = s.core.pipeRequest(e.id) orelse break :blk 12;
+ putU32(s, @intCast(request.command.len));
+ putU32(s, @intCast(request.cwd.len));
+ putU32(s, @intCast(request.inputs.len));
+ for (request.inputs) |selection| putU32(s, @intCast(selection.bytes.len));
+ appendEffect(s, request.command);
+ appendEffect(s, request.cwd);
+ for (request.inputs) |selection| appendEffect(s, selection.bytes);
+ break :blk 12;
+ },
.watch => |e| blk: {
effect_aux0 = e.pane;
effect_aux1 = @intFromBool(e.on);