Screen.region to get a region of contiguous memory for a tag

This commit is contained in:
Mitchell Hashimoto
2022-08-07 10:46:35 -07:00
parent 92602dafca
commit 2d6d027097
2 changed files with 65 additions and 10 deletions

View File

@ -86,7 +86,7 @@ pub const RowIterator = struct {
value: usize = 0, value: usize = 0,
pub fn next(self: *RowIterator) ?Row { pub fn next(self: *RowIterator) ?Row {
if (self.value >= self.tag.max(self.screen)) return null; if (self.value > self.tag.max(self.screen)) return null;
const idx = self.tag.index(self.value); const idx = self.tag.index(self.value);
const res = self.screen.getRow(idx); const res = self.screen.getRow(idx);
self.value += 1; self.value += 1;
@ -129,7 +129,7 @@ pub const RowIndexTag = enum {
.screen => screen.totalRows(), .screen => screen.totalRows(),
.viewport => screen.rows, .viewport => screen.rows,
.active => screen.rows, .active => screen.rows,
}; } - 1;
} }
/// Construct a RowIndex from a tag. /// Construct a RowIndex from a tag.
@ -216,9 +216,31 @@ pub fn rowIterator(self: *const Screen, tag: RowIndexTag) RowIterator {
return .{ .screen = self, .tag = tag }; return .{ .screen = self, .tag = tag };
} }
/// Get the visible portion of the screen. /// Region gets the contiguous portions of memory that constitute an
pub fn getVisible(self: Screen) []Cell { /// entire region. This is an efficient way to clear regions, for example
return self.storage; /// since you can memcpy directly into it.
///
/// This has two elements because internally we use a ring buffer and
/// so any region can be split into two if it crosses the ring buffer
/// boundary.
pub fn region(self: *const Screen, tag: RowIndexTag) [2][]Cell {
const top = self.rowIndex(tag.index(0));
const bot = self.rowIndex(tag.index(tag.max(self)));
// The bottom and top are available in one contiguous slice.
if (bot >= top) {
return .{
self.storage[top .. bot + self.cols],
self.storage[0..0], // just so its a valid slice, but zero length
};
}
// The bottom and top are split into two slices, so we slice to the
// bottom of the storage, then from the top.
return .{
self.storage[top..self.storage.len],
self.storage[0 .. bot + self.cols],
};
} }
/// Get a single row in the active area by index (0-indexed). /// Get a single row in the active area by index (0-indexed).
@ -649,9 +671,11 @@ test "Screen" {
// Sanity check that our test helpers work // Sanity check that our test helpers work
const str = "1ABCD\n2EFGH\n3IJKL"; const str = "1ABCD\n2EFGH\n3IJKL";
s.testWriteString(str); s.testWriteString(str);
{
var contents = try s.testString(alloc); var contents = try s.testString(alloc);
defer alloc.free(contents); defer alloc.free(contents);
try testing.expectEqualStrings(str, contents); try testing.expectEqualStrings(str, contents);
}
// Test the row iterator // Test the row iterator
var count: usize = 0; var count: usize = 0;
@ -665,6 +689,16 @@ test "Screen" {
// Should go through all rows // Should go through all rows
try testing.expectEqual(@as(usize, 3), count); try testing.expectEqual(@as(usize, 3), count);
// Should be able to easily clear screen
const reg = s.region(.viewport);
std.mem.set(Cell, reg[0], .{ .char = 'A' });
std.mem.set(Cell, reg[1], .{ .char = 'A' });
{
var contents = try s.testString(alloc);
defer alloc.free(contents);
try testing.expectEqualStrings("AAAAA\nAAAAA\nAAAAA", contents);
}
} }
test "Screen: scrolling" { test "Screen: scrolling" {
@ -825,6 +859,26 @@ test "Screen: scrollback" {
defer alloc.free(contents); defer alloc.free(contents);
try testing.expectEqualStrings("1ABCD\n2EFGH\n3IJKL", contents); try testing.expectEqualStrings("1ABCD\n2EFGH\n3IJKL", contents);
} }
// Should be able to easily clear active area only
const reg = s.region(.active);
std.mem.set(Cell, reg[0], .{ .char = 0 });
std.mem.set(Cell, reg[1], .{ .char = 0 });
{
var contents = try s.testString(alloc);
defer alloc.free(contents);
try testing.expectEqualStrings("1ABCD", contents);
}
// Scrolling to the bottom
s.scroll(.{ .bottom = {} });
{
// Test our contents rotated
var contents = try s.testString(alloc);
defer alloc.free(contents);
try testing.expectEqualStrings("", contents);
}
} }
test "Screen: scrollback empty" { test "Screen: scrollback empty" {

View File

@ -539,8 +539,9 @@ pub fn eraseDisplay(
switch (mode) { switch (mode) {
.complete => { .complete => {
const all = self.screen.getVisible(); const region = self.screen.region(.active);
std.mem.set(Screen.Cell, all, self.screen.cursor.pen); std.mem.set(Screen.Cell, region[0], self.screen.cursor.pen);
std.mem.set(Screen.Cell, region[1], self.screen.cursor.pen);
// Unsets pending wrap state // Unsets pending wrap state
self.screen.cursor.pending_wrap = false; self.screen.cursor.pending_wrap = false;