diff options
| -rw-r--r-- | src/main.zig | 16 | ||||
| -rw-r--r-- | test/fs.py | 11 |
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; @@ -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 |
