mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-22 19:56:08 +03:00
terminal/new: eraseRows viewport behavior
This commit is contained in:
@ -5170,6 +5170,7 @@ test "Screen: promtpPath" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X - we don't use this in new terminal
|
||||||
test "Screen: scrollRegionUp single" {
|
test "Screen: scrollRegionUp single" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
@ -5187,6 +5188,7 @@ test "Screen: scrollRegionUp single" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X - we don't use this in new terminal
|
||||||
test "Screen: scrollRegionUp same line" {
|
test "Screen: scrollRegionUp same line" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
@ -5204,6 +5206,7 @@ test "Screen: scrollRegionUp same line" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X - we don't use this in new terminal
|
||||||
test "Screen: scrollRegionUp single with pen" {
|
test "Screen: scrollRegionUp single with pen" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
@ -5228,6 +5231,7 @@ test "Screen: scrollRegionUp single with pen" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X - we don't use this in new terminal
|
||||||
test "Screen: scrollRegionUp multiple" {
|
test "Screen: scrollRegionUp multiple" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
@ -5245,6 +5249,7 @@ test "Screen: scrollRegionUp multiple" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X - we don't use this in new terminal
|
||||||
test "Screen: scrollRegionUp multiple count" {
|
test "Screen: scrollRegionUp multiple count" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
@ -5262,6 +5267,7 @@ test "Screen: scrollRegionUp multiple count" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X - we don't use this in new terminal
|
||||||
test "Screen: scrollRegionUp count greater than available lines" {
|
test "Screen: scrollRegionUp count greater than available lines" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
@ -5278,6 +5284,7 @@ test "Screen: scrollRegionUp count greater than available lines" {
|
|||||||
try testing.expectEqualStrings("1ABCD\n\n\n4ABCD", contents);
|
try testing.expectEqualStrings("1ABCD\n\n\n4ABCD", contents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// X - we don't use this in new terminal
|
||||||
test "Screen: scrollRegionUp fills with pen" {
|
test "Screen: scrollRegionUp fills with pen" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
@ -5302,6 +5309,7 @@ test "Screen: scrollRegionUp fills with pen" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X - we don't use this in new terminal
|
||||||
test "Screen: scrollRegionUp buffer wrap" {
|
test "Screen: scrollRegionUp buffer wrap" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
@ -5334,6 +5342,7 @@ test "Screen: scrollRegionUp buffer wrap" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X - we don't use this in new terminal
|
||||||
test "Screen: scrollRegionUp buffer wrap alternate" {
|
test "Screen: scrollRegionUp buffer wrap alternate" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
@ -5366,6 +5375,7 @@ test "Screen: scrollRegionUp buffer wrap alternate" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// X - we don't use this in new terminal
|
||||||
test "Screen: scrollRegionUp buffer wrap alternative with extra lines" {
|
test "Screen: scrollRegionUp buffer wrap alternative with extra lines" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
@ -319,6 +319,34 @@ pub fn clonePool(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the viewport for the given offset, prefering to pin to
|
||||||
|
/// "active" if the offset is within the active area.
|
||||||
|
fn viewportForOffset(self: *const PageList, offset: RowOffset) Viewport {
|
||||||
|
// If the offset is on the active page, then we pin to active
|
||||||
|
// if our row idx is beyond the active row idx.
|
||||||
|
const active = self.getTopLeft(.active);
|
||||||
|
if (offset.page == active.page) {
|
||||||
|
if (offset.row_offset >= active.row_offset) {
|
||||||
|
return .{ .active = {} };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var page_ = active.page.next;
|
||||||
|
while (page_) |page| {
|
||||||
|
// This loop is pretty fast because the active area is
|
||||||
|
// never that large so this is at most one, two pages for
|
||||||
|
// reasonable terminals (including very large real world
|
||||||
|
// ones).
|
||||||
|
|
||||||
|
// A page forward in the active area is our page, so we're
|
||||||
|
// definitely in the active area.
|
||||||
|
if (page == offset.page) return .{ .active = {} };
|
||||||
|
page_ = page.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .exact = offset };
|
||||||
|
}
|
||||||
|
|
||||||
/// Scroll options.
|
/// Scroll options.
|
||||||
pub const Scroll = union(enum) {
|
pub const Scroll = union(enum) {
|
||||||
/// Scroll to the active area. This is also sometimes referred to as
|
/// Scroll to the active area. This is also sometimes referred to as
|
||||||
@ -343,7 +371,7 @@ pub fn scroll(self: *PageList, behavior: Scroll) void {
|
|||||||
switch (behavior) {
|
switch (behavior) {
|
||||||
.active => self.viewport = .{ .active = {} },
|
.active => self.viewport = .{ .active = {} },
|
||||||
.top => self.viewport = .{ .top = {} },
|
.top => self.viewport = .{ .top = {} },
|
||||||
.delta_row => |n| delta_row: {
|
.delta_row => |n| {
|
||||||
if (n == 0) return;
|
if (n == 0) return;
|
||||||
|
|
||||||
const top = self.getTopLeft(.viewport);
|
const top = self.getTopLeft(.viewport);
|
||||||
@ -362,25 +390,7 @@ pub fn scroll(self: *PageList, behavior: Scroll) void {
|
|||||||
// But in a terminal when you get to the bottom and back into the
|
// But in a terminal when you get to the bottom and back into the
|
||||||
// active area, you usually expect that the viewport will now
|
// active area, you usually expect that the viewport will now
|
||||||
// follow the active area.
|
// follow the active area.
|
||||||
const active = self.getTopLeft(.active);
|
self.viewport = self.viewportForOffset(offset);
|
||||||
if (offset.page == active.page) {
|
|
||||||
if (offset.row_offset >= active.row_offset) {
|
|
||||||
self.viewport = .{ .active = {} };
|
|
||||||
break :delta_row;
|
|
||||||
}
|
|
||||||
} else active: {
|
|
||||||
// Check forward pages too.
|
|
||||||
var page = active.page.next orelse break :active;
|
|
||||||
while (true) {
|
|
||||||
if (page == offset.page) {
|
|
||||||
self.viewport = .{ .active = {} };
|
|
||||||
break :delta_row;
|
|
||||||
}
|
|
||||||
page = page.next orelse break :active;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.viewport = .{ .exact = offset };
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -562,6 +572,23 @@ pub fn eraseRows(
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have an exact viewport, we need to adjust for active area.
|
||||||
|
switch (self.viewport) {
|
||||||
|
.active => {},
|
||||||
|
|
||||||
|
.exact => |offset| self.viewport = self.viewportForOffset(offset),
|
||||||
|
|
||||||
|
// For top, we move back to active if our erasing moved our
|
||||||
|
// top page into the active area.
|
||||||
|
.top => {
|
||||||
|
const vp = self.viewportForOffset(.{
|
||||||
|
.page = self.pages.first.?,
|
||||||
|
.row_offset = 0,
|
||||||
|
});
|
||||||
|
if (vp == .active) self.viewport = vp;
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Erase a single page, freeing all its resources. The page can be
|
/// Erase a single page, freeing all its resources. The page can be
|
||||||
@ -1479,7 +1506,7 @@ test "PageList erase" {
|
|||||||
try testing.expectEqual(s.rows, s.totalRows());
|
try testing.expectEqual(s.rows, s.totalRows());
|
||||||
}
|
}
|
||||||
|
|
||||||
test "PageList erase resets viewport if inside erased page" {
|
test "PageList erase resets viewport to active if moves within active" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
@ -1498,7 +1525,50 @@ test "PageList erase resets viewport if inside erased page" {
|
|||||||
|
|
||||||
// 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.eraseRows(.{ .history = .{} }, null);
|
s.eraseRows(.{ .history = .{} }, null);
|
||||||
|
try testing.expect(s.viewport == .active);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "PageList erase resets viewport if inside erased page but not active" {
|
||||||
|
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.?);
|
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 = .{} }, .{ .history = .{ .y = 2 } });
|
||||||
|
try testing.expect(s.viewport.exact.page == s.pages.first.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "PageList erase resets viewport to active if top is inside active" {
|
||||||
|
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(.{ .top = {} });
|
||||||
|
|
||||||
|
// Erase the entire history, we should be back to just our active set.
|
||||||
|
s.eraseRows(.{ .history = .{} }, null);
|
||||||
|
try testing.expect(s.viewport == .active);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "PageList erase active regrows automatically" {
|
test "PageList erase active regrows automatically" {
|
||||||
|
@ -1651,3 +1651,61 @@ test "Screen: clone one line active with extra space" {
|
|||||||
try testing.expectEqualStrings("1ABC", contents);
|
try testing.expectEqualStrings("1ABC", contents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Screen: clear history with no history" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 10, 3, 3);
|
||||||
|
defer s.deinit();
|
||||||
|
try s.testWriteString("4ABCD\n5EFGH\n6IJKL");
|
||||||
|
try testing.expect(s.pages.viewport == .active);
|
||||||
|
s.eraseRows(.{ .history = .{} }, null);
|
||||||
|
try testing.expect(s.pages.viewport == .active);
|
||||||
|
{
|
||||||
|
// Test our contents rotated
|
||||||
|
const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} });
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("4ABCD\n5EFGH\n6IJKL", contents);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Test our contents rotated
|
||||||
|
const contents = try s.dumpStringAlloc(alloc, .{ .screen = .{} });
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("4ABCD\n5EFGH\n6IJKL", contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Screen: clear history" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
var s = try init(alloc, 10, 3, 3);
|
||||||
|
defer s.deinit();
|
||||||
|
try s.testWriteString("1ABCD\n2EFGH\n3IJKL\n4ABCD\n5EFGH\n6IJKL");
|
||||||
|
try testing.expect(s.pages.viewport == .active);
|
||||||
|
|
||||||
|
// Scroll to top
|
||||||
|
s.scroll(.{ .top = {} });
|
||||||
|
{
|
||||||
|
// Test our contents rotated
|
||||||
|
const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} });
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("1ABCD\n2EFGH\n3IJKL", contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.eraseRows(.{ .history = .{} }, null);
|
||||||
|
try testing.expect(s.pages.viewport == .active);
|
||||||
|
{
|
||||||
|
// Test our contents rotated
|
||||||
|
const contents = try s.dumpStringAlloc(alloc, .{ .viewport = .{} });
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("4ABCD\n5EFGH\n6IJKL", contents);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Test our contents rotated
|
||||||
|
const contents = try s.dumpStringAlloc(alloc, .{ .screen = .{} });
|
||||||
|
defer alloc.free(contents);
|
||||||
|
try testing.expectEqualStrings("4ABCD\n5EFGH\n6IJKL", contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user