summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-10-01 20:47:13 -0300
committerGabriel Schneider <[email protected]>2026-10-01 20:50:11 -0300
commit4bdeee602d1e642582ce91fdbd0da210797894e9 (patch)
tree0fda809a61bdd8271a2c90b9632fb25de3122e72
parente1550ca15093e8190c3bf9a9809e0c78b7541ac9 (diff)
downloadpardes-4bdeee602d1e642582ce91fdbd0da210797894e9.tar.gz
pardes-4bdeee602d1e642582ce91fdbd0da210797894e9.zip
An exec written back to event on a diff line (MX0 0) takes the word there, a header's, a hunk header's or the marker's, never the address; only a look takes it
Co-Authored-By: Claude Opus 5.5 <[email protected]>
-rw-r--r--src/look.zig13
-rw-r--r--src/ninep/events.zig8
2 files changed, 16 insertions, 5 deletions
diff --git a/src/look.zig b/src/look.zig
index 3d02802a..030aa432 100644
--- a/src/look.zig
+++ b/src/look.zig
@@ -2428,7 +2428,7 @@ test "a click, a 9P whole-line look and an empty event write-back take one expan
// An empty record written back to event, at the same byte.
const body = pane.file.?.content;
const line_start = modal.lineStartOffset(body, at.row);
- const written = pardes.ctlfs.events.expandAt(p, pane, body, line_start + at.col, true);
+ const written = pardes.ctlfs.events.expandAt(p, pane, body, line_start + at.col, true, true);
try std.testing.expectEqualStrings(at.want, written);
// A 9P look of the whole line.
if (at.whole_line) {
@@ -2518,7 +2518,7 @@ test "every entry point to Look takes one expansion: a diff line and a file:12:5
},
.event_write_back => {
const body = pane.file.?.content;
- const text = pardes.ctlfs.events.expandAt(p, pane, body, modal.lineStartOffset(body, case.row) + case.col, true);
+ const text = pardes.ctlfs.events.expandAt(p, pane, body, modal.lineStartOffset(body, case.row) + case.col, true, true);
lookAt(p, 0, p.scratch.allocator().dupe(u8, text) catch unreachable);
},
}
@@ -2563,6 +2563,15 @@ test "a tag word looked at by a click and by Enter is one record to an event rea
pane.body.cur_col = 0;
try std.testing.expectEqualStrings("+line", exec.operandAt(p, pane, cursorWordSel(p, pane), false, false).text.?);
try std.testing.expectEqualStrings("src/x.zig:1", exec.operandAt(p, pane, cursorWordSel(p, pane), false, true).text.?);
+ // An exec written back to event (`MX0 0`) takes the word too, on a
+ // header, a hunk header and a marker column; a look, the address.
+ const body = pane.file.?.content;
+ const events = pardes.ctlfs.events;
+ try std.testing.expectEqualStrings("diff", events.expandAt(p, pane, body, 0, true, false));
+ try std.testing.expectEqualStrings("@@", events.expandAt(p, pane, body, modal.lineStartOffset(body, 3), true, false));
+ try std.testing.expectEqualStrings("+line", events.expandAt(p, pane, body, modal.lineStartOffset(body, 5), true, false));
+ try std.testing.expectEqualStrings("src/x.zig", events.expandAt(p, pane, body, 0, true, true));
+ try std.testing.expectEqualStrings("src/x.zig:1", events.expandAt(p, pane, body, modal.lineStartOffset(body, 5), true, true));
// An event reader on the pane.
const event = pardes.ctlfs.Node.of(pane.serial, .event);
diff --git a/src/ninep/events.zig b/src/ninep/events.zig
index 5b2a763e..3910ac05 100644
--- a/src/ninep/events.zig
+++ b/src/ninep/events.zig
@@ -728,11 +728,13 @@ fn scanNumber(data: []const u8, i: *usize, overflow: *bool) ?u32 {
/// An empty range written back: what a click at `at` takes, as the mouse's
/// does (exec.pointerOperand). In a diff pane's body that is look.diffClick's
/// answer, the line's address or its code's words.
-pub fn expandAt(p: *Pardes, pane: *Pane, whole: []const u8, at: usize, in_body: bool) []const u8 {
+/// `for_look`: only a look in a body takes a diff line's address
+/// (exec.operandAt); an exec takes the word there, as anywhere.
+pub fn expandAt(p: *Pardes, pane: *Pane, whole: []const u8, at: usize, in_body: bool, for_look: bool) []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;
var word_from: usize = 0;
- if (in_body) diff: {
+ if (in_body and for_look) diff: {
const row = std.mem.count(u8, whole[0..start], "\n");
// Only when the served line is the one the diff reads there.
const lines = look.diffLines(p, pane) orelse break :diff;
@@ -794,7 +796,7 @@ pub fn writeEvent(p: *Pardes, asked: Req, id: usize) Reply {
// 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(p, pane, whole, lo, !r.action.onTag()) else whole[lo..hi];
+ const said = if (r.q0 == r.q1) r.text orelse expandAt(p, pane, whole, lo, !r.action.onTag(), r.action == .body_look or r.action == .tag_look) 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