mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
new screen supports resize without reflow
This commit is contained in:
@ -190,10 +190,11 @@ pub const Row = struct {
|
|||||||
return &self.storage[x + 1].cell;
|
return &self.storage[x + 1].cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy the row src into this row.
|
/// Copy the row src into this row. The row can be from another screen.
|
||||||
pub fn copyRow(self: Row, src: Row) void {
|
pub fn copyRow(self: Row, src: Row) void {
|
||||||
assert(self.header().init);
|
assert(self.header().init);
|
||||||
std.mem.copy(StorageCell, self.storage[1..], src.storage[1..]);
|
const end = @minimum(src.storage.len, self.storage.len);
|
||||||
|
std.mem.copy(StorageCell, self.storage[1..], src.storage[1..end]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read-only iterator for the cells in the row.
|
/// Read-only iterator for the cells in the row.
|
||||||
@ -734,6 +735,53 @@ fn selectionSlices(self: *Screen, sel_raw: Selection) struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resize the screen without any reflow. In this mode, columns/rows will
|
||||||
|
/// be truncated as they are shrunk. If they are grown, the new space is filled
|
||||||
|
/// with zeros.
|
||||||
|
pub fn resizeWithoutReflow(self: *Screen, rows: usize, cols: usize) !void {
|
||||||
|
// Make a copy so we can access the old indexes.
|
||||||
|
var old = self.*;
|
||||||
|
errdefer self.* = old;
|
||||||
|
|
||||||
|
// Change our rows and cols so calculations make sense
|
||||||
|
self.rows = rows;
|
||||||
|
self.cols = cols;
|
||||||
|
|
||||||
|
// Calculate our buffer size. This is going to be either the old data
|
||||||
|
// with scrollback or the max capacity of our new size. We prefer the old
|
||||||
|
// length so we can save all the data (ignoring col truncation).
|
||||||
|
const old_len = old.rowsWritten() * (cols + 1);
|
||||||
|
const new_max_capacity = self.maxCapacity();
|
||||||
|
const buf_size = @minimum(old_len, new_max_capacity);
|
||||||
|
|
||||||
|
// Reallocate the storage
|
||||||
|
self.storage = try StorageBuf.init(self.alloc, buf_size);
|
||||||
|
errdefer self.storage.deinit(self.alloc);
|
||||||
|
defer old.storage.deinit(self.alloc);
|
||||||
|
|
||||||
|
// Move our cursor if we have to so it stays on the screen.
|
||||||
|
self.cursor.x = @minimum(self.cursor.x, self.cols - 1);
|
||||||
|
self.cursor.y = @minimum(self.cursor.y, self.rows - 1);
|
||||||
|
|
||||||
|
// Rewrite all our rows
|
||||||
|
var y: usize = 0;
|
||||||
|
var row_it = old.rowIterator(.screen);
|
||||||
|
while (row_it.next()) |old_row| {
|
||||||
|
// If we're past the end, scroll
|
||||||
|
if (y >= self.rows) {
|
||||||
|
y -= 1;
|
||||||
|
try self.scroll(.{ .delta = 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get this row
|
||||||
|
const new_row = self.getRow(.{ .active = y });
|
||||||
|
new_row.copyRow(old_row);
|
||||||
|
|
||||||
|
// Next row
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Writes a basic string into the screen for testing. Newlines (\n) separate
|
/// Writes a basic string into the screen for testing. Newlines (\n) separate
|
||||||
/// each row. If a line is longer than the available columns, soft-wrapping
|
/// each row. If a line is longer than the available columns, soft-wrapping
|
||||||
/// will occur. This will automatically handle basic wide chars.
|
/// will occur. This will automatically handle basic wide chars.
|
||||||
@ -1261,3 +1309,72 @@ test "Screen: selectionString wide char with header" {
|
|||||||
try testing.expectEqualStrings(expected, contents);
|
try testing.expectEqualStrings(expected, contents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Screen: resize (no reflow) more rows" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 3, 5, 0);
|
||||||
|
defer s.deinit();
|
||||||
|
const str = "1ABCD\n2EFGH\n3IJKL";
|
||||||
|
try s.testWriteString(str);
|
||||||
|
try s.resizeWithoutReflow(10, 5);
|
||||||
|
|
||||||
|
{
|
||||||
|
var contents = try s.testString(alloc, .viewport);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings(str, contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Screen: resize (no reflow) less rows" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 3, 5, 0);
|
||||||
|
defer s.deinit();
|
||||||
|
const str = "1ABCD\n2EFGH\n3IJKL";
|
||||||
|
try s.testWriteString(str);
|
||||||
|
try s.resizeWithoutReflow(2, 5);
|
||||||
|
|
||||||
|
{
|
||||||
|
var contents = try s.testString(alloc, .viewport);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("2EFGH\n3IJKL", contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Screen: resize (no reflow) more cols" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 3, 5, 0);
|
||||||
|
defer s.deinit();
|
||||||
|
const str = "1ABCD\n2EFGH\n3IJKL";
|
||||||
|
try s.testWriteString(str);
|
||||||
|
try s.resizeWithoutReflow(3, 10);
|
||||||
|
|
||||||
|
{
|
||||||
|
var contents = try s.testString(alloc, .viewport);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings(str, contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Screen: resize (no reflow) less cols" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 3, 5, 0);
|
||||||
|
defer s.deinit();
|
||||||
|
const str = "1ABCD\n2EFGH\n3IJKL";
|
||||||
|
try s.testWriteString(str);
|
||||||
|
try s.resizeWithoutReflow(3, 4);
|
||||||
|
|
||||||
|
{
|
||||||
|
var contents = try s.testString(alloc, .viewport);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
const expected = "1ABC\n2EFG\n3IJK";
|
||||||
|
try testing.expectEqualStrings(expected, contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user