From cbcdf01764e2e144a821643c3a8e9a5ad39eda2e Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Sat, 1 Aug 2026 22:44:11 -0300 Subject: search look goldens: fsearch/grep/psearch/rsearch updated --- src/pardes.zig | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'src/pardes.zig') diff --git a/src/pardes.zig b/src/pardes.zig index 9b21ec79..0c7c0363 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -3857,15 +3857,29 @@ pub const Pardes = struct { // still gets its own buffer, and that IS the old rule: two searches are // two lists, both stay open at their sizes, and the new one stacks // directly below this pane (placeDoc). Focus stays here either way. - if (output_pane.resultsFrom(p, pane, from)) { - const rp = p.panes[pane.search_pane.?].?; - const rf = &rp.file.?; - if (std.mem.eql(u8, rf.output.?.arg(), pat)) { - file_pane.setContent(p, rf, content); - rf.scroll = 0; - pane.search_row = anchor; - return; - } + // ...and it is ANY open list this search already filled, not only the + // one n/N are armed on: search `foo`, then `bar`, then `foo` again and + // the third search re-arms foo's own buffer rather than opening its + // identical twin below it. Same directory only — the rows are written + // relative to it, so another dir's list is a different list. Never the + // searching pane itself (a `/` inside a +Search writes its own rows). + for (p.panes, 0..) |slot, i| { + if (i == id) continue; + const rp = slot orelse continue; + const rf = if (rp.file) |*f| f else continue; + const o = rf.output orelse continue; + if (!std.meta.eql(o.from, from) or !std.mem.eql(u8, o.arg(), pat)) continue; + if (!std.mem.eql(u8, std.fs.path.dirname(rf.path) orelse "", dir)) continue; + // a refill that changes NOTHING keeps its place: a right click on + // an already-armed word is an `n`, and throwing the list back to + // the top only to scroll down to the stepped row is a jump with no + // information in it. + const same = std.mem.eql(u8, rf.content, content); + file_pane.setContent(p, rf, content); + if (!same) rf.scroll = 0; + pane.search_pane = i; + pane.search_row = anchor; + return; } const free = p.freeSlot() orelse { p.gpa.free(content); @@ -3910,7 +3924,12 @@ pub const Pardes = struct { rp.cur_row = r; rp.cur_col = 0; rp.cur_pinned = true; - rp.ensureCursorVisible(); + // in view, but WITHOUT scrolloff: a results pane is short, and a + // three-row margin on a seven-row one means every single n scrolls the + // list out from under the eye. A row already on screen moves nothing. + const off = rp.scroll(); + const last = off + @as(i32, rp.rows) - 1; + if (r < off) rp.scrollBy(r - off) else if (r > last) rp.scrollBy(r - last); const ln = modal.lineSlice(rf.content, @intCast(step)); // Both arms are the BUILTIN, run on the results pane — the same call a // middle or right click on that row would make, so a stepped row and a -- cgit v1.3