mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 08:16:13 +03:00
reflow cursor when shrinking cols
This commit is contained in:
@ -647,6 +647,13 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
|
|||||||
);
|
);
|
||||||
std.mem.set(Cell, storage, .{ .char = 0 });
|
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)
|
// Nothing can fail from this point forward (no "try" expressions)
|
||||||
// so replace our storage. We defer freeing the "old" value because
|
// so replace our storage. We defer freeing the "old" value because
|
||||||
// we need to access the old screen to copy.
|
// 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.storage = storage;
|
||||||
self.cols = cols;
|
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.
|
// Iterate over the screen since we need to check for reflow.
|
||||||
var iter = old.rowIterator(.screen);
|
var iter = old.rowIterator(.screen);
|
||||||
var x: usize = 0;
|
var x: usize = 0;
|
||||||
@ -672,11 +682,19 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
|
|||||||
i -= 1;
|
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];
|
break :trim row[0..i];
|
||||||
};
|
};
|
||||||
|
|
||||||
// Copy all the cells into our row.
|
// Copy all the cells into our row.
|
||||||
for (trimmed_row) |cell| {
|
for (trimmed_row) |cell, i| {
|
||||||
// Soft wrap if we have to
|
// Soft wrap if we have to
|
||||||
if (x == self.cols) {
|
if (x == self.cols) {
|
||||||
var last_cell = self.getCell(y, x - 1);
|
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;
|
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
|
// Copy the old cell, unset the old wrap state
|
||||||
var new_cell = self.getCell(y, x);
|
var new_cell = self.getCell(y, x);
|
||||||
new_cell.* = cell;
|
new_cell.* = cell;
|
||||||
@ -709,6 +735,14 @@ pub fn resize(self: *Screen, alloc: Allocator, rows: usize, cols: usize) !void {
|
|||||||
x = 0;
|
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);
|
defer s.deinit(alloc);
|
||||||
const str = "1AB\n2EF\n3IJ";
|
const str = "1AB\n2EF\n3IJ";
|
||||||
s.testWriteString(str);
|
s.testWriteString(str);
|
||||||
|
const cursor = s.cursor;
|
||||||
try s.resize(alloc, 3, 3);
|
try s.resize(alloc, 3, 3);
|
||||||
|
|
||||||
|
// Cursor should not move
|
||||||
|
try testing.expectEqual(cursor, s.cursor);
|
||||||
|
|
||||||
{
|
{
|
||||||
var contents = try s.testString(alloc, .viewport);
|
var contents = try s.testString(alloc, .viewport);
|
||||||
defer alloc.free(contents);
|
defer alloc.free(contents);
|
||||||
@ -1578,8 +1616,13 @@ test "Screen: resize less cols with reflow but row space" {
|
|||||||
defer s.deinit(alloc);
|
defer s.deinit(alloc);
|
||||||
const str = "1ABCD";
|
const str = "1ABCD";
|
||||||
s.testWriteString(str);
|
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);
|
var contents = try s.testString(alloc, .viewport);
|
||||||
defer alloc.free(contents);
|
defer alloc.free(contents);
|
||||||
@ -1592,6 +1635,10 @@ test "Screen: resize less cols with reflow but row space" {
|
|||||||
const expected = "1AB\nCD";
|
const expected = "1AB\nCD";
|
||||||
try testing.expectEqualStrings(expected, contents);
|
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" {
|
test "Screen: resize less cols with reflow with trimmed rows" {
|
||||||
|
Reference in New Issue
Block a user