terminal/new: pagelist resize rows only no reflow

This commit is contained in:
Mitchell Hashimoto
2024-02-29 20:02:21 -08:00
parent 5009ab6645
commit f04d26442f
2 changed files with 128 additions and 29 deletions

View File

@ -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);
}
}

View File

@ -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);