From 3ddd34bcd94ba95d9cacbf6afcb9f89a16a414ce Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Thu, 1 Oct 2026 22:58:12 -0300 Subject: Edit's w to a file changed on disk since read is refused once, as Save is (w again to overwrite), the rest of an X/'/w written and the refused named; Edit filters get a pane command's environment ($PARDES_MOUNT, $PARDES_9P, $PARDES_PID, $winid); an Edit with no commands runs beside one whose commands run unless it touches a file that one changes, refused busy (EBUSY) as is a second Edit with commands Co-Authored-By: Claude Opus 5.5 --- src/selection_pipe.zig | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'src/selection_pipe.zig') diff --git a/src/selection_pipe.zig b/src/selection_pipe.zig index fb6587f9..66444b04 100644 --- a/src/selection_pipe.zig +++ b/src/selection_pipe.zig @@ -32,6 +32,9 @@ pub const Request = struct { shell: []const u8 = "", /// Nonzero: `stop(token)` from another thread kills its commands. token: u32 = 0, + /// The commands' environment, `NAME=value` each, when given; else this + /// process's. + env: []const []const u8 = &.{}, }; /// Worker-owned snapshot. `copy` is intentionally called synchronously while @@ -47,6 +50,7 @@ pub const Job = struct { cwds: [][]u8 = &.{}, shell: []u8 = &.{}, token: u32 = 0, + env: [][]u8 = &.{}, pub fn copy(gpa: std.mem.Allocator, request: Request) !*Job { const job = try gpa.create(Job); @@ -68,6 +72,8 @@ pub const Job = struct { job.cwds = try dupeAll(gpa, request.cwds.len, request.cwds, true); errdefer freeAll(gpa, job.cwds); job.shell = try gpa.dupe(u8, request.shell); + errdefer gpa.free(job.shell); + job.env = try dupeAll(gpa, request.env.len, request.env, false); return job; } @@ -100,6 +106,7 @@ pub const Job = struct { freeAll(gpa, job.commands); freeAll(gpa, job.cwds); gpa.free(job.shell); + freeAll(gpa, job.env); gpa.destroy(job); } }; @@ -232,7 +239,7 @@ pub fn runOne( cwd: []const u8, input: []const u8, ) Outcome { - return runIn(gpa, io, "", command, cwd, input, 0); + return runIn(gpa, io, "", command, cwd, input, 0, &.{}); } /// The commands running for a stoppable request (`Request.token`), so @@ -306,6 +313,7 @@ pub fn runIn( cwd: []const u8, input: []const u8, token: u32, + env: []const []const u8, ) Outcome { const fail = struct { fn k(kind: Failure.Kind) Outcome { @@ -320,6 +328,12 @@ pub fn runIn( // child inherits, is cleared across the fork (only the tty's SIGWINCH is // ever blocked, and its default is to be ignored). A handler resets at // exec by itself, and nothing here is ignored. + var environ: std.process.Environ.Map = .init(gpa); + defer environ.deinit(); + for (env) |line| { + const eq = std.mem.indexOfScalar(u8, line, '=') orelse continue; + environ.put(line[0..eq], line[eq + 1 ..]) catch return fail.k(.spawn); + } const none = std.posix.sigemptyset(); var kept: std.posix.sigset_t = undefined; std.posix.sigprocmask(std.posix.SIG.SETMASK, &none, &kept); @@ -327,6 +341,7 @@ pub fn runIn( var child = std.process.spawn(io, .{ .argv = &.{ if (shell.len == 0) "/bin/sh" else shell, "-c", command }, .cwd = if (cwd.len == 0) .inherit else .{ .path = cwd }, + .environ_map = if (env.len > 0) &environ else null, .stdin = .pipe, .stdout = .pipe, .stderr = .pipe, @@ -435,7 +450,7 @@ pub fn runJob(gpa: std.mem.Allocator, io: std.Io, job: *const Job) Response { response.failure = .{ .kind = .signal, .index = @intCast(i) }; break; } - const output = switch (runIn(gpa, io, job.shell, command, cwd, input, job.token)) { + const output = switch (runIn(gpa, io, job.shell, command, cwd, input, job.token, job.env)) { .ok => |bytes| bytes, .failed => |f| { // WHICH selection, because with several cursors "it failed" is -- cgit v1.3