mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
terminal/new: scroll clear
This commit is contained in:
@ -254,6 +254,36 @@ pub fn scroll(self: *PageList, behavior: Scroll) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clear the screen by scrolling written contents up into the scrollback.
|
||||||
|
/// This will not update the viewport.
|
||||||
|
pub fn scrollClear(self: *PageList) !void {
|
||||||
|
// Go through the active area backwards to find the first non-empty
|
||||||
|
// row. We use this to determine how many rows to scroll up.
|
||||||
|
const non_empty: usize = non_empty: {
|
||||||
|
var page = self.pages.last.?;
|
||||||
|
var n: usize = 0;
|
||||||
|
while (true) {
|
||||||
|
const rows: [*]Row = page.data.rows.ptr(page.data.memory);
|
||||||
|
for (0..page.data.size.rows) |i| {
|
||||||
|
const rev_i = page.data.size.rows - i - 1;
|
||||||
|
const row = rows[rev_i];
|
||||||
|
const cells = row.cells.ptr(page.data.memory)[0..self.cols];
|
||||||
|
for (cells) |cell| {
|
||||||
|
if (!cell.isEmpty()) break :non_empty self.rows - n;
|
||||||
|
}
|
||||||
|
|
||||||
|
n += 1;
|
||||||
|
if (n > self.rows) break :non_empty 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
page = page.prev orelse break :non_empty 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Scroll
|
||||||
|
for (0..non_empty) |_| _ = try self.grow();
|
||||||
|
}
|
||||||
|
|
||||||
/// Grow the active area by exactly one row.
|
/// Grow the active area by exactly one row.
|
||||||
///
|
///
|
||||||
/// This may allocate, but also may not if our current page has more
|
/// This may allocate, but also may not if our current page has more
|
||||||
@ -958,6 +988,39 @@ test "PageList scroll delta row forward into active" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "PageList scroll clear" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 80, 24, null);
|
||||||
|
defer s.deinit();
|
||||||
|
|
||||||
|
{
|
||||||
|
const cell = s.getCell(.{ .active = .{ .x = 0, .y = 0 } }).?;
|
||||||
|
cell.cell.* = .{
|
||||||
|
.content_tag = .codepoint,
|
||||||
|
.content = .{ .codepoint = 'A' },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const cell = s.getCell(.{ .active = .{ .x = 0, .y = 1 } }).?;
|
||||||
|
cell.cell.* = .{
|
||||||
|
.content_tag = .codepoint,
|
||||||
|
.content = .{ .codepoint = 'A' },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try s.scrollClear();
|
||||||
|
|
||||||
|
{
|
||||||
|
const pt = s.getCell(.{ .viewport = .{} }).?.screenPoint();
|
||||||
|
try testing.expectEqual(point.Point{ .screen = .{
|
||||||
|
.x = 0,
|
||||||
|
.y = 2,
|
||||||
|
} }, pt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "PageList grow fit in capacity" {
|
test "PageList grow fit in capacity" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
@ -277,6 +277,13 @@ pub fn scroll(self: *Screen, behavior: Scroll) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// See PageList.scrollClear. In addition to that, we reset the cursor
|
||||||
|
/// to be on top.
|
||||||
|
pub fn scrollClear(self: *Screen) !void {
|
||||||
|
try self.pages.scrollClear();
|
||||||
|
self.cursorAbsolute(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Erase the region specified by tl and bl, inclusive. Erased cells are
|
// Erase the region specified by tl and bl, inclusive. Erased cells are
|
||||||
// colored with the current style background color. This will erase all
|
// colored with the current style background color. This will erase all
|
||||||
// cells in the rows.
|
// cells in the rows.
|
||||||
|
@ -1614,19 +1614,20 @@ pub fn eraseDisplay(
|
|||||||
const protected = self.screen.protected_mode == .iso or protected_req;
|
const protected = self.screen.protected_mode == .iso or protected_req;
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
// .scroll_complete => {
|
.scroll_complete => {
|
||||||
// self.screen.scroll(.{ .clear = {} }) catch |err| {
|
self.screen.scrollClear() catch |err| {
|
||||||
// log.warn("scroll clear failed, doing a normal clear err={}", .{err});
|
log.warn("scroll clear failed, doing a normal clear err={}", .{err});
|
||||||
// self.eraseDisplay(alloc, .complete, protected_req);
|
self.eraseDisplay(.complete, protected_req);
|
||||||
// return;
|
return;
|
||||||
// };
|
};
|
||||||
//
|
|
||||||
// // Unsets pending wrap state
|
// Unsets pending wrap state
|
||||||
// self.screen.cursor.pending_wrap = false;
|
self.screen.cursor.pending_wrap = false;
|
||||||
//
|
|
||||||
// // Clear all Kitty graphics state for this screen
|
// Clear all Kitty graphics state for this screen
|
||||||
// self.screen.kitty_images.delete(alloc, self, .{ .all = true });
|
// TODO
|
||||||
// },
|
// self.screen.kitty_images.delete(alloc, self, .{ .all = true });
|
||||||
|
},
|
||||||
|
|
||||||
.complete => {
|
.complete => {
|
||||||
// If we're on the primary screen and our last non-empty row is
|
// If we're on the primary screen and our last non-empty row is
|
||||||
@ -7001,22 +7002,22 @@ test "Terminal: eraseDisplay protected below" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// test "Terminal: eraseDisplay scroll complete" {
|
test "Terminal: eraseDisplay scroll complete" {
|
||||||
// const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
// var t = try init(alloc, 10, 5);
|
var t = try init(alloc, 10, 5);
|
||||||
// defer t.deinit(alloc);
|
defer t.deinit(alloc);
|
||||||
//
|
|
||||||
// try t.print('A');
|
try t.print('A');
|
||||||
// t.carriageReturn();
|
t.carriageReturn();
|
||||||
// try t.linefeed();
|
try t.linefeed();
|
||||||
// t.eraseDisplay(.scroll_complete, false);
|
t.eraseDisplay(.scroll_complete, false);
|
||||||
//
|
|
||||||
// {
|
{
|
||||||
// const str = try t.plainString(testing.allocator);
|
const str = try t.plainString(testing.allocator);
|
||||||
// defer testing.allocator.free(str);
|
defer testing.allocator.free(str);
|
||||||
// try testing.expectEqualStrings("", str);
|
try testing.expectEqualStrings("", str);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
test "Terminal: eraseDisplay protected above" {
|
test "Terminal: eraseDisplay protected above" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
@ -599,6 +599,19 @@ pub const Cell = packed struct(u64) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the cell has no text or styling.
|
||||||
|
pub fn isEmpty(self: Cell) bool {
|
||||||
|
return switch (self.content_tag) {
|
||||||
|
.codepoint,
|
||||||
|
.codepoint_grapheme,
|
||||||
|
=> !self.hasText(),
|
||||||
|
|
||||||
|
.bg_color_palette,
|
||||||
|
.bg_color_rgb,
|
||||||
|
=> false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn hasGrapheme(self: Cell) bool {
|
pub fn hasGrapheme(self: Cell) bool {
|
||||||
return self.content_tag == .codepoint_grapheme;
|
return self.content_tag == .codepoint_grapheme;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user