mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
terminal/new: eraseRows
This commit is contained in:
@ -488,21 +488,36 @@ pub const RowChunkIterator = struct {
|
|||||||
///
|
///
|
||||||
/// This is a more efficient way to iterate through the data in a region,
|
/// This is a more efficient way to iterate through the data in a region,
|
||||||
/// since you can do simple pointer math and so on.
|
/// since you can do simple pointer math and so on.
|
||||||
|
///
|
||||||
|
/// If bl_pt is non-null, iteration will stop at the bottom left point
|
||||||
|
/// (inclusive). If bl_pt is null, the entire region specified by the point
|
||||||
|
/// tag will be iterated over. tl_pt and bl_pt must be the same tag, and
|
||||||
|
/// bl_pt must be greater than or equal to tl_pt.
|
||||||
pub fn rowChunkIterator(
|
pub fn rowChunkIterator(
|
||||||
self: *const PageList,
|
self: *const PageList,
|
||||||
tl_pt: point.Point,
|
tl_pt: point.Point,
|
||||||
|
bl_pt: ?point.Point,
|
||||||
) RowChunkIterator {
|
) RowChunkIterator {
|
||||||
|
// TODO: bl_pt assertions
|
||||||
|
|
||||||
const tl = self.getTopLeft(tl_pt);
|
const tl = self.getTopLeft(tl_pt);
|
||||||
const limit: RowChunkIterator.Limit = switch (tl_pt) {
|
const limit: RowChunkIterator.Limit = limit: {
|
||||||
// These always go to the end of the screen.
|
if (bl_pt) |pt| {
|
||||||
.screen, .active => .{ .none = {} },
|
const bl = self.getTopLeft(pt);
|
||||||
|
break :limit .{ .row = bl.forward(pt.coord().y).? };
|
||||||
|
}
|
||||||
|
|
||||||
// Viewport always is rows long
|
break :limit switch (tl_pt) {
|
||||||
.viewport => .{ .count = self.rows },
|
// These always go to the end of the screen.
|
||||||
|
.screen, .active => .{ .none = {} },
|
||||||
|
|
||||||
// History goes to the top of the active area. This is more expensive
|
// Viewport always is rows long
|
||||||
// to calculate but also more rare of a thing to iterate over.
|
.viewport => .{ .count = self.rows },
|
||||||
.history => .{ .row = self.getTopLeft(.active) },
|
|
||||||
|
// History goes to the top of the active area. This is more expensive
|
||||||
|
// to calculate but also more rare of a thing to iterate over.
|
||||||
|
.history => .{ .row = self.getTopLeft(.active) },
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return .{ .row = tl.forward(tl_pt.coord().y), .limit = limit };
|
return .{ .row = tl.forward(tl_pt.coord().y), .limit = limit };
|
||||||
@ -1040,7 +1055,7 @@ test "PageList rowChunkIterator single page" {
|
|||||||
try testing.expect(s.pages.first.?.next == null);
|
try testing.expect(s.pages.first.?.next == null);
|
||||||
|
|
||||||
// Iterate the active area
|
// Iterate the active area
|
||||||
var it = s.rowChunkIterator(.{ .active = .{} });
|
var it = s.rowChunkIterator(.{ .active = .{} }, null);
|
||||||
{
|
{
|
||||||
const chunk = it.next().?;
|
const chunk = it.next().?;
|
||||||
try testing.expect(chunk.page == s.pages.first.?);
|
try testing.expect(chunk.page == s.pages.first.?);
|
||||||
@ -1068,7 +1083,7 @@ test "PageList rowChunkIterator two pages" {
|
|||||||
try testing.expect(try s.grow() != null);
|
try testing.expect(try s.grow() != null);
|
||||||
|
|
||||||
// Iterate the active area
|
// Iterate the active area
|
||||||
var it = s.rowChunkIterator(.{ .active = .{} });
|
var it = s.rowChunkIterator(.{ .active = .{} }, null);
|
||||||
{
|
{
|
||||||
const chunk = it.next().?;
|
const chunk = it.next().?;
|
||||||
try testing.expect(chunk.page == s.pages.first.?);
|
try testing.expect(chunk.page == s.pages.first.?);
|
||||||
@ -1102,7 +1117,7 @@ test "PageList rowChunkIterator history two pages" {
|
|||||||
try testing.expect(try s.grow() != null);
|
try testing.expect(try s.grow() != null);
|
||||||
|
|
||||||
// Iterate the active area
|
// Iterate the active area
|
||||||
var it = s.rowChunkIterator(.{ .history = .{} });
|
var it = s.rowChunkIterator(.{ .history = .{} }, null);
|
||||||
{
|
{
|
||||||
const active_tl = s.getTopLeft(.active);
|
const active_tl = s.getTopLeft(.active);
|
||||||
const chunk = it.next().?;
|
const chunk = it.next().?;
|
||||||
|
@ -277,10 +277,11 @@ pub fn scroll(self: *Screen, behavior: Scroll) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Erase the active area of the screen from y=0 to rows-1. The cells
|
// Erase the region specified by tl and bl, inclusive. Erased cells are
|
||||||
/// are blanked using the given blank cell.
|
// colored with the current style background color. This will erase all
|
||||||
pub fn eraseActive(self: *Screen) void {
|
// cells in the rows.
|
||||||
var it = self.pages.rowChunkIterator(.{ .active = .{} });
|
pub fn eraseRows(self: *Screen, tl: point.Point, bl: ?point.Point) void {
|
||||||
|
var it = self.pages.rowChunkIterator(tl, bl);
|
||||||
while (it.next()) |chunk| {
|
while (it.next()) |chunk| {
|
||||||
for (chunk.rows()) |*row| {
|
for (chunk.rows()) |*row| {
|
||||||
const cells_offset = row.cells;
|
const cells_offset = row.cells;
|
||||||
@ -345,6 +346,20 @@ pub fn eraseCells(
|
|||||||
@memset(cells, self.blankCell());
|
@memset(cells, self.blankCell());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Erase cells but only if they are not protected.
|
||||||
|
pub fn eraseUnprotectedCells(
|
||||||
|
self: *Screen,
|
||||||
|
page: *Page,
|
||||||
|
row: *Row,
|
||||||
|
cells: []Cell,
|
||||||
|
) void {
|
||||||
|
for (cells) |*cell| {
|
||||||
|
if (cell.protected) continue;
|
||||||
|
const cell_multi: [*]Cell = @ptrCast(cell);
|
||||||
|
self.eraseCells(page, row, cell_multi[0..1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the blank cell to use when doing terminal operations that
|
/// Returns the blank cell to use when doing terminal operations that
|
||||||
/// require preserving the bg color.
|
/// require preserving the bg color.
|
||||||
fn blankCell(self: *const Screen) Cell {
|
fn blankCell(self: *const Screen) Cell {
|
||||||
@ -743,7 +758,7 @@ test "Screen style reset with unset" {
|
|||||||
try testing.expectEqual(@as(usize, 0), page.styles.count(page.memory));
|
try testing.expectEqual(@as(usize, 0), page.styles.count(page.memory));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Screen eraseActive one line" {
|
test "Screen eraseRows active one line" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
@ -751,13 +766,13 @@ test "Screen eraseActive one line" {
|
|||||||
defer s.deinit();
|
defer s.deinit();
|
||||||
|
|
||||||
try s.testWriteString("hello, world");
|
try s.testWriteString("hello, world");
|
||||||
s.eraseActive();
|
s.eraseRows(.{ .active = .{} }, null);
|
||||||
const str = try s.dumpStringAlloc(alloc, .{ .screen = .{} });
|
const str = try s.dumpStringAlloc(alloc, .{ .screen = .{} });
|
||||||
defer alloc.free(str);
|
defer alloc.free(str);
|
||||||
try testing.expectEqualStrings("", str);
|
try testing.expectEqualStrings("", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Screen eraseActive multi line" {
|
test "Screen eraseRows active multi line" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
@ -765,13 +780,13 @@ test "Screen eraseActive multi line" {
|
|||||||
defer s.deinit();
|
defer s.deinit();
|
||||||
|
|
||||||
try s.testWriteString("hello\nworld");
|
try s.testWriteString("hello\nworld");
|
||||||
s.eraseActive();
|
s.eraseRows(.{ .active = .{} }, null);
|
||||||
const str = try s.dumpStringAlloc(alloc, .{ .screen = .{} });
|
const str = try s.dumpStringAlloc(alloc, .{ .screen = .{} });
|
||||||
defer alloc.free(str);
|
defer alloc.free(str);
|
||||||
try testing.expectEqualStrings("", str);
|
try testing.expectEqualStrings("", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Screen eraseActive styled line" {
|
test "Screen eraseRows active styled line" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
@ -786,7 +801,7 @@ test "Screen eraseActive styled line" {
|
|||||||
const page = s.cursor.page_offset.page.data;
|
const page = s.cursor.page_offset.page.data;
|
||||||
try testing.expectEqual(@as(usize, 1), page.styles.count(page.memory));
|
try testing.expectEqual(@as(usize, 1), page.styles.count(page.memory));
|
||||||
|
|
||||||
s.eraseActive();
|
s.eraseRows(.{ .active = .{} }, null);
|
||||||
|
|
||||||
// We should have none because active cleared it
|
// We should have none because active cleared it
|
||||||
try testing.expectEqual(@as(usize, 0), page.styles.count(page.memory));
|
try testing.expectEqual(@as(usize, 0), page.styles.count(page.memory));
|
||||||
|
Reference in New Issue
Block a user