mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
terminal: proper cursor copy for alt screen
This commit is contained in:
@ -437,6 +437,32 @@ fn cursorDownOrScroll(self: *Screen) !void {
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy another cursor. The cursor can be on any screen but the x/y
|
||||
/// must be within our screen bounds.
|
||||
pub fn cursorCopy(self: *Screen, other: Cursor) !void {
|
||||
assert(other.x < self.pages.cols);
|
||||
assert(other.y < self.pages.rows);
|
||||
|
||||
const old = self.cursor;
|
||||
self.cursor = other;
|
||||
errdefer self.cursor = old;
|
||||
|
||||
// We need to keep our old x/y because that is our cursorAbsolute
|
||||
// will fix up our pointers.
|
||||
//
|
||||
// We keep our old page pin because we expect to be in the active
|
||||
// page relative to our own screen.
|
||||
self.cursor.page_pin = old.page_pin;
|
||||
self.cursor.x = old.x;
|
||||
self.cursor.y = old.y;
|
||||
self.cursorAbsolute(other.x, other.y);
|
||||
|
||||
// We keep the old style ref so manualStyleUpdate can clean our old style up.
|
||||
self.cursor.style_id = old.style_id;
|
||||
self.cursor.style_ref = old.style_ref;
|
||||
try self.manualStyleUpdate();
|
||||
}
|
||||
|
||||
/// Options for scrolling the viewport of the terminal grid. The reason
|
||||
/// we have this in addition to PageList.Scroll is because we have additional
|
||||
/// scroll behaviors that are not part of the PageList.Scroll enum.
|
||||
@ -1730,6 +1756,68 @@ test "Screen read and write no scrollback large" {
|
||||
}
|
||||
}
|
||||
|
||||
test "Screen cursorCopy x/y" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var s = try Screen.init(alloc, 10, 10, 0);
|
||||
defer s.deinit();
|
||||
s.cursorAbsolute(2, 3);
|
||||
try testing.expect(s.cursor.x == 2);
|
||||
try testing.expect(s.cursor.y == 3);
|
||||
|
||||
var s2 = try Screen.init(alloc, 10, 10, 0);
|
||||
defer s2.deinit();
|
||||
try s2.cursorCopy(s.cursor);
|
||||
try testing.expect(s2.cursor.x == 2);
|
||||
try testing.expect(s2.cursor.y == 3);
|
||||
try s2.testWriteString("Hello");
|
||||
|
||||
{
|
||||
const str = try s2.dumpStringAlloc(alloc, .{ .screen = .{} });
|
||||
defer alloc.free(str);
|
||||
try testing.expectEqualStrings("\n\n\n Hello", str);
|
||||
}
|
||||
}
|
||||
|
||||
test "Screen cursorCopy style deref" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var s = try Screen.init(alloc, 10, 10, 0);
|
||||
defer s.deinit();
|
||||
|
||||
var s2 = try Screen.init(alloc, 10, 10, 0);
|
||||
defer s2.deinit();
|
||||
const page = s2.cursor.page_pin.page.data;
|
||||
|
||||
// Bold should create our style
|
||||
try s2.setAttribute(.{ .bold = {} });
|
||||
try testing.expectEqual(@as(usize, 1), page.styles.count(page.memory));
|
||||
try testing.expect(s2.cursor.style.flags.bold);
|
||||
|
||||
// Copy default style, should release our style
|
||||
try s2.cursorCopy(s.cursor);
|
||||
try testing.expect(!s2.cursor.style.flags.bold);
|
||||
try testing.expectEqual(@as(usize, 0), page.styles.count(page.memory));
|
||||
}
|
||||
|
||||
test "Screen cursorCopy style copy" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var s = try Screen.init(alloc, 10, 10, 0);
|
||||
defer s.deinit();
|
||||
try s.setAttribute(.{ .bold = {} });
|
||||
|
||||
var s2 = try Screen.init(alloc, 10, 10, 0);
|
||||
defer s2.deinit();
|
||||
const page = s2.cursor.page_pin.page.data;
|
||||
try s2.cursorCopy(s.cursor);
|
||||
try testing.expect(s2.cursor.style.flags.bold);
|
||||
try testing.expectEqual(@as(usize, 1), page.styles.count(page.memory));
|
||||
}
|
||||
|
||||
test "Screen style basics" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
@ -2142,19 +2142,13 @@ pub fn alternateScreen(
|
||||
self.screen.kitty_images.dirty = true;
|
||||
|
||||
// Bring our pen with us
|
||||
self.screen.cursor = old.cursor;
|
||||
self.screen.cursor.style_id = 0;
|
||||
self.screen.cursor.style_ref = null;
|
||||
self.screen.cursorAbsolute(old.cursor.x, old.cursor.y);
|
||||
self.screen.cursorCopy(old.cursor) catch |err| {
|
||||
log.warn("cursor copy failed entering alt screen err={}", .{err});
|
||||
};
|
||||
|
||||
if (options.clear_on_enter) {
|
||||
self.eraseDisplay(.complete, false);
|
||||
}
|
||||
|
||||
// Update any style ref after we erase the display so we definitely have space
|
||||
self.screen.manualStyleUpdate() catch |err| {
|
||||
log.warn("style update failed entering alt screen err={}", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
/// Switch back to the primary screen (reset alternate screen mode).
|
||||
@ -6414,7 +6408,8 @@ test "Terminal: saveCursor with screen change" {
|
||||
defer t.deinit(alloc);
|
||||
|
||||
try t.setAttribute(.{ .bold = {} });
|
||||
t.screen.cursor.x = 2;
|
||||
t.setCursorPos(t.screen.cursor.y + 1, 3);
|
||||
try testing.expect(t.screen.cursor.x == 2);
|
||||
t.screen.charset.gr = .G3;
|
||||
t.modes.set(.origin, true);
|
||||
t.alternateScreen(.{
|
||||
|
Reference in New Issue
Block a user