summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/terminal.zig17
1 files changed, 16 insertions, 1 deletions
diff --git a/src/terminal.zig b/src/terminal.zig
index 6bf46bef..1a3b6a21 100644
--- a/src/terminal.zig
+++ b/src/terminal.zig
@@ -1343,7 +1343,10 @@ pub fn shellRows(p: *Pardes, pane: *Pane) ![]const []const u8 {
if (pane.terminal == null) return &empty_grid;
const c = &p.shell_rows;
if (!c.stale and c.pane == pane) return c.rows;
- if (c.pane != null) {
+ // Another pane's rows, or a dropped pane's still waiting for the step's
+ // sweep (dropPane keeps them, as they may still be borrowed): this
+ // step's rows are scratch, and nothing in the slot is written over.
+ if (c.pane != null or c.text_alloc.len > 0 or c.rows.len > 0) {
c.stale = true;
return (try buildRows(p.scratch.allocator(), p, pane)).rows;
}
@@ -1357,6 +1360,18 @@ pub fn shellRows(p: *Pardes, pane: *Pane) ![]const []const u8 {
return c.rows;
}
+test "rows asked for after a pane's cached rows were dropped, before the sweep, leak nothing" {
+ if (comptime !enabled) return error.SkipZigTest;
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true });
+ defer p.deinit();
+ const pane = p.panes[0].?;
+ try std.testing.expect(pane.terminal != null);
+ _ = try shellRows(p, pane);
+ // A pane's teardown drops its entry; the rows stay until the sweep.
+ p.shell_rows.dropPane(pane);
+ _ = try shellRows(p, pane);
+}
+
/// The full modal motion surface: shell history with the live edit overlay
/// spliced into the rows it covers.
pub fn cursorLines(p: *Pardes, pane: *Pane) ![]const []const u8 {