summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ninep/events.zig30
1 files changed, 29 insertions, 1 deletions
diff --git a/src/ninep/events.zig b/src/ninep/events.zig
index 63405781..fa90fe71 100644
--- a/src/ninep/events.zig
+++ b/src/ninep/events.zig
@@ -688,6 +688,15 @@ fn scanNumber(data: []const u8, i: *usize) ?u32 {
}
/// Writing a Look or Exec record back performs the action it names.
+/// The word a click at `at` expands to: the file name or word run under it
+/// on its line (look.expandedWord), else nothing.
+fn expandAt(whole: []const u8, at: usize) []const u8 {
+ const start = if (std.mem.lastIndexOfScalar(u8, whole[0..at], '\n')) |nl| nl + 1 else 0;
+ const end = std.mem.indexOfScalarPos(u8, whole, at, '\n') orelse whole.len;
+ const b = look.expandedWord(whole[start..end], at - start) orelse return "";
+ return whole[start + b.lo .. start + b.hi];
+}
+
pub fn writeEvent(p: *Pardes, asked: Req, id: usize) Reply {
const pane0 = p.panes[id] orelse return Reply.fail(asked.tag, E.NOENT);
// Its last record needs no newline, as every other line file's last
@@ -723,7 +732,10 @@ pub fn writeEvent(p: *Pardes, asked: Req, id: usize) Reply {
const whole = if (r.action.onTag()) pane_files.tagOf(p, pane) else pane_files.bodyOf(pane);
const lo = @min(@as(usize, r.q0), whole.len);
const hi = @max(lo, @min(@as(usize, r.q1), whole.len));
- const said = if (r.q0 == r.q1) r.text orelse whole[lo..hi] else whole[lo..hi];
+ // An empty range with no text is a click at that point: expanded as
+ // the click would be, to the word or file name under it (acme's
+ // expand, look.c).
+ const said = if (r.q0 == r.q1) r.text orelse expandAt(whole, lo) else whole[lo..hi];
const text = p.scratch.allocator().dupe(u8, said) catch continue;
switch (r.action) {
// A body's click written back is done as the click would have
@@ -1237,6 +1249,22 @@ test "a pane named before it is announced has its new under that name, and no re
try testing.expect(std.mem.indexOf(u8, after.bytes, try std.fmt.bufPrint(&want, "rename {d} ", .{shell.serial})) == null);
}
+test "an empty range written back is expanded as a click at that point would be" {
+ const p = try withFile(testing.allocator, "abc def abc\nx Newcol y\n");
+ defer p.deinit();
+ const serial = serialOf(p);
+ const pane = p.panes[p.paneBySerial(serial).?].?;
+ const event = Node.of(serial, .event);
+ // A look at 1 is a look at `abc`: from dot, past the first, the next.
+ pane_files.setDot(pane, .{ .q0 = 4, .q1 = 4 });
+ try testing.expectEqual(Status.ok, wr(p, event, "ML1 1\n").reply.status);
+ try testing.expectEqual(pane_files.State.Range{ .q0 = 8, .q1 = 11 }, pane_files.dotOf(pane));
+ // An exec at 15 runs the word there, `Newcol`.
+ const cols = p.ncol;
+ try testing.expectEqual(Status.ok, wr(p, event, "MX15 15\n").reply.status);
+ try testing.expectEqual(cols + 1, p.ncol);
+}
+
test "opens of the log share the open records, and a closed one frees its record" {
const gpa = testing.allocator;
const p = try withFile(gpa, "x\n");