From 8fc6bb0633d7992dad6b28a2d36730689226e096 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 21 Sep 2026 23:23:22 -0300 Subject: Stack a pane's transient lines instead of letting the last one win the row A pane's message, its pending leader chord and a prompt waiting for input all wanted the same row above the tagline. The prompt won it, the leader drew over whatever was there on the right, and renderBodyLayer recomputed "is anything down there" inline to reserve a single row. Three claimants, one row, and two places deciding. Pane.Notices is that decision in one place: a short ordered list of the lines a pane is showing, rebuilt every frame by collectNotices from the state that owns each one. The body layer reserves exactly notices.len rows, the way it already reserves rows for sticky context headers, and the paint pass walks the list and gives each line a row of its own, stacked upward from the tagline. Nothing stores a second copy of the truth, so a line that goes away is simply not added next frame and the rest close the gap. One notice lands on exactly the row the message always had, and the prompt stays nearest the tagline so it keeps its cursor. Last also learned what to do when the jumplist is empty. It used to walk the jumps and, finding nothing, do nothing at all -- which is the ordinary case for a pane that opened beside this one and was never focused, such as the text pane the bare tty layout puts under the shell. It now falls back to neighbourPane: the next pane down the column, wrapping, and any other live pane failing that. Alternating with the neighbour is what Last is for. Co-Authored-By: Claude Opus 5 (1M context) --- src/builtins.zig | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/builtins.zig') diff --git a/src/builtins.zig b/src/builtins.zig index aa2b2d6d..30a5a50f 100644 --- a/src/builtins.zig +++ b/src/builtins.zig @@ -701,6 +701,9 @@ pub const Last = struct { // Restore the cursor without recentering the pane's retained view. if (j.pane != c.id) return c.p.focusPaneLine(j.pane, .{ .line = j.line, .col = j.col }, .keep); } + // Nothing on the jumplist to go back to, which is the ordinary case + // for a pane that opened beside this one and was never focused. + if (c.p.neighbourPane(c.id)) |next| c.p.focusPaneLine(next, .{ .line = 0, .col = 0 }, .keep); } }; -- cgit v1.3