terminal2: PageList iterators all support reverse

This commit is contained in:
Mitchell Hashimoto
2024-03-05 21:39:22 -08:00
parent 83af8d1aac
commit 6dd88c29ca
2 changed files with 133 additions and 36 deletions

View File

@ -1502,6 +1502,8 @@ pub const CellIterator = struct {
pub fn next(self: *CellIterator) ?Pin { pub fn next(self: *CellIterator) ?Pin {
const cell = self.cell orelse return null; const cell = self.cell orelse return null;
switch (self.row_it.page_it.direction) {
.right_down => {
if (cell.x + 1 < cell.page.data.size.cols) { if (cell.x + 1 < cell.page.data.size.cols) {
// We still have cells in this row, increase x. // We still have cells in this row, increase x.
var copy = cell; var copy = cell;
@ -1511,6 +1513,26 @@ pub const CellIterator = struct {
// We need to move to the next row. // We need to move to the next row.
self.cell = self.row_it.next(); self.cell = self.row_it.next();
} }
},
.left_up => {
if (cell.x > 0) {
// We still have cells in this row, decrease x.
var copy = cell;
copy.x -= 1;
self.cell = copy;
} else {
// We need to move to the previous row and last col
if (self.row_it.next()) |next_cell| {
var copy = next_cell;
copy.x = next_cell.page.data.size.cols - 1;
self.cell = copy;
} else {
self.cell = null;
}
}
},
}
return cell; return cell;
} }
@ -1518,11 +1540,13 @@ pub const CellIterator = struct {
pub fn cellIterator( pub fn cellIterator(
self: *const PageList, self: *const PageList,
direction: Direction,
tl_pt: point.Point, tl_pt: point.Point,
bl_pt: ?point.Point, bl_pt: ?point.Point,
) CellIterator { ) CellIterator {
var row_it = self.rowIterator(tl_pt, bl_pt); var row_it = self.rowIterator(direction, tl_pt, bl_pt);
const cell = row_it.next() orelse return .{ .row_it = row_it }; var cell = row_it.next() orelse return .{ .row_it = row_it };
if (direction == .left_up) cell.x = cell.page.data.size.cols - 1;
return .{ .row_it = row_it, .cell = cell }; return .{ .row_it = row_it, .cell = cell };
} }
@ -1535,6 +1559,8 @@ pub const RowIterator = struct {
const chunk = self.chunk orelse return null; const chunk = self.chunk orelse return null;
const row: Pin = .{ .page = chunk.page, .y = self.offset }; const row: Pin = .{ .page = chunk.page, .y = self.offset };
switch (self.page_it.direction) {
.right_down => {
// Increase our offset in the chunk // Increase our offset in the chunk
self.offset += 1; self.offset += 1;
@ -1543,6 +1569,19 @@ pub const RowIterator = struct {
self.chunk = self.page_it.next(); self.chunk = self.page_it.next();
if (self.chunk) |c| self.offset = c.start; if (self.chunk) |c| self.offset = c.start;
} }
},
.left_up => {
// If we are at the start of the chunk, we need to move to the
// previous chunk.
if (self.offset == 0) {
self.chunk = self.page_it.next();
if (self.chunk) |c| self.offset = c.end - 1;
} else {
self.offset -= 1;
}
},
}
return row; return row;
} }
@ -1555,12 +1594,20 @@ pub const RowIterator = struct {
/// iteration bounds. /// iteration bounds.
pub fn rowIterator( pub fn rowIterator(
self: *const PageList, self: *const PageList,
direction: Direction,
tl_pt: point.Point, tl_pt: point.Point,
bl_pt: ?point.Point, bl_pt: ?point.Point,
) RowIterator { ) RowIterator {
var page_it = self.pageIterator(.right_down, tl_pt, bl_pt); var page_it = self.pageIterator(direction, 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 = switch (direction) {
.right_down => chunk.start,
.left_up => chunk.end - 1,
},
};
} }
pub const PageIterator = struct { pub const PageIterator = struct {
@ -2753,7 +2800,7 @@ test "PageList cellIterator" {
} }
} }
var it = s.cellIterator(.{ .screen = .{} }, null); var it = s.cellIterator(.right_down, .{ .screen = .{} }, null);
{ {
const p = it.next().?; const p = it.next().?;
try testing.expectEqual(point.Point{ .screen = .{ try testing.expectEqual(point.Point{ .screen = .{
@ -2785,6 +2832,56 @@ test "PageList cellIterator" {
try testing.expect(it.next() == null); try testing.expect(it.next() == null);
} }
test "PageList cellIterator reverse" {
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(.left_up, .{ .screen = .{} }, null);
{
const p = it.next().?;
try testing.expectEqual(point.Point{ .screen = .{
.x = 1,
.y = 1,
} }, 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 = 0,
} }, s.pointFromPin(.screen, p).?);
}
{
const p = it.next().?;
try testing.expectEqual(point.Point{ .screen = .{
.x = 0,
.y = 0,
} }, 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;
@ -3364,7 +3461,7 @@ test "PageList resize (no reflow) less cols" {
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.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
while (it.next()) |offset| { while (it.next()) |offset| {
const rac = offset.rowAndCell(); const rac = offset.rowAndCell();
const cells = offset.page.data.getCells(rac.row); const cells = offset.page.data.getCells(rac.row);
@ -3388,7 +3485,7 @@ test "PageList resize (no reflow) less cols pin in trimmed cols" {
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.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
while (it.next()) |offset| { while (it.next()) |offset| {
const rac = offset.rowAndCell(); const rac = offset.rowAndCell();
const cells = offset.page.data.getCells(rac.row); const cells = offset.page.data.getCells(rac.row);
@ -3443,7 +3540,7 @@ test "PageList resize (no reflow) more cols" {
try testing.expectEqual(@as(usize, 10), s.cols); try testing.expectEqual(@as(usize, 10), s.cols);
try testing.expectEqual(@as(usize, 3), s.totalRows()); try testing.expectEqual(@as(usize, 3), s.totalRows());
var it = s.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
while (it.next()) |offset| { while (it.next()) |offset| {
const rac = offset.rowAndCell(); const rac = offset.rowAndCell();
const cells = offset.page.data.getCells(rac.row); const cells = offset.page.data.getCells(rac.row);
@ -3467,7 +3564,7 @@ test "PageList resize (no reflow) less cols then more cols" {
try testing.expectEqual(@as(usize, 5), s.cols); try testing.expectEqual(@as(usize, 5), s.cols);
try testing.expectEqual(@as(usize, 3), s.totalRows()); try testing.expectEqual(@as(usize, 3), s.totalRows());
var it = s.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
while (it.next()) |offset| { while (it.next()) |offset| {
const rac = offset.rowAndCell(); const rac = offset.rowAndCell();
const cells = offset.page.data.getCells(rac.row); const cells = offset.page.data.getCells(rac.row);
@ -3487,7 +3584,7 @@ test "PageList resize (no reflow) less rows and cols" {
try testing.expectEqual(@as(usize, 5), s.cols); try testing.expectEqual(@as(usize, 5), s.cols);
try testing.expectEqual(@as(usize, 7), s.rows); try testing.expectEqual(@as(usize, 7), s.rows);
var it = s.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
while (it.next()) |offset| { while (it.next()) |offset| {
const rac = offset.rowAndCell(); const rac = offset.rowAndCell();
const cells = offset.page.data.getCells(rac.row); const cells = offset.page.data.getCells(rac.row);
@ -3508,7 +3605,7 @@ test "PageList resize (no reflow) more rows and less cols" {
try testing.expectEqual(@as(usize, 20), s.rows); try testing.expectEqual(@as(usize, 20), s.rows);
try testing.expectEqual(@as(usize, 20), s.totalRows()); try testing.expectEqual(@as(usize, 20), s.totalRows());
var it = s.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
while (it.next()) |offset| { while (it.next()) |offset| {
const rac = offset.rowAndCell(); const rac = offset.rowAndCell();
const cells = offset.page.data.getCells(rac.row); const cells = offset.page.data.getCells(rac.row);
@ -3529,7 +3626,7 @@ test "PageList resize (no reflow) empty screen" {
try testing.expectEqual(@as(usize, 10), s.rows); try testing.expectEqual(@as(usize, 10), s.rows);
try testing.expectEqual(@as(usize, 10), s.totalRows()); try testing.expectEqual(@as(usize, 10), s.totalRows());
var it = s.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
while (it.next()) |offset| { while (it.next()) |offset| {
const rac = offset.rowAndCell(); const rac = offset.rowAndCell();
const cells = offset.page.data.getCells(rac.row); const cells = offset.page.data.getCells(rac.row);
@ -3568,7 +3665,7 @@ test "PageList resize (no reflow) more cols forces smaller cap" {
// Our total rows should be the same, and contents should be the same. // Our total rows should be the same, and contents should be the same.
try testing.expectEqual(rows, s.totalRows()); try testing.expectEqual(rows, s.totalRows());
var it = s.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
while (it.next()) |offset| { while (it.next()) |offset| {
const rac = offset.rowAndCell(); const rac = offset.rowAndCell();
const cells = offset.page.data.getCells(rac.row); const cells = offset.page.data.getCells(rac.row);
@ -3673,7 +3770,7 @@ test "PageList resize reflow more cols no wrapped rows" {
try testing.expectEqual(@as(usize, 10), s.cols); try testing.expectEqual(@as(usize, 10), s.cols);
try testing.expectEqual(@as(usize, 3), s.totalRows()); try testing.expectEqual(@as(usize, 3), s.totalRows());
var it = s.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
while (it.next()) |offset| { while (it.next()) |offset| {
const rac = offset.rowAndCell(); const rac = offset.rowAndCell();
const cells = offset.page.data.getCells(rac.row); const cells = offset.page.data.getCells(rac.row);
@ -3722,7 +3819,7 @@ test "PageList resize reflow more cols wrapped rows" {
} }, pt); } }, pt);
} }
var it = s.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
{ {
// First row should be unwrapped // First row should be unwrapped
const offset = it.next().?; const offset = it.next().?;
@ -4199,7 +4296,7 @@ test "PageList resize reflow less cols no wrapped rows" {
try testing.expectEqual(@as(usize, 5), s.cols); try testing.expectEqual(@as(usize, 5), s.cols);
try testing.expectEqual(@as(usize, 3), s.totalRows()); try testing.expectEqual(@as(usize, 3), s.totalRows());
var it = s.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
while (it.next()) |offset| { while (it.next()) |offset| {
for (0..4) |x| { for (0..4) |x| {
var offset_copy = offset; var offset_copy = offset;
@ -4244,7 +4341,7 @@ test "PageList resize reflow less cols wrapped rows" {
} }, pt); } }, pt);
} }
var it = s.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
{ {
// First row should be wrapped // First row should be wrapped
const offset = it.next().?; const offset = it.next().?;
@ -4320,7 +4417,7 @@ test "PageList resize reflow less cols wrapped rows with graphemes" {
try testing.expect(s.pages.first == s.pages.last); try testing.expect(s.pages.first == s.pages.last);
const page = &s.pages.first.?.data; const page = &s.pages.first.?.data;
var it = s.rowIterator(.{ .screen = .{} }, null); var it = s.rowIterator(.right_down, .{ .screen = .{} }, null);
{ {
// First row should be wrapped // First row should be wrapped
const offset = it.next().?; const offset = it.next().?;
@ -4554,7 +4651,7 @@ test "PageList resize reflow less cols blank lines" {
try testing.expectEqual(@as(usize, 2), s.cols); try testing.expectEqual(@as(usize, 2), s.cols);
try testing.expectEqual(@as(usize, 3), s.totalRows()); try testing.expectEqual(@as(usize, 3), s.totalRows());
var it = s.rowIterator(.{ .active = .{} }, null); var it = s.rowIterator(.right_down, .{ .active = .{} }, null);
{ {
// First row should be wrapped // First row should be wrapped
const offset = it.next().?; const offset = it.next().?;
@ -4606,7 +4703,7 @@ test "PageList resize reflow less cols blank lines between" {
try testing.expectEqual(@as(usize, 2), s.cols); try testing.expectEqual(@as(usize, 2), s.cols);
try testing.expectEqual(@as(usize, 4), s.totalRows()); try testing.expectEqual(@as(usize, 4), s.totalRows());
var it = s.rowIterator(.{ .active = .{} }, null); var it = s.rowIterator(.right_down, .{ .active = .{} }, null);
{ {
const offset = it.next().?; const offset = it.next().?;
const rac = offset.rowAndCell(); const rac = offset.rowAndCell();
@ -4661,7 +4758,7 @@ test "PageList resize reflow less cols copy style" {
try testing.expectEqual(@as(usize, 2), s.cols); try testing.expectEqual(@as(usize, 2), s.cols);
try testing.expectEqual(@as(usize, 2), s.totalRows()); try testing.expectEqual(@as(usize, 2), s.totalRows());
var it = s.rowIterator(.{ .active = .{} }, null); var it = s.rowIterator(.right_down, .{ .active = .{} }, null);
while (it.next()) |offset| { while (it.next()) |offset| {
for (0..s.cols - 1) |x| { for (0..s.cols - 1) |x| {
var offset_copy = offset; var offset_copy = offset;

View File

@ -852,7 +852,7 @@ pub fn dumpString(
) !void { ) !void {
var blank_rows: usize = 0; var blank_rows: usize = 0;
var iter = self.pages.rowIterator(tl, null); var iter = self.pages.rowIterator(.right_down, tl, null);
while (iter.next()) |row_offset| { while (iter.next()) |row_offset| {
const rac = row_offset.rowAndCell(); const rac = row_offset.rowAndCell();
const cells = cells: { const cells = cells: {