summaryrefslogtreecommitdiff
path: root/src/ninep/ctl.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep/ctl.zig')
-rw-r--r--src/ninep/ctl.zig40
1 files changed, 38 insertions, 2 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index c1f78bab..70e06d4b 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -51,8 +51,20 @@ fn noteResult(p: *Pardes, serial: u32) void {
/// Runs one look or exec from the pane `id`, then records the panes it
/// created; failing that, a look records the pane it focused and an exec
/// the pane it acted on (even one it closed).
-fn run(p: *Pardes, id: usize, exec: bool, text: []const u8) void {
+fn run(p: *Pardes, id: usize, exec: bool, text: []const u8, own: bool) void {
const context = p.panes[id].?.serial;
+ // A pane an event reader holds hears its clicks instead of acting on
+ // them (editors/acme/look.c:53 and exec.c:173 send them to winevent),
+ // and a line written to its own look or exec is a click on it; the
+ // reader writes the record back to have it done.
+ if (own and p.panes[id].?.fs.readers > 0) {
+ const named = std.meta.stringToEnum(Builtin, exec_line.commandText(text)) != null;
+ var flag: u32 = pardes.ctlfs.events.flag_expansion;
+ if (named) flag |= pardes.ctlfs.events.flag_builtin;
+ if (!exec and !named and std.mem.indexOfAny(u8, text, "/.:") != null) flag |= pardes.ctlfs.events.flag_filename;
+ _ = pardes.ctlfs.events.noteAction(p, id, if (exec) .body_exec else .body_look, 0, 0, flag, text);
+ return noteResult(p, context);
+ }
const before = Serials.snapshot(p);
if (exec) _ = pardes.exec.execute(p, id, text) else look.lookAt(p, id, text);
const after = Serials.snapshot(p);
@@ -82,7 +94,7 @@ pub fn command(p: *Pardes, req: Req, serial: ?u32, exec: bool) Reply {
if (!apply) continue;
const id = if (serial) |s| p.paneBySerial(s) orelse break else p.active;
if (p.panes[id] == null) return Reply.fail(req.tag, E.NOENT);
- run(p, id, exec, text);
+ run(p, id, exec, text, serial != null);
}
}
return .{ .tag = req.tag, .written = @intCast(req.data.len) };
@@ -858,3 +870,27 @@ test "exec Save writes the named file through the host" {
try testing.expect(!pane_files.dirtyOf(pane));
try testing.expectEqualStrings(pane.file.?.content, p.fallback.get("/tmp/renamed.txt").?);
}
+
+test "a pane's own look and exec go to the event reader holding it, which writes them back to act" {
+ const gpa = testing.allocator;
+ const p = try withFile(gpa, "Msg routed\n");
+ defer p.deinit();
+ const serial = serialOf(p);
+ const event = Node.of(serial, .event);
+ const h = call(p, .{ .tag = 1, .op = .open, .node = event }).reply.handle;
+ try testing.expectEqual(tree.Status.ok, wr(p, Node.of(serial, .exec), "Msg routed\n").reply.status);
+ // Not done: the reader has it, as it would a middle click.
+ const pane = p.panes[0].?;
+ try testing.expect(std.mem.indexOf(u8, pane.msg[0..pane.msg_len], "routed") == null);
+ const record = call(p, .{ .tag = 2, .op = .read, .node = event, .handle = h, .size = 256 }).bytes;
+ try testing.expectEqualStrings("FX0 0 2 10 Msg routed\n", record);
+ // Written back, it is done.
+ try testing.expectEqual(tree.Status.ok, wr(p, event, record).reply.status);
+ try testing.expect(std.mem.indexOf(u8, pane.msg[0..pane.msg_len], "routed") != null);
+ try testing.expectEqual(tree.Status.ok, wr(p, Node.of(serial, .look), "one.txt:3\n").reply.status);
+ try testing.expectEqualStrings("FL0 0 6 9 one.txt:3\n", call(p, .{ .tag = 3, .op = .read, .node = event, .handle = h, .size = 256 }).bytes);
+ _ = call(p, .{ .tag = 4, .op = .release, .node = event, .handle = h });
+ // With no reader, the root's and the pane's act at once.
+ try testing.expectEqual(tree.Status.ok, wr(p, Node.of(serial, .exec), "Msg direct\n").reply.status);
+ try testing.expect(std.mem.indexOf(u8, pane.msg[0..pane.msg_len], "direct") != null);
+}