diff --git a/src/terminal/Terminal.zig b/src/terminal/Terminal.zig index 882ef41c0..a2bf6d50e 100644 --- a/src/terminal/Terminal.zig +++ b/src/terminal/Terminal.zig @@ -2621,12 +2621,59 @@ pub fn plainStringUnwrapped(self: *Terminal, alloc: Allocator) ![]const u8 { return try self.screen.dumpStringAllocUnwrapped(alloc, .{ .viewport = .{} }); } -/// Full reset +/// Full reset. +/// +/// This will attempt to free the existing screen memory and allocate +/// new screens but if that fails this will reuse the existing memory +/// from the prior screens. In the latter case, memory may be wasted +/// (since its unused) but it isn't leaked. pub fn fullReset(self: *Terminal) void { - // Switch back to primary screen and clear it. We do not restore cursor - // because see the next step... - self.primaryScreen(.{ .clear_on_exit = true, .cursor_save = false }); + // Attempt to initialize new screens. + var new_primary = Screen.init( + self.screen.alloc, + self.cols, + self.rows, + self.screen.pages.explicit_max_size, + ) catch |err| { + log.warn("failed to allocate new primary screen, reusing old memory err={}", .{err}); + self.fallbackReset(); + return; + }; + const new_secondary = Screen.init( + self.secondary_screen.alloc, + self.cols, + self.rows, + 0, + ) catch |err| { + log.warn("failed to allocate new secondary screen, reusing old memory err={}", .{err}); + new_primary.deinit(); + self.fallbackReset(); + return; + }; + // If we got here, both new screens were successfully allocated + // and we can deinitialize the old screens. + self.screen.deinit(); + self.secondary_screen.deinit(); + + // Replace with the newly allocated screens. + self.screen = new_primary; + self.secondary_screen = new_secondary; + + self.resetCommonState(); +} + +fn fallbackReset(self: *Terminal) void { + // Clear existing screens without reallocation + self.primaryScreen(.{ .clear_on_exit = true, .cursor_save = false }); + self.screen.clearSelection(); + self.eraseDisplay(.scrollback, false); + self.eraseDisplay(.complete, false); + self.screen.cursorAbsolute(0, 0); + self.resetCommonState(); +} + +fn resetCommonState(self: *Terminal) void { // We set the saved cursor to null and then restore. This will force // our cursor to go back to the default which will also move the cursor // to the top-left. @@ -2640,7 +2687,6 @@ pub fn fullReset(self: *Terminal) void { self.modes = .{}; self.flags = .{}; self.tabstops.reset(TABSTOP_INTERVAL); - self.screen.clearSelection(); self.screen.kitty_keyboard = .{}; self.secondary_screen.kitty_keyboard = .{}; self.screen.protected_mode = .off; @@ -2651,9 +2697,6 @@ pub fn fullReset(self: *Terminal) void { .right = self.cols - 1, }; self.previous_char = null; - self.eraseDisplay(.scrollback, false); - self.eraseDisplay(.complete, false); - self.screen.cursorAbsolute(0, 0); self.pwd.clearRetainingCapacity(); self.status_display = .main; }