summaryrefslogtreecommitdiff
path: root/src/exec.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-30 15:39:27 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commita898c0cce8377150417e7d8dda8f952ffdf241ab (patch)
tree2197f55f9c58c80c5608b84f5510141ba6771cba /src/exec.zig
parentc04df904f2fa686cbe5ce0c078a96260af7b08bd (diff)
downloadpardes-a898c0cce8377150417e7d8dda8f952ffdf241ab.tar.gz
pardes-a898c0cce8377150417e7d8dda8f952ffdf241ab.zip
A right click on a diff line opens the place it names: its file, the hunk's new line, the line itself
In a diff pane (a .diff/.patch file, or a command pane's diff output), the look's own expansion, which its hover shows, takes a whole line for a `diff --git`, `---`, `+++` or `@@` line wherever the pointer is on it, markers included, and for a hunk line when the pointer is on its `+`, `-` or space. Then the look opens the file (a/ b/ dropped, timestamps cut) at the line from the hunk header and the lines above it: `@@` the hunk's first new line, context and added lines their own, a removed line the new line now where it was. `diff --git` and `+++` open the new file; `---` the old one, unless the `+++` under it names another. On a hunk line's code the expansion is its words, the prefix never one of them, and looks as ever. Other panes are untouched. Paths resolve in the repository (walking up to `.git` or `.jj` from the diff's directory, or a command pane's), then that directory. A file not here opens nothing and says `Look: b/x: no such file here`, or `deleted by this diff`. A 9P look writing a whole line of the diff does the same. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/exec.zig')
-rw-r--r--src/exec.zig46
1 files changed, 45 insertions, 1 deletions
diff --git a/src/exec.zig b/src/exec.zig
index 5e223f04..5a421f19 100644
--- a/src/exec.zig
+++ b/src/exec.zig
@@ -169,10 +169,54 @@ pub fn pointerOperand(p: *Pardes, pane: *Pane, clicked: Pane.Sel) PointerOperand
result.text = edit.currentSelText(p, pane);
return result;
}
+ // In a diff, a file or hunk header, and a hunk line pointed at on its
+ // `+`/`-`/` ` prefix, are looked at whole: the place the line names
+ // (look.diffLook). A hunk line's code is words, looked at as ever:
+ // the code's, the prefix never one of them.
+ var word_from: usize = 0;
+ if (clicked.r0 >= pane.tag_rows and clicked.r0 == clicked.r1 and clicked.c0 == clicked.c1 and row >= 0) diff: {
+ const lines = look.diffLines(p, pane) orelse break :diff;
+ const at: usize = @intCast(row);
+ if (at >= lines.len) break :diff;
+ const line = lines[at];
+ const target = @import("diff.zig").targetAt(lines, at, pane.file == null) orelse break :diff;
+ const on_prefix = col == 0 and line.len > 0 and std.mem.indexOfScalar(u8, "+- ", line[0]) != null;
+ switch (target.kind) {
+ .context, .added, .removed => if (!on_prefix) {
+ word_from = @intFromBool(line.len > 0 and std.mem.indexOfScalar(u8, "+- ", line[0]) != null);
+ break :diff;
+ },
+ else => {},
+ }
+ result.text = line;
+ p.diff_look = .{ .serial = pane.serial, .row = at };
+ const hi = std.math.cast(i32, line.len) orelse return result;
+ if (hi == 0) return result;
+ var expanded = clicked;
+ if (pane.file != null) {
+ result.file_word = .{ .row = row, .lo = 0, .hi = hi };
+ const first = pane.wrapRow(row, 0);
+ const last = pane.wrapRow(row, hi - 1);
+ if (first.row < 0 or last.row < 0) return result;
+ expanded.r0 = first.row + @as(i32, pane.tag_rows);
+ expanded.c0 = @as(i32, panes.File.gutterWidth(pane)) + panes.File.displayOffset(pane, row, first.at, 0);
+ expanded.r1 = last.row + @as(i32, pane.tag_rows);
+ expanded.c1 = @as(i32, panes.File.gutterWidth(pane)) + panes.File.displayEndOffset(pane, row, last.at, hi - 1);
+ } else {
+ const shown = if (raw) raw_line else line;
+ expanded.c0 = 0;
+ expanded.c1 = @as(i32, @intCast(panes.File.rawDisplayCol(shown, shown.len))) - 1;
+ }
+ result.preview = expanded;
+ result.expanded = expanded;
+ return result;
+ }
if (pane.file != null and clicked.r0 >= pane.tag_rows and clicked.r0 == clicked.r1 and clicked.c0 == clicked.c1) {
const line = panes.File.sourceLine(pane, row);
const source_col: usize = @intCast(@max(0, col));
- const b = look.expandedWord(line, source_col) orelse return result;
+ if (source_col < word_from or word_from > line.len) return result;
+ const word = look.expandedWord(line[word_from..], source_col - word_from) orelse return result;
+ const b: look.ExpandedWord = .{ .lo = word.lo + word_from, .hi = word.hi + word_from };
const lo = std.math.cast(i32, b.lo) orelse return result;
const hi = std.math.cast(i32, b.hi) orelse return result;
result.text = line[b.lo..b.hi];