From f04d26442f3809a834cdff384f457c76ed14bcf1 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 29 Feb 2024 20:02:21 -0800 Subject: [PATCH] terminal/new: pagelist resize rows only no reflow --- src/terminal/new/PageList.zig | 128 ++++++++++++++++++++++++++++++++++ src/terminal/new/page.zig | 29 -------- 2 files changed, 128 insertions(+), 29 deletions(-) diff --git a/src/terminal/new/PageList.zig b/src/terminal/new/PageList.zig index edd68b657..5fa630400 100644 --- a/src/terminal/new/PageList.zig +++ b/src/terminal/new/PageList.zig @@ -347,6 +347,63 @@ fn viewportForOffset(self: *const PageList, offset: RowOffset) Viewport { return .{ .exact = offset }; } +/// Resize options +pub const Resize = struct { + /// The new cols/cells of the screen. + cols: ?size.CellCountInt = null, + rows: ?size.CellCountInt = null, + + /// Whether to reflow the text. If this is false then the text will + /// be truncated if the new size is smaller than the old size. + reflow: bool = true, +}; + +/// Resize +/// TODO: docs +pub fn resize(self: *PageList, opts: Resize) !void { + if (!opts.reflow) return try self.resizeWithoutReflow(opts); +} + +fn resizeWithoutReflow(self: *PageList, opts: Resize) !void { + assert(!opts.reflow); + + // If we're only changing the number of rows, it is a very fast operation. + if (opts.cols == null) { + const rows = opts.rows orelse return; + switch (std.math.order(rows, self.rows)) { + .eq => {}, + + // Making rows smaller, we simply change our rows value. Changing + // the row size doesn't affect anything else since max size and + // so on are all byte-based. + .lt => self.rows = rows, + + // Making rows larger we adjust our row count, and then grow + // to the row count. + .gt => gt: { + self.rows = rows; + + // Perform a quick count to make sure we have at least + // the number of rows we need. This should be fast because + // we only need to count up to "rows" + var count: usize = 0; + var page = self.pages.first; + while (page) |p| : (page = p.next) { + count += p.data.size.rows; + if (count >= rows) break :gt; + } + + assert(count < rows); + for (count..rows) |_| _ = try self.grow(); + }, + } + + return; + } + + @panic("TODO"); +} + /// Scroll options. pub const Scroll = union(enum) { /// Scroll to the active area. This is also sometimes referred to as @@ -1665,3 +1722,74 @@ test "PageList clone less than active" { defer s2.deinit(); try testing.expectEqual(@as(usize, s.rows), s2.totalRows()); } + +test "PageList resize (no reflow) more rows" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 10, 3, 0); + defer s.deinit(); + try testing.expectEqual(@as(usize, 3), s.totalRows()); + + // Resize + try s.resize(.{ .rows = 10, .reflow = false }); + try testing.expectEqual(@as(usize, 10), s.rows); + try testing.expectEqual(@as(usize, 10), s.totalRows()); + + { + const pt = s.getCell(.{ .active = .{} }).?.screenPoint(); + try testing.expectEqual(point.Point{ .screen = .{ + .x = 0, + .y = 0, + } }, pt); + } +} + +test "PageList resize (no reflow) more rows with history" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 10, 3, null); + defer s.deinit(); + try s.growRows(50); + { + const pt = s.getCell(.{ .active = .{} }).?.screenPoint(); + try testing.expectEqual(point.Point{ .screen = .{ + .x = 0, + .y = 50, + } }, pt); + } + + // Resize + try s.resize(.{ .rows = 5, .reflow = false }); + try testing.expectEqual(@as(usize, 5), s.rows); + try testing.expectEqual(@as(usize, 53), s.totalRows()); + { + const pt = s.getCell(.{ .active = .{} }).?.screenPoint(); + try testing.expectEqual(point.Point{ .screen = .{ + .x = 0, + .y = 48, + } }, pt); + } +} + +test "PageList resize (no reflow) less rows" { + const testing = std.testing; + const alloc = testing.allocator; + + var s = try init(alloc, 10, 10, 0); + defer s.deinit(); + try testing.expectEqual(@as(usize, 10), s.totalRows()); + + // Resize + try s.resize(.{ .rows = 5, .reflow = false }); + try testing.expectEqual(@as(usize, 5), s.rows); + try testing.expectEqual(@as(usize, 10), s.totalRows()); + { + const pt = s.getCell(.{ .active = .{} }).?.screenPoint(); + try testing.expectEqual(point.Point{ .screen = .{ + .x = 0, + .y = 5, + } }, pt); + } +} diff --git a/src/terminal/new/page.zig b/src/terminal/new/page.zig index 02c8dbd11..df443b4c3 100644 --- a/src/terminal/new/page.zig +++ b/src/terminal/new/page.zig @@ -206,35 +206,6 @@ pub const Page = struct { return result; } - /// Clone and resize this page to the new layout with a provided - /// memory buffer. The new layout can change any parameters. If they - /// do not fit within the new layout, OutOfMemory is returned. - /// If OutOfMemory is returned, the memory buffer is not zeroed; - /// the caller should zero if it is reused. - /// - /// If reflow is true, soft-wrapped text will be reflowed. If reflow - /// is false then soft-wrapped text will be truncated. - /// - /// For deleted cells, this will reclaim the grapheme/style memory - /// as appropriate. A page has no concept of the current active style - /// so if you want the current active style to not be GCd then you - /// should increase the ref count before calling this function, and - /// decrease it after. - pub fn resizeBuf( - self: *Page, - buf: OffsetBuf, - l: Layout, - reflow: bool, - ) !Page { - // TODO - if (reflow) @panic("TODO"); - - // Non-reflow resize is relatively simple. - _ = self; - _ = buf; - _ = l; - } - /// Get a single row. y must be valid. pub fn getRow(self: *const Page, y: usize) *Row { assert(y < self.size.rows);