summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-30 21:14:06 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commita2c719779c9ce0f676fb159135675df6275e77bf (patch)
treedd4752d91d50f73a4b1ed7ff031bfea00c6aac62
parent27f8f6e0a5bb2751e1642db1e7e68b2cf72e50b0 (diff)
downloadpardes-a2c719779c9ce0f676fb159135675df6275e77bf.tar.gz
pardes-a2c719779c9ce0f676fb159135675df6275e77bf.zip
Forwarding pardes @pN for a pane the session has not is refused, "this session has no such pane", exit 1 and no pane made; one it has is looked at
@p999:1 was taken as a new file's name, so a pane named <cwd>/@p999 was made and the launch succeeded; an @pN the session did have was the same stray pane. A pane address is now checked against the session: one it has is a look at it, one it has not is refused with the reason and exit 1, as a refused name is. Co-Authored-By: Claude Opus 5.5 <[email protected]>
-rw-r--r--src/main.zig16
-rw-r--r--test/fs.py11
2 files changed, 25 insertions, 2 deletions
diff --git a/src/main.zig b/src/main.zig
index 6c5eaba1..3218fef1 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -106,6 +106,8 @@ fn forwardWords(err: anyerror, buf: []u8) []const u8 {
error.NotOneLine => "a file name is one line, and this one holds a newline",
error.NotAFileName => "names a directory, not a file",
error.NoWorkingDirectory => "this shell's working directory is gone",
+ error.NotAPaneAddress => "not a pane address: @p and a pane's number",
+ error.NoSuchPane => "this session has no such pane",
else => if (pardes.Messages.dialReason(err)) |why| why else words: {
var n: usize = 0;
for (@errorName(err), 0..) |c, i| {
@@ -450,6 +452,20 @@ fn nativeMain(init: std.process.Init) !void {
var home_buf: [4096]u8 = undefined;
const word = pardes.filesystem.expandHome(typed_word, &home_buf);
const target = @import("look.zig").parsePathLine(word);
+ // `@pN[:addr]` addresses a pane of this session: one it has is
+ // looked at, one it has not is refused, never a file of that name.
+ if (std.mem.startsWith(u8, target.path, pardes.config.pane_addr)) {
+ const digits = word[pardes.config.pane_addr.len .. std.mem.indexOfScalar(u8, word, ':') orelse word.len];
+ const serial = std.fmt.parseInt(u32, digits, 10) catch Refuse.with(init.io, word, error.NotAPaneAddress);
+ var name_buf: [64]u8 = undefined;
+ const name = try std.fmt.bufPrint(&name_buf, "/pane/{d}/name", .{serial});
+ const named = ninep_io.Client.read(arena, parent.dial, name, name) catch Refuse.with(init.io, word, error.NoSuchPane);
+ arena.free(named);
+ var command_buf: [4200]u8 = undefined;
+ const command = std.fmt.bufPrint(&command_buf, "{s}\n", .{word}) catch |err| Refuse.with(init.io, word, err);
+ ninep_io.Client.write(arena, parent.dial, look, command) catch |err| Refuse.with(init.io, word, err);
+ return;
+ }
var realbuf: [4096]u8 = undefined;
var newbuf: [4096]u8 = undefined;
const found_path: ?[]const u8 = if (pardes.filesystem.isVirtual(target.path)) target.path else if (pardes.filesystem.resolveOs(target.path, &realbuf)) |r| r.path else null;
diff --git a/test/fs.py b/test/fs.py
index eba5a5fa..7061c61f 100644
--- a/test/fs.py
+++ b/test/fs.py
@@ -1391,14 +1391,21 @@ def test(binary, quic=False):
assert refused.returncode == 1, refused
assert b'bad character in file name' in refused.stderr, refused.stderr
assert serials() == before, (serials(), before)
- # A name with a newline is said in words, not an error's name.
- for word, said in (('two\nlines.txt', b'a file name is one line'),):
+ # A pane address the session has not is refused in words, exit
+ # 1, no pane made for a file of that name; one it has is looked
+ # at. A name with a newline is said in words, not an error name.
+ for word, said in (('@p999:1', b'pardes: @p999:1: this session has no such pane'),
+ ('two\nlines.txt', b'a file name is one line')):
refused = subprocess.run([binary, word], cwd=root, env=env,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=10)
assert refused.returncode == 1, refused
assert said in refused.stderr, refused.stderr
assert b'NotOneLine' not in refused.stderr and b'NoSuchPane' not in refused.stderr
assert serials() == before, (serials(), before)
+ looked = subprocess.run([binary, '@p1:1'], cwd=root, env=env,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=10)
+ assert looked.returncode == 0, looked.stderr
+ assert serials() == before, (serials(), before)
orphan = launch('--wait')
assert orphan.poll() is None
assert orphan.wait(timeout=5) == 1