terminal: fullReset uses the new screen reset methods

This commit is contained in:
Mitchell Hashimoto
2024-12-02 17:43:56 -05:00
parent d7fcaefdf3
commit 212bd3d5fb
2 changed files with 66 additions and 66 deletions

View File

@ -83,8 +83,8 @@ pub const Dirty = packed struct {
/// The cursor position and style. /// The cursor position and style.
pub const Cursor = struct { pub const Cursor = struct {
// The x/y position within the viewport. // The x/y position within the viewport.
x: size.CellCountInt, x: size.CellCountInt = 0,
y: size.CellCountInt, y: size.CellCountInt = 0,
/// The visual style of the cursor. This defaults to block because /// The visual style of the cursor. This defaults to block because
/// it has to default to something, but users of this struct are /// it has to default to something, but users of this struct are
@ -249,6 +249,50 @@ pub fn assertIntegrity(self: *const Screen) void {
} }
} }
/// Reset the screen according to the logic of a DEC RIS sequence.
///
/// - Clears the screen and attempts to reclaim memory.
/// - Moves the cursor to the top-left.
/// - Clears any cursor state: style, hyperlink, etc.
/// - Resets the charset
/// - Clears the selection
/// - Deletes all Kitty graphics
/// - Resets Kitty Keyboard settings
/// - Disables protection mode
///
pub fn reset(self: *Screen) void {
// Reset our pages
self.pages.reset();
// The above reset preserves tracked pins so we can still use
// our cursor pin, which should be at the top-left already.
const cursor_pin: *PageList.Pin = self.cursor.page_pin;
assert(cursor_pin.node == self.pages.pages.first.?);
assert(cursor_pin.x == 0);
assert(cursor_pin.y == 0);
const cursor_rac = cursor_pin.rowAndCell();
self.cursor.deinit(self.alloc);
self.cursor = .{
.page_pin = cursor_pin,
.page_row = cursor_rac.row,
.page_cell = cursor_rac.cell,
};
// Clear kitty graphics
self.kitty_images.delete(
self.alloc,
undefined, // All image deletion doesn't need the terminal
.{ .all = true },
);
// Reset our basic state
self.saved_cursor = null;
self.charset = .{};
self.kitty_keyboard = .{};
self.protected_mode = .off;
self.clearSelection();
}
/// Clone the screen. /// Clone the screen.
/// ///
/// This will copy: /// This will copy:

View File

@ -2627,82 +2627,38 @@ pub fn plainStringUnwrapped(self: *Terminal, alloc: Allocator) ![]const u8 {
/// Full reset. /// Full reset.
/// ///
/// This will attempt to free the existing screen memory and allocate /// This will attempt to free the existing screen memory but if that fails
/// new screens but if that fails this will reuse the existing memory /// this will reuse the existing memory. In the latter case, memory may
/// from the prior screens. In the latter case, memory may be wasted /// be wasted (since its unused) but it isn't leaked.
/// (since its unused) but it isn't leaked.
pub fn fullReset(self: *Terminal) void { pub fn fullReset(self: *Terminal) void {
// Attempt to initialize new screens. // Reset our screens
var new_primary = Screen.init( self.screen.reset();
self.screen.alloc, self.secondary_screen.reset();
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 // Ensure we're back on primary screen
// and we can deinitialize the old screens. if (self.active_screen != .primary) {
self.screen.deinit(); const old = self.screen;
self.secondary_screen.deinit(); self.screen = self.secondary_screen;
self.secondary_screen = old;
// Replace with the newly allocated screens. self.active_screen = .primary;
self.screen = new_primary;
self.secondary_screen = new_secondary;
self.resetCommonState();
} }
fn fallbackReset(self: *Terminal) void { // Rest our basic state
// 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.
self.screen.saved_cursor = null;
self.restoreCursor() catch |err| {
log.warn("restore cursor on primary screen failed err={}", .{err});
};
self.screen.endHyperlink();
self.screen.charset = .{};
self.modes.reset(); self.modes.reset();
self.flags = .{}; self.flags = .{};
self.tabstops.reset(TABSTOP_INTERVAL); self.tabstops.reset(TABSTOP_INTERVAL);
self.screen.kitty_keyboard = .{}; self.previous_char = null;
self.secondary_screen.kitty_keyboard = .{}; self.pwd.clearRetainingCapacity();
self.screen.protected_mode = .off; self.status_display = .main;
self.scrolling_region = .{ self.scrolling_region = .{
.top = 0, .top = 0,
.bottom = self.rows - 1, .bottom = self.rows - 1,
.left = 0, .left = 0,
.right = self.cols - 1, .right = self.cols - 1,
}; };
self.previous_char = null;
self.pwd.clearRetainingCapacity(); // Always mark dirty so we redraw everything
self.status_display = .main; self.flags.dirty.clear = true;
} }
/// Returns true if the point is dirty, used for testing. /// Returns true if the point is dirty, used for testing.