reflow cursor when shrinking cols

This commit is contained in:
Mitchell Hashimoto
2022-08-08 14:02:28 -07:00
parent 6fa4cb07c7
commit e4c8bbd394

View File

@ -647,6 +647,13 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
);
std.mem.set(Cell, storage, .{ .char = 0 });
// Convert our cursor coordinates to screen coordinates because
// we may have to reflow the cursor if the line it is on is moved.
var cursor_pos = (point.Viewport{
.x = self.cursor.x,
.y = self.cursor.y,
}).toScreen(self);
// Nothing can fail from this point forward (no "try" expressions)
// so replace our storage. We defer freeing the "old" value because
// we need to access the old screen to copy.
@ -658,6 +665,9 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
self.storage = storage;
self.cols = cols;
// Whether we need to move the cursor or not
var new_cursor: ?point.ScreenPoint = null;
// Iterate over the screen since we need to check for reflow.
var iter = old.rowIterator(.screen);
var x: usize = 0;
@ -672,11 +682,19 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
i -= 1;
}
// If our cursor was past the end of this line, move it
// to the end of the contentful area.
if (cursor_pos.y == iter.value - 1 and
cursor_pos.x >= i)
{
cursor_pos.x = i - 1;
}
break :trim row[0..i];
};
// Copy all the cells into our row.
for (trimmed_row) |cell| {
for (trimmed_row) |cell, i| {
// Soft wrap if we have to
if (x == self.cols) {
var last_cell = self.getCell(y, x - 1);
@ -692,6 +710,14 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
x = 0;
}
// If our cursor is on this point, we need to move it.
if (cursor_pos.y == iter.value - 1 and
cursor_pos.x == i)
{
assert(new_cursor == null);
new_cursor = .{ .x = x, .y = y };
}
// Copy the old cell, unset the old wrap state
var new_cell = self.getCell(y, x);
new_cell.* = cell;
@ -709,6 +735,14 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
x = 0;
}
}
// If we have a new cursor, we need to convert that to a viewport
// point and set it up.
if (new_cursor) |pos| {
const viewport_pos = pos.toViewport(self);
self.cursor.x = viewport_pos.x;
self.cursor.y = viewport_pos.y;
}
}
}
@ -1556,8 +1590,12 @@ test "Screen: resize less cols no reflow" {
defer s.deinit(alloc);
const str = "1AB\n2EF\n3IJ";
s.testWriteString(str);
const cursor = s.cursor;
try s.resize(alloc, 3, 3);
// Cursor should not move
try testing.expectEqual(cursor, s.cursor);
{
var contents = try s.testString(alloc, .viewport);
defer alloc.free(contents);
@ -1578,8 +1616,13 @@ test "Screen: resize less cols with reflow but row space" {
defer s.deinit(alloc);
const str = "1ABCD";
s.testWriteString(str);
try s.resize(alloc, 3, 3);
// Put our cursor on the end
s.cursor.x = 4;
s.cursor.y = 0;
try testing.expectEqual(@as(u32, 'D'), s.getCell(s.cursor.y, s.cursor.x).char);
try s.resize(alloc, 3, 3);
{
var contents = try s.testString(alloc, .viewport);
defer alloc.free(contents);
@ -1592,6 +1635,10 @@ test "Screen: resize less cols with reflow but row space" {
const expected = "1AB\nCD";
try testing.expectEqualStrings(expected, contents);
}
// Cursor should be on the last line
try testing.expectEqual(@as(usize, 1), s.cursor.x);
try testing.expectEqual(@as(usize, 1), s.cursor.y);
}
test "Screen: resize less cols with reflow with trimmed rows" {