From 9dba9742f4f2071fd85c67c3a7fe311b7f37617c Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Thu, 1 Oct 2026 17:50:26 -0300 Subject: Enter and Tab on a tag word tell an event reader as a click on it does, at its place in the tag; only a look takes a diff line's address, an exec there takes the word (follows vpmzwuzk) Co-Authored-By: Claude Opus 5.5 --- src/look.zig | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'src/look.zig') diff --git a/src/look.zig b/src/look.zig index 0df1f307..a2aa5be0 100644 --- a/src/look.zig +++ b/src/look.zig @@ -2524,6 +2524,68 @@ test "every entry point to Look takes one expansion: a diff line and a file:12:5 } } +test "a tag word looked at by a click and by Enter is one record to an event reader; an exec on a diff line takes its word, never the address" { + if (!platform_has_fs) return; + const diff_text = + \\diff --git a/src/x.zig b/src/x.zig + \\--- a/src/x.zig + \\+++ b/src/x.zig + \\@@ -1,1 +1,1 @@ + \\-old + \\+line one + \\ + ; + var fx: DiffFixture = undefined; + try fx.init(true, &.{.{ "src/x.zig", "line one\n" }}, diff_text); + defer fx.tmp.cleanup(); + const th = @import("ninep/testing.zig"); + const p = try Pardes.init(std.testing.allocator, .{ .cols = 100, .rows = 30 }); + defer p.deinit(); + const pane = try fx.open(p, diff_text); + pane.tag_expanded = true; + var frame = std.heap.ArenaAllocator.init(std.testing.allocator); + defer frame.deinit(); + p.sync(); + _ = try p.render(frame.allocator()); + + // An exec on the `+` of a hunk line takes the word there; a look, the + // address the line names. + pane.body.cur_row = 5; + 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 event reader on the pane. + const event = pardes.ctlfs.Node.of(pane.serial, .event); + const opened = th.call(p, .{ .tag = 1, .op = .open, .node = event }); + defer _ = th.call(p, .{ .tag = 9, .op = .release, .node = event, .handle = opened.reply.handle }); + const tag = try tagline.tagText(p, p.scratch.allocator(), pane); + const at: u16 = @intCast(std.mem.lastIndexOf(u8, tag, "Del").?); + // A B3 click on the tag's Del, where the tag as shown has it... + const shown = (try tagline.shownTag(p, p.scratch.allocator(), pane)).text; + const shown_at = std.mem.lastIndexOf(u8, shown, "Del").?; + const shown_row: u16 = @intCast(std.mem.count(u8, shown[0..shown_at], "\n")); + const line_start = if (std.mem.lastIndexOfScalar(u8, shown[0..shown_at], '\n')) |nl| nl + 1 else 0; + const x = p.rects[0].x + TAG_TEXT_INSET + @as(u16, @intCast(panes.File.displayWidth(shown[line_start..shown_at]))) + 1; + const y = p.rects[0].y + shown_row; + p.update(.{ .mouse = .{ .button = .right, .kind = .press, .col = x, .row = y } }); + p.update(.{ .mouse = .{ .button = .right, .kind = .release, .col = x, .row = y } }); + var clicked_buf: [128]u8 = undefined; + const clicked = th.rd(p, event, 0, 4096).bytes; + @memcpy(clicked_buf[0..clicked.len], clicked); + // ...and Enter with the tag's cursor on it. + tagline.enterTag(p, pane); + pane.tag.mode = .normal; + pane.tag.cur_row = 0; + pane.tag.cur_col = at + 1; + p.update(.{ .key = .{ .cp = Key.enter } }); + const keyed = th.rd(p, event, 0, 4096).bytes; + // The same record but for its origin, mouse or keyboard. + try std.testing.expect(clicked.len > 2); + try std.testing.expectEqualStrings(clicked_buf[1..clicked.len], keyed[1..]); + try std.testing.expect(p.panes[0] != null); +} + test "Look outside a diff pane expands and looks as ever" { const p = try Pardes.init(std.testing.allocator, .{ .cols = 100, .rows = 30 }); defer p.deinit(); -- cgit v1.3