From 06e88a975b6eda1e88082f192950c408e62282ab Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 21 Feb 2024 19:26:44 -0800 Subject: [PATCH] terminal/new: pages have a size --- src/terminal/new/PageList.zig | 9 +++++---- src/terminal/new/Screen.zig | 10 +++++----- src/terminal/new/Terminal.zig | 15 ++++++++------- src/terminal/new/page.zig | 32 ++++++++++++++++++++++---------- 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/terminal/new/PageList.zig b/src/terminal/new/PageList.zig index f2f3528fb..1f0075136 100644 --- a/src/terminal/new/PageList.zig +++ b/src/terminal/new/PageList.zig @@ -8,6 +8,7 @@ const Allocator = std.mem.Allocator; const assert = std.debug.assert; const point = @import("point.zig"); const pagepkg = @import("page.zig"); +const size = @import("size.zig"); const Page = pagepkg.Page; /// The number of PageList.Nodes we preheat the pool with. A node is @@ -55,13 +56,13 @@ active: RowOffset, /// The current desired screen dimensions. I say "desired" because individual /// pages may still be a different size and not yet reflowed since we lazily /// reflow text. -cols: usize, -rows: usize, +cols: size.CellCountInt, +rows: size.CellCountInt, pub fn init( alloc: Allocator, - cols: usize, - rows: usize, + cols: size.CellCountInt, + rows: size.CellCountInt, max_scrollback: usize, ) !PageList { _ = max_scrollback; diff --git a/src/terminal/new/Screen.zig b/src/terminal/new/Screen.zig index 3d1f27ab7..926825e39 100644 --- a/src/terminal/new/Screen.zig +++ b/src/terminal/new/Screen.zig @@ -24,8 +24,8 @@ cursor: Cursor, /// The cursor position. const Cursor = struct { // The x/y position within the viewport. - x: usize, - y: usize, + x: size.CellCountInt, + y: size.CellCountInt, /// The "last column flag (LCF)" as its called. If this is set then the /// next character print will force a soft-wrap. @@ -47,8 +47,8 @@ const Cursor = struct { /// Initialize a new screen. pub fn init( alloc: Allocator, - cols: usize, - rows: usize, + cols: size.CellCountInt, + rows: size.CellCountInt, max_scrollback: usize, ) !Screen { // Initialize our backing pages. This will initialize the viewport. @@ -106,7 +106,7 @@ pub fn cursorDown(self: *Screen) void { } /// Move the cursor to some absolute position. -pub fn cursorHorizontalAbsolute(self: *Screen, x: usize) void { +pub fn cursorHorizontalAbsolute(self: *Screen, x: size.CellCountInt) void { assert(x < self.pages.cols); const page_rac = self.cursor.page_offset.rowAndCell(x); diff --git a/src/terminal/new/Terminal.zig b/src/terminal/new/Terminal.zig index 449c77141..96b81ae1b 100644 --- a/src/terminal/new/Terminal.zig +++ b/src/terminal/new/Terminal.zig @@ -20,6 +20,7 @@ const Tabstops = @import("../Tabstops.zig"); const color = @import("../color.zig"); const mouse_shape = @import("../mouse_shape.zig"); +const size = @import("size.zig"); const pagepkg = @import("page.zig"); const style = @import("style.zig"); const Screen = @import("Screen.zig"); @@ -65,8 +66,8 @@ status_display: ansi.StatusDisplay = .main, tabstops: Tabstops, /// The size of the terminal. -rows: usize, -cols: usize, +rows: size.CellCountInt, +cols: size.CellCountInt, /// The size of the screen in pixels. This is used for pty events and images width_px: u32 = 0, @@ -155,18 +156,18 @@ pub const MouseFormat = enum(u3) { pub const ScrollingRegion = struct { // Top and bottom of the scroll region (0-indexed) // Precondition: top < bottom - top: usize, - bottom: usize, + top: size.CellCountInt, + bottom: size.CellCountInt, // Left/right scroll regions. // Precondition: right > left // Precondition: right <= cols - 1 - left: usize, - right: usize, + left: size.CellCountInt, + right: size.CellCountInt, }; /// Initialize a new terminal. -pub fn init(alloc: Allocator, cols: usize, rows: usize) !Terminal { +pub fn init(alloc: Allocator, cols: size.CellCountInt, rows: size.CellCountInt) !Terminal { return Terminal{ .cols = cols, .rows = rows, diff --git a/src/terminal/new/page.zig b/src/terminal/new/page.zig index 6ffc7f2d6..7b42d7240 100644 --- a/src/terminal/new/page.zig +++ b/src/terminal/new/page.zig @@ -70,7 +70,13 @@ pub const Page = struct { /// The available set of styles in use on this page. styles: style.Set, - /// The capacity of this page. + /// The current dimensions of the page. The capacity may be larger + /// than this. This allows us to allocate a larger page than necessary + /// and also to resize a page smaller witout reallocating. + size: Size, + + /// The capacity of this page. This is the full size of the backing + /// memory and is fixed at page creation time. capacity: Capacity, /// The allocator to use for multi-codepoint grapheme data. We use @@ -85,11 +91,17 @@ pub const Page = struct { const grapheme_bytes_default = grapheme_count_default * grapheme_chunk; const GraphemeMap = AutoOffsetHashMap(Offset(Cell), Offset(u21).Slice); + /// The size of this page. + pub const Size = struct { + cols: size.CellCountInt, + rows: size.CellCountInt, + }; + /// Capacity of this page. pub const Capacity = struct { /// Number of columns and rows we can know about. - cols: usize, - rows: usize, + cols: size.CellCountInt, + rows: size.CellCountInt, /// Number of unique styles that can be used on this page. styles: u16 = 16, @@ -99,8 +111,7 @@ pub const Page = struct { }; /// Initialize a new page, allocating the required backing memory. - /// It is HIGHLY RECOMMENDED you use a page_allocator as the allocator - /// but any allocator is allowed. + /// The size of the initialized page defaults to the full capacity. pub fn init(alloc: Allocator, cap: Capacity) !Page { const l = layout(cap); const backing = try alloc.alignedAlloc(u8, std.mem.page_size, l.total_size); @@ -138,6 +149,7 @@ pub const Page = struct { buf.add(l.grapheme_map_start), l.grapheme_map_layout, ), + .size = .{ .cols = cap.cols, .rows = cap.rows }, .capacity = cap, }; } @@ -149,7 +161,7 @@ pub const Page = struct { /// Get a single row. y must be valid. pub fn getRow(self: *const Page, y: usize) *Row { - assert(y < self.capacity.rows); + assert(y < self.size.rows); return &self.rows.ptr(self.memory)[y]; } @@ -163,7 +175,7 @@ pub const Page = struct { } const cells = row.cells.ptr(self.memory); - return cells[0..self.capacity.cols]; + return cells[0..self.size.cols]; } /// Get the row and cell for the given X/Y within this page. @@ -171,8 +183,8 @@ pub const Page = struct { row: *Row, cell: *Cell, } { - assert(y < self.capacity.rows); - assert(x < self.capacity.cols); + assert(y < self.size.rows); + assert(x < self.size.cols); const rows = self.rows.ptr(self.memory); const row = &rows[y]; @@ -199,7 +211,7 @@ pub const Page = struct { const rows_start = 0; const rows_end = rows_start + (cap.rows * @sizeOf(Row)); - const cells_count = cap.cols * cap.rows; + const cells_count: usize = @intCast(cap.cols * cap.rows); const cells_start = alignForward(usize, rows_end, @alignOf(Cell)); const cells_end = cells_start + (cells_count * @sizeOf(Cell));