terminal/new: fix up cursor on grow cols

This commit is contained in:
Mitchell Hashimoto
2024-03-03 17:16:50 -08:00
parent fad08ade5b
commit 2147097631
3 changed files with 86 additions and 11 deletions

View File

@ -6442,6 +6442,7 @@ test "Screen: resize more rows with populated scrollback" {
}
}
// X
test "Screen: resize more rows and cols with wrapping" {
const testing = std.testing;
const alloc = testing.allocator;

View File

@ -457,6 +457,46 @@ fn resizeGrowCols(
} else {
for (total..self.rows) |_| _ = try self.grow();
}
// If we have a cursor, we need to update the correct y value. I'm
// not at all happy about this, I wish we could do this in a more
// efficient way as we resize the pages. But at the time of typing this
// I can't think of a way and I'd rather get things working. Someone please
// help!
//
// The challenge is that as rows are unwrapped, we want to preserve the
// cursor. So for examle if you have "A\nB" where AB is soft-wrapped and
// the cursor is on 'B' (x=0, y=1) and you grow the columns, we want
// the cursor to remain on B (x=1, y=0) as it grows.
//
// The easy thing to do would be to count how many rows we unwrapped
// and then subtract that from the original y. That's how I started. The
// challenge is that if we unwrap with scrollback, our scrollback is
// "pulled down" so that the original (x=0,y=0) line is now pushed down.
// Detecting this while resizing seems non-obvious. This is a tested case
// so if you change this logic, you should see failures or passes if it
// works.
//
// The approach I take instead is if we have a cursor offset, I work
// backwards to find the offset we marked while reflowing and update
// the y from that. This is _not terrible_ because active areas are
// generally small and this is a more or less linear search. Its just
// kind of clunky.
if (cursor) |c| cursor: {
const offset = c.offset orelse break :cursor;
var active_it = self.rowIterator(.{ .active = .{} }, null);
var y: size.CellCountInt = 0;
while (active_it.next()) |it_offset| {
if (it_offset.page == offset.page and
it_offset.row_offset == offset.row_offset)
{
c.y = y;
break :cursor;
}
y += 1;
}
}
}
// We use a cursor to track where we are in the src/dst. This is very
@ -672,6 +712,9 @@ fn reflowPage(
// better calculate the CHANGE in coordinate by subtracting
// our dst from src which will calculate how many rows
// we unwrapped to get here.
//
// Note this doesn't handle when we pull down scrollback.
// See the cursor updates in resizeGrowCols for that.
c.y -|= src_cursor.y - dst_cursor.y;
c.offset = .{

View File

@ -2476,14 +2476,13 @@ test "Screen: resize more cols with populated scrollback" {
}
// Cursor should still be on the "5"
// TODO
// {
// const list_cell = s.pages.getCell(.{ .active = .{
// .x = s.cursor.x,
// .y = s.cursor.y,
// } }).?;
// try testing.expectEqual(@as(u21, '5'), list_cell.cell.content.codepoint);
// }
{
const list_cell = s.pages.getCell(.{ .active = .{
.x = s.cursor.x,
.y = s.cursor.y,
} }).?;
try testing.expectEqual(@as(u21, '5'), list_cell.cell.content.codepoint);
}
}
test "Screen: resize more cols with reflow" {
@ -2523,9 +2522,41 @@ test "Screen: resize more cols with reflow" {
}
// Our cursor should've moved
// TODO
// try testing.expectEqual(@as(size.CellCountInt, 2), s.cursor.x);
// try testing.expectEqual(@as(size.CellCountInt, 2), s.cursor.y);
try testing.expectEqual(@as(size.CellCountInt, 2), s.cursor.x);
try testing.expectEqual(@as(size.CellCountInt, 2), s.cursor.y);
}
test "Screen: resize more rows and cols with wrapping" {
const testing = std.testing;
const alloc = testing.allocator;
var s = try init(alloc, 2, 4, 0);
defer s.deinit();
const str = "1A2B\n3C4D";
try s.testWriteString(str);
{
const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} });
defer alloc.free(contents);
const expected = "1A\n2B\n3C\n4D";
try testing.expectEqualStrings(expected, contents);
}
try s.resize(5, 10);
// Cursor should move due to wrapping
try testing.expectEqual(@as(size.CellCountInt, 3), s.cursor.x);
try testing.expectEqual(@as(size.CellCountInt, 1), s.cursor.y);
{
const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} });
defer alloc.free(contents);
try testing.expectEqualStrings(str, contents);
}
{
const contents = try s.dumpStringAlloc(alloc, .{ .screen = .{} });
defer alloc.free(contents);
try testing.expectEqualStrings(str, contents);
}
}
test "Screen: resize less rows no scrollback" {