summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/builtins.zig22
-rw-r--r--src/detached/server.zig1
-rw-r--r--src/pardes.zig17
3 files changed, 39 insertions, 1 deletions
diff --git a/src/builtins.zig b/src/builtins.zig
index cb588ba3..bc9bb075 100644
--- a/src/builtins.zig
+++ b/src/builtins.zig
@@ -742,9 +742,29 @@ pub const Attach = struct {
if (comptime enabled) ask(c) else unreachable;
}
fn ask(c: Ctx) void {
- const name = c.arg orelse "";
+ const name = std.mem.trim(u8, c.arg orelse "", " \t\r\n");
if (name.len > pardes.attach_name_max)
return c.p.reportError(c.id, comptime word(@This()), error.NameTooLong);
+ // A detached session has no terminal to move: bare, there is no
+ // "the one session there" but itself; a name is said for what it is.
+ if (c.p.opts.detached_session) {
+ if (name.len == 0) return c.p.reportFailure(c.id, "wrong #args in control message \"Attach\": a detached session names the session");
+ // A session is its socket, `pardes-detached-<name>.sock` beside
+ // the 9P ones (detached/server.zig socketPath); not imported, as
+ // the core links no frontend's code.
+ const ninep_io = @import("9p_io.zig");
+ var dir_buf: [ninep_io.sun_path_len:0]u8 = undefined;
+ var path_buf: [ninep_io.sun_path_len + 64:0]u8 = undefined;
+ const exists = if (ninep_io.socketDir(&dir_buf)) |dir|
+ (if (std.fmt.bufPrintSentinel(&path_buf, "{s}/pardes-detached-{s}.sock", .{ dir, name }, 0)) |path| ninep_io.statNoFollow(path) != null else |_| false)
+ else
+ false;
+ var said: [pardes.attach_name_max + 96]u8 = undefined;
+ return c.p.reportFailure(c.id, if (exists)
+ std.fmt.bufPrint(&said, "Attach: {s}: a detached session has no terminal to attach; Attach from a frontend", .{name}) catch "Attach: a detached session has no terminal to attach"
+ else
+ std.fmt.bufPrint(&said, "Attach: {s}: no such session", .{name}) catch "Attach: no such session");
+ }
c.p.emit(.{ .attach = .{ .pane = @intCast(c.id), .name = .from(name) } });
}
};
diff --git a/src/detached/server.zig b/src/detached/server.zig
index 001acc47..2b87bd60 100644
--- a/src/detached/server.zig
+++ b/src/detached/server.zig
@@ -1243,6 +1243,7 @@ pub fn run(init: std.process.Init, opts: pardes.Options, name: []const u8) !void
// and an attaching frontend its own.
options.cols = detached_cols;
options.rows = detached_rows;
+ options.detached_session = true;
options.image_allocator = allocs.image;
options.pdf_allocator = allocs.pdf;
options.tree_sitter_allocator = allocs.tree_sitter;
diff --git a/src/pardes.zig b/src/pardes.zig
index f479f44d..4472df8f 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -573,6 +573,20 @@ test "Attach asks for a session and tears nothing down" {
try std.testing.expect(p.panes[0] != null);
}
+test "Attach in a detached session: bare is wrong #args, a name no session has says so, and nothing is asked" {
+ if (comptime !can_attach) return;
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .detached_session = true });
+ defer p.deinit();
+ while (p.nextEffect()) |_| {}
+ const pane = p.panes[0].?;
+ try std.testing.expect(p.executeBuiltinLine(0, "Attach"));
+ try std.testing.expect(drainForAttach(p) == null);
+ try std.testing.expectStringStartsWith(pane.msg[0..pane.msg_len], "wrong #args");
+ try std.testing.expect(p.executeBuiltinLine(0, "Attach zz-no-such-session-qq"));
+ try std.testing.expect(drainForAttach(p) == null);
+ try std.testing.expectEqualStrings("Attach: zz-no-such-session-qq: no such session", pane.msg[0..pane.msg_len]);
+}
+
test "Detach asks the frontend to leave, and says so when there is nothing to leave" {
if (comptime !can_attach) return; // compiled out where nothing polls `takeAttach` — see `can_attach`
const gpa = std.testing.allocator;
@@ -4199,6 +4213,9 @@ pub const Options = struct {
/// load a dump of another instance instead of spawning shells (acme -l)
load_path: ?[]const u8 = null,
nested: bool = false,
+ /// The core of a `--detach` session (detached/server.zig): it has no
+ /// terminal of its own, so Attach there is refused with why.
+ detached_session: bool = false,
startup_config: ?[]const u8 = null,
ninep_name: []const u8 = "",
ninep_tcp: ?[]const u8 = null,