mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +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
|
/// 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
|
/// contents in the page will be preserved but the page itself will be
|
||||||
/// underutilized (size < capacity).
|
/// underutilized (size < capacity).
|
||||||
pub fn erase(
|
pub fn eraseRows(
|
||||||
self: *PageList,
|
self: *PageList,
|
||||||
tl_pt: point.Point,
|
tl_pt: point.Point,
|
||||||
bl_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 rows = chunk.page.data.rows.ptr(chunk.page.data.memory);
|
||||||
const scroll_amount = chunk.page.data.size.rows - chunk.end;
|
const scroll_amount = chunk.page.data.size.rows - chunk.end;
|
||||||
for (0..scroll_amount) |i| {
|
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 dst: *Row = &rows[i];
|
||||||
const old_dst = dst.*;
|
const old_dst = dst.*;
|
||||||
dst.* = src.*;
|
dst.* = src.*;
|
||||||
@ -400,6 +400,17 @@ pub fn erase(
|
|||||||
// be written to again (its in the past) or it will grow and the
|
// be written to again (its in the past) or it will grow and the
|
||||||
// terminal erase will automatically erase the data.
|
// 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);
|
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
|
/// Erase a single page, freeing all its resources. The page can be
|
||||||
/// anywhere in the linked list.
|
/// anywhere in the linked list.
|
||||||
fn erasePage(self: *PageList, page: *List.Node) void {
|
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
|
// Remove the page from the linked list
|
||||||
self.pages.remove(page);
|
self.pages.remove(page);
|
||||||
|
|
||||||
@ -1276,6 +1301,28 @@ test "PageList erase" {
|
|||||||
try testing.expect(s.totalRows() > s.rows);
|
try testing.expect(s.totalRows() > s.rows);
|
||||||
|
|
||||||
// Erase the entire history, we should be back to just our active set.
|
// 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());
|
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;
|
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
|
// Clear the region specified by tl and bl, inclusive. Cleared cells are
|
||||||
// colored with the current style background color. This will clear all
|
// colored with the current style background color. This will clear all
|
||||||
// cells in the rows.
|
// cells in the rows.
|
||||||
@ -844,3 +861,71 @@ test "Screen clearRows active styled line" {
|
|||||||
defer alloc.free(str);
|
defer alloc.free(str);
|
||||||
try testing.expectEqualStrings("", 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
|
// Unsets pending wrap state
|
||||||
assert(!self.screen.cursor.pending_wrap);
|
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