mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
terminal/new: eraseDisplay history
This commit is contained in:
@ -364,7 +364,7 @@ fn createPage(self: *PageList) !*List.Node {
|
||||
/// If the top or bottom point is in the middle of a page, the other
|
||||
/// contents in the page will be preserved but the page itself will be
|
||||
/// underutilized (size < capacity).
|
||||
pub fn erase(
|
||||
pub fn eraseRows(
|
||||
self: *PageList,
|
||||
tl_pt: point.Point,
|
||||
bl_pt: ?point.Point,
|
||||
@ -388,7 +388,7 @@ pub fn erase(
|
||||
const rows = chunk.page.data.rows.ptr(chunk.page.data.memory);
|
||||
const scroll_amount = chunk.page.data.size.rows - chunk.end;
|
||||
for (0..scroll_amount) |i| {
|
||||
const src: *Row = &rows[i + scroll_amount];
|
||||
const src: *Row = &rows[i + chunk.end];
|
||||
const dst: *Row = &rows[i];
|
||||
const old_dst = dst.*;
|
||||
dst.* = src.*;
|
||||
@ -400,6 +400,17 @@ pub fn erase(
|
||||
// be written to again (its in the past) or it will grow and the
|
||||
// terminal erase will automatically erase the data.
|
||||
|
||||
// If our viewport is on this page and the offset is beyond
|
||||
// our new end, shift it.
|
||||
switch (self.viewport) {
|
||||
.top, .active => {},
|
||||
.exact => |*offset| exact: {
|
||||
if (offset.page != chunk.page) break :exact;
|
||||
offset.row_offset -|= scroll_amount;
|
||||
},
|
||||
}
|
||||
|
||||
// Our new size is the amount we scrolled
|
||||
chunk.page.data.size.rows = @intCast(scroll_amount);
|
||||
}
|
||||
}
|
||||
@ -407,6 +418,20 @@ pub fn erase(
|
||||
/// Erase a single page, freeing all its resources. The page can be
|
||||
/// anywhere in the linked list.
|
||||
fn erasePage(self: *PageList, page: *List.Node) void {
|
||||
// If our viewport is pinned to this page, then we need to update it.
|
||||
switch (self.viewport) {
|
||||
.top, .active => {},
|
||||
.exact => |*offset| {
|
||||
if (offset.page == page) {
|
||||
if (page.next) |next| {
|
||||
offset.page = next;
|
||||
} else {
|
||||
self.viewport = .{ .active = {} };
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Remove the page from the linked list
|
||||
self.pages.remove(page);
|
||||
|
||||
@ -1276,6 +1301,28 @@ test "PageList erase" {
|
||||
try testing.expect(s.totalRows() > s.rows);
|
||||
|
||||
// Erase the entire history, we should be back to just our active set.
|
||||
s.erase(.{ .history = .{} }, null);
|
||||
s.eraseRows(.{ .history = .{} }, null);
|
||||
try testing.expectEqual(s.rows, s.totalRows());
|
||||
}
|
||||
|
||||
test "PageList erase resets viewport if inside erased page" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var s = try init(alloc, 80, 24, null);
|
||||
defer s.deinit();
|
||||
|
||||
// Grow so we take up at least 5 pages.
|
||||
const page = &s.pages.last.?.data;
|
||||
for (0..page.capacity.rows * 5) |_| {
|
||||
_ = try s.grow();
|
||||
}
|
||||
|
||||
// Move our viewport to the top
|
||||
s.scroll(.{ .delta_row = -@as(isize, @intCast(s.totalRows())) });
|
||||
try testing.expect(s.viewport.exact.page == s.pages.first.?);
|
||||
|
||||
// Erase the entire history, we should be back to just our active set.
|
||||
s.eraseRows(.{ .history = .{} }, null);
|
||||
try testing.expect(s.viewport.exact.page == s.pages.first.?);
|
||||
}
|
||||
|
@ -299,6 +299,23 @@ pub fn scrollClear(self: *Screen) !void {
|
||||
self.kitty_images.dirty = true;
|
||||
}
|
||||
|
||||
/// Erase the region specified by tl and br, inclusive. This will physically
|
||||
/// erase the rows meaning the memory will be reclaimed (if the underlying
|
||||
/// page is empty) and other rows will be shifted up.
|
||||
pub fn eraseRows(
|
||||
self: *Screen,
|
||||
tl: point.Point,
|
||||
bl: ?point.Point,
|
||||
) void {
|
||||
// Erase the rows
|
||||
self.pages.eraseRows(tl, bl);
|
||||
|
||||
// Just to be safe, reset our cursor since it is possible depending
|
||||
// on the points that our active area shifted so our pointers are
|
||||
// invalid.
|
||||
//self.cursorAbsolute(self.cursor.x, self.cursor.y);
|
||||
}
|
||||
|
||||
// Clear the region specified by tl and bl, inclusive. Cleared cells are
|
||||
// colored with the current style background color. This will clear all
|
||||
// cells in the rows.
|
||||
@ -844,3 +861,71 @@ test "Screen clearRows active styled line" {
|
||||
defer alloc.free(str);
|
||||
try testing.expectEqualStrings("", str);
|
||||
}
|
||||
|
||||
test "Terminal: eraseRows history" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var s = try Screen.init(alloc, 5, 5, 1000);
|
||||
defer s.deinit();
|
||||
|
||||
try s.testWriteString("1\n2\n3\n4\n5\n6");
|
||||
|
||||
{
|
||||
const str = try s.dumpStringAlloc(alloc, .{ .active = .{} });
|
||||
defer alloc.free(str);
|
||||
try testing.expectEqualStrings("2\n3\n4\n5\n6", str);
|
||||
}
|
||||
{
|
||||
const str = try s.dumpStringAlloc(alloc, .{ .screen = .{} });
|
||||
defer alloc.free(str);
|
||||
try testing.expectEqualStrings("1\n2\n3\n4\n5\n6", str);
|
||||
}
|
||||
|
||||
s.eraseRows(.{ .history = .{} }, null);
|
||||
|
||||
{
|
||||
const str = try s.dumpStringAlloc(alloc, .{ .active = .{} });
|
||||
defer alloc.free(str);
|
||||
try testing.expectEqualStrings("2\n3\n4\n5\n6", str);
|
||||
}
|
||||
{
|
||||
const str = try s.dumpStringAlloc(alloc, .{ .screen = .{} });
|
||||
defer alloc.free(str);
|
||||
try testing.expectEqualStrings("2\n3\n4\n5\n6", str);
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: eraseRows history with more lines" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
var s = try Screen.init(alloc, 5, 5, 1000);
|
||||
defer s.deinit();
|
||||
|
||||
try s.testWriteString("A\nB\nC\n1\n2\n3\n4\n5\n6");
|
||||
|
||||
{
|
||||
const str = try s.dumpStringAlloc(alloc, .{ .active = .{} });
|
||||
defer alloc.free(str);
|
||||
try testing.expectEqualStrings("2\n3\n4\n5\n6", str);
|
||||
}
|
||||
{
|
||||
const str = try s.dumpStringAlloc(alloc, .{ .screen = .{} });
|
||||
defer alloc.free(str);
|
||||
try testing.expectEqualStrings("A\nB\nC\n1\n2\n3\n4\n5\n6", str);
|
||||
}
|
||||
|
||||
s.eraseRows(.{ .history = .{} }, null);
|
||||
|
||||
{
|
||||
const str = try s.dumpStringAlloc(alloc, .{ .active = .{} });
|
||||
defer alloc.free(str);
|
||||
try testing.expectEqualStrings("2\n3\n4\n5\n6", str);
|
||||
}
|
||||
{
|
||||
const str = try s.dumpStringAlloc(alloc, .{ .screen = .{} });
|
||||
defer alloc.free(str);
|
||||
try testing.expectEqualStrings("2\n3\n4\n5\n6", str);
|
||||
}
|
||||
}
|
||||
|
@ -1714,13 +1714,8 @@ pub fn eraseDisplay(
|
||||
// Unsets pending wrap state
|
||||
assert(!self.screen.cursor.pending_wrap);
|
||||
},
|
||||
//
|
||||
// .scrollback => self.screen.clear(.history) catch |err| {
|
||||
// // This isn't a huge issue, so just log it.
|
||||
// log.err("failed to clear scrollback: {}", .{err});
|
||||
// },
|
||||
|
||||
else => @panic("TODO"),
|
||||
.scrollback => self.screen.eraseRows(.{ .history = .{} }, null),
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user