mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
terminal2: PageList pageIterator reverse
This commit is contained in:
@ -257,7 +257,7 @@ pub fn clone(
|
|||||||
bot: ?point.Point,
|
bot: ?point.Point,
|
||||||
) !PageList {
|
) !PageList {
|
||||||
// First, count our pages so our preheat is exactly what we need.
|
// First, count our pages so our preheat is exactly what we need.
|
||||||
var it = self.pageIterator(top, bot);
|
var it = self.pageIterator(.right_down, top, bot);
|
||||||
const page_count: usize = page_count: {
|
const page_count: usize = page_count: {
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (it.next()) |_| count += 1;
|
while (it.next()) |_| count += 1;
|
||||||
@ -281,7 +281,7 @@ pub fn clonePool(
|
|||||||
top: point.Point,
|
top: point.Point,
|
||||||
bot: ?point.Point,
|
bot: ?point.Point,
|
||||||
) !PageList {
|
) !PageList {
|
||||||
var it = self.pageIterator(top, bot);
|
var it = self.pageIterator(.right_down, top, bot);
|
||||||
|
|
||||||
// Copy our pages
|
// Copy our pages
|
||||||
var page_list: List = .{};
|
var page_list: List = .{};
|
||||||
@ -427,7 +427,7 @@ fn resizeCols(
|
|||||||
const cap = try std_capacity.adjust(.{ .cols = cols });
|
const cap = try std_capacity.adjust(.{ .cols = cols });
|
||||||
|
|
||||||
// Go page by page and shrink the columns on a per-page basis.
|
// Go page by page and shrink the columns on a per-page basis.
|
||||||
var it = self.pageIterator(.{ .screen = .{} }, null);
|
var it = self.pageIterator(.right_down, .{ .screen = .{} }, null);
|
||||||
while (it.next()) |chunk| {
|
while (it.next()) |chunk| {
|
||||||
// Fast-path: none of our rows are wrapped. In this case we can
|
// Fast-path: none of our rows are wrapped. In this case we can
|
||||||
// treat this like a no-reflow resize. This only applies if we
|
// treat this like a no-reflow resize. This only applies if we
|
||||||
@ -911,7 +911,7 @@ fn resizeWithoutReflow(self: *PageList, opts: Resize) !void {
|
|||||||
// resize the columns, and clear any cells that are beyond
|
// resize the columns, and clear any cells that are beyond
|
||||||
// the new size.
|
// the new size.
|
||||||
.lt => {
|
.lt => {
|
||||||
var it = self.pageIterator(.{ .screen = .{} }, null);
|
var it = self.pageIterator(.right_down, .{ .screen = .{} }, null);
|
||||||
while (it.next()) |chunk| {
|
while (it.next()) |chunk| {
|
||||||
const page = &chunk.page.data;
|
const page = &chunk.page.data;
|
||||||
const rows = page.rows.ptr(page.memory);
|
const rows = page.rows.ptr(page.memory);
|
||||||
@ -940,7 +940,7 @@ fn resizeWithoutReflow(self: *PageList, opts: Resize) !void {
|
|||||||
.gt => {
|
.gt => {
|
||||||
const cap = try std_capacity.adjust(.{ .cols = cols });
|
const cap = try std_capacity.adjust(.{ .cols = cols });
|
||||||
|
|
||||||
var it = self.pageIterator(.{ .screen = .{} }, null);
|
var it = self.pageIterator(.right_down, .{ .screen = .{} }, null);
|
||||||
while (it.next()) |chunk| {
|
while (it.next()) |chunk| {
|
||||||
try self.resizeWithoutReflowGrowCols(cap, chunk);
|
try self.resizeWithoutReflowGrowCols(cap, chunk);
|
||||||
}
|
}
|
||||||
@ -1270,7 +1270,7 @@ pub fn eraseRows(
|
|||||||
// A pageIterator iterates one page at a time from the back forward.
|
// A pageIterator iterates one page at a time from the back forward.
|
||||||
// "back" here is in terms of scrollback, but actually the front of the
|
// "back" here is in terms of scrollback, but actually the front of the
|
||||||
// linked list.
|
// linked list.
|
||||||
var it = self.pageIterator(tl_pt, bl_pt);
|
var it = self.pageIterator(.right_down, tl_pt, bl_pt);
|
||||||
while (it.next()) |chunk| {
|
while (it.next()) |chunk| {
|
||||||
// If the chunk is a full page, deinit thit page and remove it from
|
// If the chunk is a full page, deinit thit page and remove it from
|
||||||
// the linked list.
|
// the linked list.
|
||||||
@ -1492,6 +1492,9 @@ pub fn getCell(self: *const PageList, pt: point.Point) ?Cell {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Direction that iterators can move.
|
||||||
|
pub const Direction = enum { left_up, right_down };
|
||||||
|
|
||||||
pub const CellIterator = struct {
|
pub const CellIterator = struct {
|
||||||
row_it: RowIterator,
|
row_it: RowIterator,
|
||||||
cell: ?Pin = null,
|
cell: ?Pin = null,
|
||||||
@ -1555,7 +1558,7 @@ pub fn rowIterator(
|
|||||||
tl_pt: point.Point,
|
tl_pt: point.Point,
|
||||||
bl_pt: ?point.Point,
|
bl_pt: ?point.Point,
|
||||||
) RowIterator {
|
) RowIterator {
|
||||||
var page_it = self.pageIterator(tl_pt, bl_pt);
|
var page_it = self.pageIterator(.right_down, tl_pt, bl_pt);
|
||||||
const chunk = page_it.next() orelse return .{ .page_it = page_it };
|
const chunk = page_it.next() orelse return .{ .page_it = page_it };
|
||||||
return .{ .page_it = page_it, .chunk = chunk, .offset = chunk.start };
|
return .{ .page_it = page_it, .chunk = chunk, .offset = chunk.start };
|
||||||
}
|
}
|
||||||
@ -1563,6 +1566,7 @@ pub fn rowIterator(
|
|||||||
pub const PageIterator = struct {
|
pub const PageIterator = struct {
|
||||||
row: ?Pin = null,
|
row: ?Pin = null,
|
||||||
limit: Limit = .none,
|
limit: Limit = .none,
|
||||||
|
direction: Direction = .right_down,
|
||||||
|
|
||||||
const Limit = union(enum) {
|
const Limit = union(enum) {
|
||||||
none,
|
none,
|
||||||
@ -1571,6 +1575,13 @@ pub const PageIterator = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn next(self: *PageIterator) ?Chunk {
|
pub fn next(self: *PageIterator) ?Chunk {
|
||||||
|
return switch (self.direction) {
|
||||||
|
.left_up => self.nextUp(),
|
||||||
|
.right_down => self.nextDown(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nextDown(self: *PageIterator) ?Chunk {
|
||||||
// Get our current row location
|
// Get our current row location
|
||||||
const row = self.row orelse return null;
|
const row = self.row orelse return null;
|
||||||
|
|
||||||
@ -1636,6 +1647,78 @@ pub const PageIterator = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn nextUp(self: *PageIterator) ?Chunk {
|
||||||
|
// Get our current row location
|
||||||
|
const row = self.row orelse return null;
|
||||||
|
|
||||||
|
return switch (self.limit) {
|
||||||
|
.none => none: {
|
||||||
|
// If we have no limit, then we consume this entire page. Our
|
||||||
|
// next row is the next page.
|
||||||
|
self.row = next: {
|
||||||
|
const next_page = row.page.prev orelse break :next null;
|
||||||
|
break :next .{
|
||||||
|
.page = next_page,
|
||||||
|
.y = next_page.data.size.rows - 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
break :none .{
|
||||||
|
.page = row.page,
|
||||||
|
.start = 0,
|
||||||
|
.end = row.y + 1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
.count => |*limit| count: {
|
||||||
|
assert(limit.* > 0); // should be handled already
|
||||||
|
const len = @min(row.y, limit.*);
|
||||||
|
if (len > limit.*) {
|
||||||
|
self.row = row.up(len);
|
||||||
|
limit.* -= len;
|
||||||
|
} else {
|
||||||
|
self.row = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
break :count .{
|
||||||
|
.page = row.page,
|
||||||
|
.start = row.y - len,
|
||||||
|
.end = row.y - 1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
.row => |limit_row| row: {
|
||||||
|
// If this is not the same page as our limit then we
|
||||||
|
// can consume the entire page.
|
||||||
|
if (limit_row.page != row.page) {
|
||||||
|
self.row = next: {
|
||||||
|
const next_page = row.page.prev orelse break :next null;
|
||||||
|
break :next .{
|
||||||
|
.page = next_page,
|
||||||
|
.y = next_page.data.size.rows - 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
break :row .{
|
||||||
|
.page = row.page,
|
||||||
|
.start = 0,
|
||||||
|
.end = row.y + 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the same page then we only consume up to
|
||||||
|
// the limit row.
|
||||||
|
self.row = null;
|
||||||
|
if (row.y < limit_row.y) return null;
|
||||||
|
break :row .{
|
||||||
|
.page = row.page,
|
||||||
|
.start = limit_row.y,
|
||||||
|
.end = row.y + 1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub const Chunk = struct {
|
pub const Chunk = struct {
|
||||||
page: *List.Node,
|
page: *List.Node,
|
||||||
start: usize,
|
start: usize,
|
||||||
@ -1667,37 +1750,33 @@ pub const PageIterator = struct {
|
|||||||
/// bl_pt must be greater than or equal to tl_pt.
|
/// bl_pt must be greater than or equal to tl_pt.
|
||||||
pub fn pageIterator(
|
pub fn pageIterator(
|
||||||
self: *const PageList,
|
self: *const PageList,
|
||||||
|
direction: Direction,
|
||||||
tl_pt: point.Point,
|
tl_pt: point.Point,
|
||||||
bl_pt: ?point.Point,
|
bl_pt: ?point.Point,
|
||||||
) PageIterator {
|
) PageIterator {
|
||||||
// TODO: bl_pt assertions
|
const tl_pin = self.pin(tl_pt).?;
|
||||||
|
const bl_pin = if (bl_pt) |pt|
|
||||||
|
self.pin(pt).?
|
||||||
|
else
|
||||||
|
self.getBottomRight(tl_pt) orelse return .{ .row = null };
|
||||||
|
|
||||||
const tl = self.getTopLeft(tl_pt);
|
if (comptime std.debug.runtime_safety) {
|
||||||
const limit: PageIterator.Limit = limit: {
|
assert(tl_pin.eql(bl_pin) or tl_pin.isBefore(bl_pin));
|
||||||
if (bl_pt) |pt| {
|
|
||||||
const bl = self.getTopLeft(pt);
|
|
||||||
break :limit .{ .row = bl.down(pt.coord().y).? };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break :limit switch (tl_pt) {
|
return switch (direction) {
|
||||||
// These always go to the end of the screen.
|
.right_down => .{
|
||||||
.screen, .active => .{ .none = {} },
|
.row = tl_pin,
|
||||||
|
.limit = .{ .row = bl_pin },
|
||||||
|
.direction = .right_down,
|
||||||
|
},
|
||||||
|
|
||||||
// Viewport always is rows long
|
.left_up => .{
|
||||||
.viewport => .{ .count = self.rows },
|
.row = bl_pin,
|
||||||
|
.limit = .{ .row = tl_pin },
|
||||||
// History goes to the top of the active area. This is more expensive
|
.direction = .left_up,
|
||||||
// to calculate but also more rare of a thing to iterate over.
|
|
||||||
.history => history: {
|
|
||||||
const active_tl = self.getTopLeft(.active);
|
|
||||||
const history_bot = active_tl.up(1) orelse
|
|
||||||
return .{ .row = null };
|
|
||||||
break :history .{ .row = history_bot };
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
return .{ .row = tl.down(tl_pt.coord().y), .limit = limit };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the top-left of the screen for the given tag.
|
/// Get the top-left of the screen for the given tag.
|
||||||
@ -1732,6 +1811,32 @@ fn getTopLeft(self: *const PageList, tag: point.Tag) Pin {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the bottom right of the screen for the given tag. This can
|
||||||
|
/// return null because it is possible that a tag is not in the screen
|
||||||
|
/// (e.g. history does not yet exist).
|
||||||
|
fn getBottomRight(self: *const PageList, tag: point.Tag) ?Pin {
|
||||||
|
return switch (tag) {
|
||||||
|
.screen, .active => last: {
|
||||||
|
const page = self.pages.last.?;
|
||||||
|
break :last .{
|
||||||
|
.page = page,
|
||||||
|
.y = page.data.size.rows - 1,
|
||||||
|
.x = page.data.size.cols - 1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
.viewport => viewport: {
|
||||||
|
const tl = self.getTopLeft(.viewport);
|
||||||
|
break :viewport tl.down(self.rows - 1).?;
|
||||||
|
},
|
||||||
|
|
||||||
|
.history => active: {
|
||||||
|
const tl = self.getTopLeft(.active);
|
||||||
|
break :active tl.up(1);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// The total rows in the screen. This is the actual row count currently
|
/// The total rows in the screen. This is the actual row count currently
|
||||||
/// and not a capacity or maximum.
|
/// and not a capacity or maximum.
|
||||||
///
|
///
|
||||||
@ -2467,7 +2572,7 @@ test "PageList pageIterator single page" {
|
|||||||
try testing.expect(s.pages.first.?.next == null);
|
try testing.expect(s.pages.first.?.next == null);
|
||||||
|
|
||||||
// Iterate the active area
|
// Iterate the active area
|
||||||
var it = s.pageIterator(.{ .active = .{} }, null);
|
var it = s.pageIterator(.right_down, .{ .active = .{} }, null);
|
||||||
{
|
{
|
||||||
const chunk = it.next().?;
|
const chunk = it.next().?;
|
||||||
try testing.expect(chunk.page == s.pages.first.?);
|
try testing.expect(chunk.page == s.pages.first.?);
|
||||||
@ -2495,7 +2600,7 @@ test "PageList pageIterator two pages" {
|
|||||||
try testing.expect(try s.grow() != null);
|
try testing.expect(try s.grow() != null);
|
||||||
|
|
||||||
// Iterate the active area
|
// Iterate the active area
|
||||||
var it = s.pageIterator(.{ .active = .{} }, null);
|
var it = s.pageIterator(.right_down, .{ .active = .{} }, null);
|
||||||
{
|
{
|
||||||
const chunk = it.next().?;
|
const chunk = it.next().?;
|
||||||
try testing.expect(chunk.page == s.pages.first.?);
|
try testing.expect(chunk.page == s.pages.first.?);
|
||||||
@ -2529,7 +2634,7 @@ test "PageList pageIterator history two pages" {
|
|||||||
try testing.expect(try s.grow() != null);
|
try testing.expect(try s.grow() != null);
|
||||||
|
|
||||||
// Iterate the active area
|
// Iterate the active area
|
||||||
var it = s.pageIterator(.{ .history = .{} }, null);
|
var it = s.pageIterator(.right_down, .{ .history = .{} }, null);
|
||||||
{
|
{
|
||||||
const active_tl = s.getTopLeft(.active);
|
const active_tl = s.getTopLeft(.active);
|
||||||
const chunk = it.next().?;
|
const chunk = it.next().?;
|
||||||
@ -2541,6 +2646,145 @@ test "PageList pageIterator history two pages" {
|
|||||||
try testing.expect(it.next() == null);
|
try testing.expect(it.next() == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "PageList pageIterator reverse single page" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 80, 24, null);
|
||||||
|
defer s.deinit();
|
||||||
|
|
||||||
|
// The viewport should be within a single page
|
||||||
|
try testing.expect(s.pages.first.?.next == null);
|
||||||
|
|
||||||
|
// Iterate the active area
|
||||||
|
var it = s.pageIterator(.left_up, .{ .active = .{} }, null);
|
||||||
|
{
|
||||||
|
const chunk = it.next().?;
|
||||||
|
try testing.expect(chunk.page == s.pages.first.?);
|
||||||
|
try testing.expectEqual(@as(usize, 0), chunk.start);
|
||||||
|
try testing.expectEqual(@as(usize, s.rows), chunk.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should only have one chunk
|
||||||
|
try testing.expect(it.next() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "PageList pageIterator reverse two pages" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 80, 24, null);
|
||||||
|
defer s.deinit();
|
||||||
|
|
||||||
|
// Grow to capacity
|
||||||
|
const page1_node = s.pages.last.?;
|
||||||
|
const page1 = page1_node.data;
|
||||||
|
for (0..page1.capacity.rows - page1.size.rows) |_| {
|
||||||
|
try testing.expect(try s.grow() == null);
|
||||||
|
}
|
||||||
|
try testing.expect(try s.grow() != null);
|
||||||
|
|
||||||
|
// Iterate the active area
|
||||||
|
var it = s.pageIterator(.left_up, .{ .active = .{} }, null);
|
||||||
|
var count: usize = 0;
|
||||||
|
{
|
||||||
|
const chunk = it.next().?;
|
||||||
|
try testing.expect(chunk.page == s.pages.last.?);
|
||||||
|
const start: usize = 0;
|
||||||
|
try testing.expectEqual(start, chunk.start);
|
||||||
|
try testing.expectEqual(start + 1, chunk.end);
|
||||||
|
count += chunk.end - chunk.start;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const chunk = it.next().?;
|
||||||
|
try testing.expect(chunk.page == s.pages.first.?);
|
||||||
|
const start = chunk.page.data.size.rows - s.rows + 1;
|
||||||
|
try testing.expectEqual(start, chunk.start);
|
||||||
|
try testing.expectEqual(chunk.page.data.size.rows, chunk.end);
|
||||||
|
count += chunk.end - chunk.start;
|
||||||
|
}
|
||||||
|
try testing.expect(it.next() == null);
|
||||||
|
try testing.expectEqual(s.rows, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "PageList pageIterator reverse history two pages" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 80, 24, null);
|
||||||
|
defer s.deinit();
|
||||||
|
|
||||||
|
// Grow to capacity
|
||||||
|
const page1_node = s.pages.last.?;
|
||||||
|
const page1 = page1_node.data;
|
||||||
|
for (0..page1.capacity.rows - page1.size.rows) |_| {
|
||||||
|
try testing.expect(try s.grow() == null);
|
||||||
|
}
|
||||||
|
try testing.expect(try s.grow() != null);
|
||||||
|
|
||||||
|
// Iterate the active area
|
||||||
|
var it = s.pageIterator(.left_up, .{ .history = .{} }, null);
|
||||||
|
{
|
||||||
|
const active_tl = s.getTopLeft(.active);
|
||||||
|
const chunk = it.next().?;
|
||||||
|
try testing.expect(chunk.page == s.pages.first.?);
|
||||||
|
const start: usize = 0;
|
||||||
|
try testing.expectEqual(start, chunk.start);
|
||||||
|
try testing.expectEqual(active_tl.y, chunk.end);
|
||||||
|
}
|
||||||
|
try testing.expect(it.next() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "PageList cellIterator" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 2, 2, 0);
|
||||||
|
defer s.deinit();
|
||||||
|
try testing.expect(s.pages.first == s.pages.last);
|
||||||
|
const page = &s.pages.first.?.data;
|
||||||
|
for (0..s.rows) |y| {
|
||||||
|
for (0..s.cols) |x| {
|
||||||
|
const rac = page.getRowAndCell(x, y);
|
||||||
|
rac.cell.* = .{
|
||||||
|
.content_tag = .codepoint,
|
||||||
|
.content = .{ .codepoint = @intCast(x) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var it = s.cellIterator(.{ .screen = .{} }, null);
|
||||||
|
{
|
||||||
|
const p = it.next().?;
|
||||||
|
try testing.expectEqual(point.Point{ .screen = .{
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
} }, s.pointFromPin(.screen, p).?);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const p = it.next().?;
|
||||||
|
try testing.expectEqual(point.Point{ .screen = .{
|
||||||
|
.x = 1,
|
||||||
|
.y = 0,
|
||||||
|
} }, s.pointFromPin(.screen, p).?);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const p = it.next().?;
|
||||||
|
try testing.expectEqual(point.Point{ .screen = .{
|
||||||
|
.x = 0,
|
||||||
|
.y = 1,
|
||||||
|
} }, s.pointFromPin(.screen, p).?);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const p = it.next().?;
|
||||||
|
try testing.expectEqual(point.Point{ .screen = .{
|
||||||
|
.x = 1,
|
||||||
|
.y = 1,
|
||||||
|
} }, s.pointFromPin(.screen, p).?);
|
||||||
|
}
|
||||||
|
try testing.expect(it.next() == null);
|
||||||
|
}
|
||||||
|
|
||||||
test "PageList erase" {
|
test "PageList erase" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
@ -3181,7 +3425,7 @@ test "PageList resize (no reflow) less cols clears graphemes" {
|
|||||||
try testing.expectEqual(@as(usize, 5), s.cols);
|
try testing.expectEqual(@as(usize, 5), s.cols);
|
||||||
try testing.expectEqual(@as(usize, 10), s.totalRows());
|
try testing.expectEqual(@as(usize, 10), s.totalRows());
|
||||||
|
|
||||||
var it = s.pageIterator(.{ .screen = .{} }, null);
|
var it = s.pageIterator(.right_down, .{ .screen = .{} }, null);
|
||||||
while (it.next()) |chunk| {
|
while (it.next()) |chunk| {
|
||||||
try testing.expectEqual(@as(usize, 0), chunk.page.data.graphemeCount());
|
try testing.expectEqual(@as(usize, 0), chunk.page.data.graphemeCount());
|
||||||
}
|
}
|
||||||
@ -4547,53 +4791,3 @@ test "PageList resize reflow less cols to wrap a wide char" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "PageList cellIterator" {
|
|
||||||
const testing = std.testing;
|
|
||||||
const alloc = testing.allocator;
|
|
||||||
|
|
||||||
var s = try init(alloc, 2, 2, 0);
|
|
||||||
defer s.deinit();
|
|
||||||
try testing.expect(s.pages.first == s.pages.last);
|
|
||||||
const page = &s.pages.first.?.data;
|
|
||||||
for (0..s.rows) |y| {
|
|
||||||
for (0..s.cols) |x| {
|
|
||||||
const rac = page.getRowAndCell(x, y);
|
|
||||||
rac.cell.* = .{
|
|
||||||
.content_tag = .codepoint,
|
|
||||||
.content = .{ .codepoint = @intCast(x) },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var it = s.cellIterator(.{ .screen = .{} }, null);
|
|
||||||
{
|
|
||||||
const p = it.next().?;
|
|
||||||
try testing.expectEqual(point.Point{ .screen = .{
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
} }, s.pointFromPin(.screen, p).?);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const p = it.next().?;
|
|
||||||
try testing.expectEqual(point.Point{ .screen = .{
|
|
||||||
.x = 1,
|
|
||||||
.y = 0,
|
|
||||||
} }, s.pointFromPin(.screen, p).?);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const p = it.next().?;
|
|
||||||
try testing.expectEqual(point.Point{ .screen = .{
|
|
||||||
.x = 0,
|
|
||||||
.y = 1,
|
|
||||||
} }, s.pointFromPin(.screen, p).?);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const p = it.next().?;
|
|
||||||
try testing.expectEqual(point.Point{ .screen = .{
|
|
||||||
.x = 1,
|
|
||||||
.y = 1,
|
|
||||||
} }, s.pointFromPin(.screen, p).?);
|
|
||||||
}
|
|
||||||
try testing.expect(it.next() == null);
|
|
||||||
}
|
|
||||||
|
@ -503,7 +503,7 @@ pub fn clearRows(
|
|||||||
bl: ?point.Point,
|
bl: ?point.Point,
|
||||||
protected: bool,
|
protected: bool,
|
||||||
) void {
|
) void {
|
||||||
var it = self.pages.pageIterator(tl, bl);
|
var it = self.pages.pageIterator(.right_down, tl, bl);
|
||||||
while (it.next()) |chunk| {
|
while (it.next()) |chunk| {
|
||||||
for (chunk.rows()) |*row| {
|
for (chunk.rows()) |*row| {
|
||||||
const cells_offset = row.cells;
|
const cells_offset = row.cells;
|
||||||
|
@ -1864,7 +1864,7 @@ pub fn decaln(self: *Terminal) !void {
|
|||||||
self.eraseDisplay(.complete, false);
|
self.eraseDisplay(.complete, false);
|
||||||
|
|
||||||
// Fill with Es, does not move cursor.
|
// Fill with Es, does not move cursor.
|
||||||
var it = self.screen.pages.pageIterator(.{ .active = .{} }, null);
|
var it = self.screen.pages.pageIterator(.right_down, .{ .active = .{} }, null);
|
||||||
while (it.next()) |chunk| {
|
while (it.next()) |chunk| {
|
||||||
for (chunk.rows()) |*row| {
|
for (chunk.rows()) |*row| {
|
||||||
const cells_multi: [*]Cell = row.cells.ptr(chunk.page.data.memory);
|
const cells_multi: [*]Cell = row.cells.ptr(chunk.page.data.memory);
|
||||||
|
Reference in New Issue
Block a user