diff --git a/src/terminal/Screen.zig b/src/terminal/Screen.zig index 2170d42a3..620267ad5 100644 --- a/src/terminal/Screen.zig +++ b/src/terminal/Screen.zig @@ -78,7 +78,7 @@ pub const Dirty = packed struct { hyperlink_hover: bool = false, }; -/// The cursor position. +/// The cursor position and style. pub const Cursor = struct { // The x/y position within the viewport. x: size.CellCountInt, @@ -761,26 +761,23 @@ pub fn cursorCopy(self: *Screen, other: Cursor) !void { self.cursor = other; errdefer self.cursor = old; - // Clear our style information initially so runtime safety integrity - // checks pass since there is a period below where the cursor is - // invalid. - self.cursor.style = .{}; - self.cursor.style_id = 0; + // Keep our old style ID so it can be properly cleaned up below. + self.cursor.style_id = old.style_id; - // 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. + // Keep our old page pin and X/Y because: + // 1. The old style will need to be cleaned up from the page it's from. + // 2. The new position navigated to by `cursorAbsolute` needs to be in 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 = other.style; - self.cursor.style_id = old.style_id; + // Call manual style update in order to clean up our old style, if we have + // one, and also to load the style from the other cursor, if it had one. try self.manualStyleUpdate(); + + // Move to the correct location to match the other cursor. + self.cursorAbsolute(other.x, other.y); } /// Always use this to write to cursor.page_pin.*. @@ -2737,6 +2734,77 @@ test "Screen cursorCopy style deref" { try testing.expectEqual(@as(usize, 0), page.styles.count()); } +test "Screen cursorCopy style deref new page" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 10, 10, 0); + defer s.deinit(); + + var s2 = try Screen.init(alloc, 10, 10, 2048); + defer s2.deinit(); + + // We need to get the cursor on a new page. + const first_page_size = s2.pages.pages.first.?.data.capacity.rows; + + // Fill the scrollback with blank lines until + // there are only 5 rows left on the first page. + for (0..first_page_size - 5) |_| { + try s2.testWriteString("\n"); + } + + try s2.testWriteString("1\n2\n3\n4\n5\n6\n7\n8\n9\n10"); + + // s2.pages.diagram(...): + // + // +----------+ = PAGE 0 + // ... : : + // +-------------+ ACTIVE + // 4300 |1 | | 0 + // 4301 |2 | | 1 + // 4302 |3 | | 2 + // 4303 |4 | | 3 + // 4304 |5 | | 4 + // +----------+ : + // +----------+ : = PAGE 1 + // 0 |6 | | 5 + // 1 |7 | | 6 + // 2 |8 | | 7 + // 3 |9 | | 8 + // 4 |10 | | 9 + // : ^ : : = PIN 0 + // +----------+ : + // +-------------+ + + // This should be PAGE 1 + const page = &s2.cursor.page_pin.page.data; + + // It should be the last page in the list. + try testing.expectEqual(&s2.pages.pages.last.?.data, page); + // It should have a previous page. + try testing.expect(s2.cursor.page_pin.page.prev != null); + + // The cursor should be at 2, 9 + try testing.expect(s2.cursor.x == 2); + try testing.expect(s2.cursor.y == 9); + + // Bold should create our style in page 1. + try s2.setAttribute(.{ .bold = {} }); + try testing.expectEqual(@as(usize, 1), page.styles.count()); + try testing.expect(s2.cursor.style.flags.bold); + + // Copy the cursor for the first screen. This should release + // the style from page 1 and move the cursor back to page 0. + try s2.cursorCopy(s.cursor); + try testing.expect(!s2.cursor.style.flags.bold); + try testing.expectEqual(@as(usize, 0), page.styles.count()); + // The page after the page the cursor is now in should be page 1. + try testing.expectEqual(page, &s2.cursor.page_pin.page.next.?.data); + // The cursor should be at 0, 0 + try testing.expect(s2.cursor.x == 0); + try testing.expect(s2.cursor.y == 0); +} + test "Screen cursorCopy style copy" { const testing = std.testing; const alloc = testing.allocator; diff --git a/src/terminal/ref_counted_set.zig b/src/terminal/ref_counted_set.zig index 2032f641d..ed31db029 100644 --- a/src/terminal/ref_counted_set.zig +++ b/src/terminal/ref_counted_set.zig @@ -109,7 +109,7 @@ pub fn RefCountedSet( items: Offset(Item), /// The number of living items currently stored in the set. - living: Id = 0, + living: usize = 0, /// The next index to store an item at. /// Id 0 is reserved for unused items.