summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 07:21:10 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commit97780909cbe0f4c62dfb9b012bff3fe7e7ec32f9 (patch)
tree35eef2c6ceca2dd6e3cf8047d66d6134c929245d
parenta0bca6764a6a425b71e1567ff9d49f9828c5813c (diff)
downloadpardes-97780909cbe0f4c62dfb9b012bff3fe7e7ec32f9.tar.gz
pardes-97780909cbe0f4c62dfb9b012bff3fe7e7ec32f9.zip
An event record never carries flag 2, as no expansion record follows; flag 1 reads the first word
In acme flag 2 promises a second record with the expanded range, and acme's libraries read one. F records set it always and a click with no range known set it, with none following: a library then took the next event for it. Records here carry the word already, so 2 is never set. Flag 1 now reads the first word as acme's lookup does, so `Msg hi` is 1. Co-Authored-By: Claude Opus 5.5 <[email protected]>
-rw-r--r--docs/fs.md8
-rw-r--r--src/exec.zig9
-rw-r--r--src/mouse.zig8
-rw-r--r--src/ninep/ctl.zig13
4 files changed, 27 insertions, 11 deletions
diff --git a/docs/fs.md b/docs/fs.md
index 23c87216..5a4ece78 100644
--- a/docs/fs.md
+++ b/docs/fs.md
@@ -771,9 +771,11 @@ files, the editor's own lines), `K` (the keyboard) or `M` (the mouse); the
action's case says where: `x`/`l` a click executed or looked at in the tag
(its offsets count the tag's whole text, path included, as `tag` reads),
`X`/`L` in the body, `I`/`D` text put in or taken out of the body, `i`/`d`
-of the tag. The flag is acme's: 1 the text is a builtin's word, 2 the range
-was expanded from a click (a second record gives the original range), 4 (a
-look) the text is a file name or address, 8 (an exec) chorded: two records
+of the tag. The flag is acme's: 1 the text's first word is a builtin's, 2
+an expansion record follows (acme's look.c:42-43, exec.c:154-157; pardes
+never sends one: a click's record already carries the word it took, its
+range and text, so 2 is never set, whatever the origin), 4 (a look) the
+text is a file name or address, 8 (an exec) chorded: two records
follow, the argument's text and where it came from, `<file>:#q0,#q1`, each
with no place of its own: offsets `0 0` and flag 0, `Mx0 0 0 5 hello` (as
acme's exec.c:182 writes them).
diff --git a/src/exec.zig b/src/exec.zig
index aee2e1e5..2b0c90cb 100644
--- a/src/exec.zig
+++ b/src/exec.zig
@@ -733,6 +733,15 @@ pub fn commandText(txt: []const u8) []const u8 {
return cmd;
}
+/// The builtin a command line's first word names, as acme's lookup reads
+/// only the first word (editors/acme/exec.c, lookup): what an event's
+/// flag 1 says.
+pub fn namesBuiltin(txt: []const u8) bool {
+ const cmd = commandText(txt);
+ const end = std.mem.indexOfAny(u8, cmd, " \t") orelse cmd.len;
+ return std.meta.stringToEnum(Builtin, cmd[0..end]) != null;
+}
+
pub fn executeBuiltinLine(p: *Pardes, id: usize, txt: []const u8) bool {
const cmd = commandText(txt);
if (cmd.len == 0 or p.exec_depth >= max_exec_depth) return false;
diff --git a/src/mouse.zig b/src/mouse.zig
index 9eefa9a1..5bfd92ee 100644
--- a/src/mouse.zig
+++ b/src/mouse.zig
@@ -723,10 +723,12 @@ fn reportGesture(
(if (on_tag) .tag_look else .body_look)
else
(if (on_tag) .tag_exec else .body_exec);
- const named = std.meta.stringToEnum(Builtin, exec.commandText(text)) != null;
+ const named = exec.namesBuiltin(text);
const range = gestureRange(p, id, text, on_tag, operand);
+ // No flag 2: the record already carries the word a click took, its
+ // range and text, and in acme flag 2 promises a second record with them
+ // (editors/acme/exec.c:154-183, look.c:42-68), which none follows here.
var flag: u32 = if (named) ctlfs.events.flag_builtin else 0;
- if (range.q0 == range.q1 and text.len > 0) flag |= ctlfs.events.flag_expansion;
if (is_look) {
if (!named and std.mem.indexOfAny(u8, text, "/.:") != null) flag |= ctlfs.events.flag_filename;
} else if (chord_arg != null) flag |= ctlfs.events.flag_chorded;
@@ -1670,7 +1672,7 @@ test "a chorded exec an event reader holds is told with its argument, and writte
@memcpy(g[0..bytes.len], bytes);
r.* = g[0..bytes.len];
}
- try std.testing.expect(std.mem.endsWith(u8, records[0], " 11 3 Msg\n")); // builtin|expansion|chorded
+ try std.testing.expect(std.mem.endsWith(u8, records[0], " 9 3 Msg\n")); // builtin|chorded, no expansion record
try std.testing.expectEqualStrings("X0 0 0 8 arg-text\n", records[1][1..]);
try std.testing.expect(std.mem.endsWith(u8, records[2], "test.txt:#9,#17\n"));
// Written back whole, it runs with its argument.
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 665913fc..709f017f 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -60,8 +60,10 @@ pub fn run(p: *Pardes, id: usize, exec: bool, text: []const u8, in_tag: bool) vo
// record back to have it done.
// A click in a column's or the workspace's tag is not the pane's.
if (!in_tag 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;
+ const named = exec_line.namesBuiltin(text);
+ // No flag 2: a written line was never expanded from a click, and no
+ // expansion record follows (editors/acme/look.c:42-43, exec.c:154-157).
+ var flag: u32 = 0;
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);
@@ -1453,16 +1455,17 @@ test "a pane's own look and exec go to the event reader holding it, which writes
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);
+ // Flag 1: its first word is a builtin; no 2, no expansion follows.
+ try testing.expectEqualStrings("FX0 0 1 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);
+ try testing.expectEqualStrings("FL0 0 4 9 one.txt:3\n", call(p, .{ .tag = 3, .op = .read, .node = event, .handle = h, .size = 256 }).bytes);
// The root's is a click at the pane with the keyboard, this one.
try testing.expectEqual(tree.Status.ok, wr(p, root_exec, "Msg rooted\n").reply.status);
try testing.expect(std.mem.indexOf(u8, pane.msg[0..pane.msg_len], "rooted") == null);
- try testing.expectEqualStrings("FX0 0 2 10 Msg rooted\n", call(p, .{ .tag = 5, .op = .read, .node = event, .handle = h, .size = 256 }).bytes);
+ try testing.expectEqualStrings("FX0 0 1 10 Msg rooted\n", call(p, .{ .tag = 5, .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);