terminal: updating render state with tests
parent
3f7cee1e99
commit
a860801323
|
|
@ -42,7 +42,7 @@ pub const RenderState = struct {
|
||||||
/// area and scrolling with new output.
|
/// area and scrolling with new output.
|
||||||
viewport_is_bottom: bool,
|
viewport_is_bottom: bool,
|
||||||
|
|
||||||
/// The rows (y=0 is top) of the viewport.
|
/// The rows (y=0 is top) of the viewport. Guaranteed to be `rows` length.
|
||||||
///
|
///
|
||||||
/// This is a MultiArrayList because only the update cares about
|
/// This is a MultiArrayList because only the update cares about
|
||||||
/// the allocators. Callers care about all the other properties, and
|
/// the allocators. Callers care about all the other properties, and
|
||||||
|
|
@ -75,7 +75,7 @@ pub const RenderState = struct {
|
||||||
/// Arena used for any heap allocations for this row,
|
/// Arena used for any heap allocations for this row,
|
||||||
arena: ArenaAllocator.State,
|
arena: ArenaAllocator.State,
|
||||||
|
|
||||||
/// The cells in this row, always `cols` length.
|
/// The cells in this row. Guaranteed to be `cols` length.
|
||||||
cells: std.MultiArrayList(Cell),
|
cells: std.MultiArrayList(Cell),
|
||||||
|
|
||||||
/// A dirty flag that can be used by the renderer to track
|
/// A dirty flag that can be used by the renderer to track
|
||||||
|
|
@ -113,7 +113,8 @@ pub const RenderState = struct {
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
t: *Terminal,
|
t: *Terminal,
|
||||||
) Allocator.Error!void {
|
) Allocator.Error!void {
|
||||||
self.redraw = redraw: {
|
const s: *Screen = t.screens.active;
|
||||||
|
const redraw = redraw: {
|
||||||
// If our screen key changed, we need to do a full rebuild
|
// If our screen key changed, we need to do a full rebuild
|
||||||
// because our render state is viewport-specific.
|
// because our render state is viewport-specific.
|
||||||
if (t.screens.active_key != self.screen) break :redraw true;
|
if (t.screens.active_key != self.screen) break :redraw true;
|
||||||
|
|
@ -134,17 +135,23 @@ pub const RenderState = struct {
|
||||||
if (v > 0) break :redraw true;
|
if (v > 0) break :redraw true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If our dimensions changed, we do a full rebuild.
|
||||||
|
if (self.rows != s.pages.rows or
|
||||||
|
self.cols != s.pages.cols)
|
||||||
|
{
|
||||||
|
break :redraw true;
|
||||||
|
}
|
||||||
|
|
||||||
break :redraw false;
|
break :redraw false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Full redraw resets our state completely.
|
// Full redraw resets our state completely.
|
||||||
if (self.redraw) {
|
if (redraw) {
|
||||||
self.* = .empty;
|
self.* = .empty;
|
||||||
self.screen = t.screens.active_key;
|
self.screen = t.screens.active_key;
|
||||||
|
self.redraw = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const s: *Screen = t.screens.active;
|
|
||||||
|
|
||||||
// Always set our cheap fields, its more expensive to compare
|
// Always set our cheap fields, its more expensive to compare
|
||||||
self.rows = s.pages.rows;
|
self.rows = s.pages.rows;
|
||||||
self.cols = s.pages.cols;
|
self.cols = s.pages.cols;
|
||||||
|
|
@ -186,7 +193,7 @@ pub const RenderState = struct {
|
||||||
var y: size.CellCountInt = 0;
|
var y: size.CellCountInt = 0;
|
||||||
while (row_it.next()) |row_pin| : (y = y + 1) {
|
while (row_it.next()) |row_pin| : (y = y + 1) {
|
||||||
// If the row isn't dirty then we assume it is unchanged.
|
// If the row isn't dirty then we assume it is unchanged.
|
||||||
if (!self.redraw and !row_pin.isDirty()) continue;
|
if (!redraw and !row_pin.isDirty()) continue;
|
||||||
|
|
||||||
// Promote our arena. State is copied by value so we need to
|
// Promote our arena. State is copied by value so we need to
|
||||||
// restore it on all exit paths so we don't leak memory.
|
// restore it on all exit paths so we don't leak memory.
|
||||||
|
|
@ -306,3 +313,32 @@ test {
|
||||||
defer state.deinit(alloc);
|
defer state.deinit(alloc);
|
||||||
try state.update(alloc, &t);
|
try state.update(alloc, &t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "basic text" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var t = try Terminal.init(alloc, .{
|
||||||
|
.cols = 10,
|
||||||
|
.rows = 3,
|
||||||
|
});
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
var s = t.vtStream();
|
||||||
|
defer s.deinit();
|
||||||
|
try s.nextSlice("ABCD");
|
||||||
|
|
||||||
|
var state: RenderState = .empty;
|
||||||
|
defer state.deinit(alloc);
|
||||||
|
try state.update(alloc, &t);
|
||||||
|
|
||||||
|
// Verify we have the right number of rows
|
||||||
|
const row_data = state.row_data.slice();
|
||||||
|
try testing.expectEqual(3, row_data.len);
|
||||||
|
|
||||||
|
// All rows should have cols cells
|
||||||
|
const cells = row_data.items(.cells);
|
||||||
|
try testing.expectEqual(10, cells[0].len);
|
||||||
|
try testing.expectEqual(10, cells[1].len);
|
||||||
|
try testing.expectEqual(10, cells[2].len);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue