mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
terminal: add "clear" screen scroll mode
This commit is contained in:
@ -1788,6 +1788,15 @@ pub const Scroll = union(enum) {
|
|||||||
/// this will change nothing. If the row is outside the viewport, the
|
/// this will change nothing. If the row is outside the viewport, the
|
||||||
/// viewport will change so that this row is at the top of the viewport.
|
/// viewport will change so that this row is at the top of the viewport.
|
||||||
row: RowIndex,
|
row: RowIndex,
|
||||||
|
|
||||||
|
/// Scroll down and move all viewport contents into the scrollback
|
||||||
|
/// so that the screen is clear. This isn't eqiuivalent to "screen" with
|
||||||
|
/// the value set to the viewport size because this will handle the case
|
||||||
|
/// that the viewport is not full.
|
||||||
|
///
|
||||||
|
/// This will ignore empty trailing rows. An empty row is a row that
|
||||||
|
/// has never been written to at all. A row with spaces is not empty.
|
||||||
|
clear: void,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Scroll the screen by the given behavior. Note that this will always
|
/// Scroll the screen by the given behavior. Note that this will always
|
||||||
@ -1815,9 +1824,27 @@ pub fn scroll(self: *Screen, behavior: Scroll) Allocator.Error!void {
|
|||||||
|
|
||||||
// Scroll to a specific row
|
// Scroll to a specific row
|
||||||
.row => |idx| self.scrollRow(idx),
|
.row => |idx| self.scrollRow(idx),
|
||||||
|
|
||||||
|
// Scroll until the viewport is clear by moving the viewport contents
|
||||||
|
// into the scrollback.
|
||||||
|
.clear => try self.scrollClear(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn scrollClear(self: *Screen) Allocator.Error!void {
|
||||||
|
// The full amount of rows in the viewport
|
||||||
|
const full_amount = self.rowsWritten() - self.viewport;
|
||||||
|
|
||||||
|
// Find the number of non-empty rows
|
||||||
|
const non_empty = for (0..full_amount) |i| {
|
||||||
|
const rev_i = full_amount - i - 1;
|
||||||
|
const row = self.getRow(.{ .viewport = rev_i });
|
||||||
|
if (!row.isEmpty()) break rev_i + 1;
|
||||||
|
} else full_amount;
|
||||||
|
|
||||||
|
try self.scroll(.{ .screen = @intCast(non_empty) });
|
||||||
|
}
|
||||||
|
|
||||||
fn scrollRow(self: *Screen, idx: RowIndex) void {
|
fn scrollRow(self: *Screen, idx: RowIndex) void {
|
||||||
// Convert the given row to a screen point.
|
// Convert the given row to a screen point.
|
||||||
const screen_idx = idx.toScreen(self);
|
const screen_idx = idx.toScreen(self);
|
||||||
@ -3691,6 +3718,109 @@ test "Screen: scrolling with scrollback available doesn't move selection" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Screen: scroll and clear full screen" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 3, 5, 5);
|
||||||
|
defer s.deinit();
|
||||||
|
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
||||||
|
|
||||||
|
{
|
||||||
|
const contents = try s.testString(alloc, .viewport);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("1ABCD\n2EFGH\n3IJKL", contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
try s.scroll(.{ .clear = {} });
|
||||||
|
{
|
||||||
|
const contents = try s.testString(alloc, .viewport);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("", contents);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const contents = try s.testString(alloc, .screen);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("1ABCD\n2EFGH\n3IJKL", contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Screen: scroll and clear partial screen" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 3, 5, 5);
|
||||||
|
defer s.deinit();
|
||||||
|
try s.testWriteString("1ABCD\n2EFGH");
|
||||||
|
|
||||||
|
{
|
||||||
|
const contents = try s.testString(alloc, .viewport);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("1ABCD\n2EFGH", contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
try s.scroll(.{ .clear = {} });
|
||||||
|
{
|
||||||
|
const contents = try s.testString(alloc, .viewport);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("", contents);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const contents = try s.testString(alloc, .screen);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("1ABCD\n2EFGH", contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Screen: scroll and clear empty screen" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 3, 5, 5);
|
||||||
|
defer s.deinit();
|
||||||
|
try s.scroll(.{ .clear = {} });
|
||||||
|
try testing.expectEqual(@as(usize, 0), s.viewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Screen: scroll and clear ignore blank lines" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 3, 5, 10);
|
||||||
|
defer s.deinit();
|
||||||
|
try s.testWriteString("1ABCD\n2EFGH");
|
||||||
|
try s.scroll(.{ .clear = {} });
|
||||||
|
{
|
||||||
|
const contents = try s.testString(alloc, .viewport);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("", contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move back to top-left
|
||||||
|
s.cursor.x = 0;
|
||||||
|
s.cursor.y = 0;
|
||||||
|
|
||||||
|
// Write and clear
|
||||||
|
try s.testWriteString("3ABCD\n");
|
||||||
|
try s.scroll(.{ .clear = {} });
|
||||||
|
{
|
||||||
|
const contents = try s.testString(alloc, .viewport);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("", contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move back to top-left
|
||||||
|
s.cursor.x = 0;
|
||||||
|
s.cursor.y = 0;
|
||||||
|
try s.testWriteString("X");
|
||||||
|
|
||||||
|
{
|
||||||
|
const contents = try s.testString(alloc, .screen);
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("1ABCD\n2EFGH\n3ABCD\nX", contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "Screen: history region with no scrollback" {
|
test "Screen: history region with no scrollback" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
Reference in New Issue
Block a user