From 6a43880a7ef6899f0d66c1b0a63a7e7b5610236a Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 3 Aug 2026 00:32:11 -0300 Subject: pipe selections through shell commands --- src/web.zig | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'src/web.zig') 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); -- cgit v1.3