summaryrefslogtreecommitdiff
path: root/src/builtins.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 12:06:13 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:14 -0300
commit8b18331f5e3f6c346b992019163ec3f5b6e6b721 (patch)
treef6e0236af8b0ac0428078d5ba512df10a1f3f43d /src/builtins.zig
parent990c2e1b184e9cb1fddd8eb1b05a472cfb113dde (diff)
downloadpardes-8b18331f5e3f6c346b992019163ec3f5b6e6b721.tar.gz
pardes-8b18331f5e3f6c346b992019163ec3f5b6e6b721.zip
Kill asks the host to signal at once and says when a shell has no job to signal
Kill queued a signal effect for later, so the job it saw running by its marks could have ended, and another started, before the signal went; and with job control off the job shares the shell's process group, so the host skipped it and Kill reported nothing. Kill now calls the host's kill_job while it holds the turn, and when the only job is the shell's own group says 'Kill: no job to signal', which also fails a write of Kill to ctl. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/builtins.zig')
-rw-r--r--src/builtins.zig36
1 files changed, 28 insertions, 8 deletions
diff --git a/src/builtins.zig b/src/builtins.zig
index 0154e707..93eae8ec 100644
--- a/src/builtins.zig
+++ b/src/builtins.zig
@@ -235,16 +235,23 @@ test "Kill stops the commands pardes typed, bare all and by name those that matc
const prompt = "\x1b]133;A;cl=line;aid=pardes\x07$ \x1b]133;B;aid=pardes\x07";
p.update(.{ .output = .{ .pane = @intCast(term), .bytes = prompt } });
while (p.nextEffect()) |_| {}
+ // The host the core asks: how many it was asked to stop, and whether
+ // their shells run jobs in groups of their own.
const killed = struct {
+ var asked: usize = 0;
+ var job_control = true;
+ const vtable: pardes.Host.VTable = .{ .kill_job = answer };
+ fn answer(_: ?*anyopaque, _: u8) bool {
+ asked += 1;
+ return job_control;
+ }
fn count(pp: *Pardes, line: []const u8) usize {
+ asked = 0;
_ = pp.executeBuiltinLine(pp.active, line);
- var n: usize = 0;
- while (pp.nextEffect()) |e| if (e == .signal_pty and e.signal_pty.sig == .command) {
- n += 1;
- };
- return n;
+ return asked;
}
};
+ p.host = .{ .vtable = &killed.vtable };
// Nothing running: nothing to stop, and never the shell.
try std.testing.expectEqual(@as(usize, 0), killed.count(p, "Kill"));
_ = exec.execute(p, term, "make -j8");
@@ -257,6 +264,15 @@ test "Kill stops the commands pardes typed, bare all and by name those that matc
try std.testing.expectEqual(@as(usize, 1), killed.count(p, "Kill ls make"));
try std.testing.expectEqual(@as(usize, 1), killed.count(p, "Kill"));
try std.testing.expect(!p.quit);
+ // With job control off there is no job apart from the shell: said, and
+ // over ctl the write fails with it.
+ killed.job_control = false;
+ p.fs.no_prompt = true;
+ try std.testing.expectEqual(@as(usize, 1), killed.count(p, "Kill"));
+ try std.testing.expectStringStartsWith(p.fs.failure[0..p.fs.failure_len], "Kill: no job to signal");
+ p.fs.no_prompt = false;
+ p.fs.failure_len = 0;
+ killed.job_control = true;
// Ended (a D mark): nothing to stop again.
p.update(.{ .output = .{ .pane = @intCast(term), .bytes = "\x1b]133;D;143;aid=pardes\x07" ++ prompt } });
while (p.nextEffect()) |_| {}
@@ -362,6 +378,7 @@ pub const Kill = struct {
pub fn run(c: Ctx) void {
const names = std.mem.trim(u8, c.arg orelse "", " \t\r\n");
var stopped = false;
+ var jobless = false;
for (c.p.panes, 0..) |slot, id| {
const pane = slot orelse continue;
if (!panes.Terminal.commandRunning(pane)) continue;
@@ -372,10 +389,13 @@ pub const Kill = struct {
if (std.mem.eql(u8, w, sent.word[0..sent.len])) break;
} else continue;
}
- c.p.emit(.{ .signal_pty = .{ .pane = @intCast(id), .sig = .command } });
- stopped = true;
+ // Asked of the host now, not queued: the job the marks say is
+ // running is the one signalled, not whatever runs by then.
+ if (c.p.hostKillJob(id)) stopped = true else jobless = true;
}
- if (!stopped and names.len > 0) c.p.reportError(c.id, "Kill", error.NoSuchCommand);
+ if (stopped) return;
+ if (jobless) return c.p.reportFailure(c.id, "Kill: no job to signal (its shell runs it without job control)");
+ if (names.len > 0) c.p.reportError(c.id, "Kill", error.NoSuchCommand);
}
};