mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 08:16:13 +03:00
terminal: rename scroll "delta/delta_no_grow" to screen/viewport
This commit is contained in:
@ -1469,13 +1469,15 @@ pub const Scroll = union(enum) {
|
|||||||
/// Scroll up (negative) or down (positive) some fixed amount.
|
/// Scroll up (negative) or down (positive) some fixed amount.
|
||||||
/// Scrolling direction (up/down) describes the direction the viewport
|
/// Scrolling direction (up/down) describes the direction the viewport
|
||||||
/// moves, not the direction text moves. This is the colloquial way that
|
/// moves, not the direction text moves. This is the colloquial way that
|
||||||
/// scrolling is described: "scroll the page down".
|
/// scrolling is described: "scroll the page down". This scrolls the
|
||||||
delta: isize,
|
/// screen (potentially in addition to the viewport) and may therefore
|
||||||
|
/// create more rows if necessary.
|
||||||
|
screen: isize,
|
||||||
|
|
||||||
/// Same as delta but scrolling down will not grow the scrollback.
|
/// This is the same as "screen" but only scrolls the viewport. The
|
||||||
/// Scrolling down at the bottom will do nothing (similar to how
|
/// delta will be clamped at the current size of the screen and will
|
||||||
/// delta at the top does nothing).
|
/// never create new scrollback.
|
||||||
delta_no_grow: isize,
|
viewport: isize,
|
||||||
|
|
||||||
/// Scroll so the given row is in view. If the row is in the viewport,
|
/// Scroll so the given row is in view. If the row is in the viewport,
|
||||||
/// this will change nothing. If the row is outside the viewport, the
|
/// this will change nothing. If the row is outside the viewport, the
|
||||||
@ -1498,8 +1500,8 @@ pub fn scroll(self: *Screen, behavior: Scroll) !void {
|
|||||||
.bottom => self.viewport = self.history,
|
.bottom => self.viewport = self.history,
|
||||||
|
|
||||||
// TODO: deltas greater than the entire scrollback
|
// TODO: deltas greater than the entire scrollback
|
||||||
.delta => |delta| try self.scrollDelta(delta, true),
|
.screen => |delta| try self.scrollDelta(delta, false),
|
||||||
.delta_no_grow => |delta| try self.scrollDelta(delta, false),
|
.viewport => |delta| try self.scrollDelta(delta, true),
|
||||||
|
|
||||||
// Scroll to a specific row
|
// Scroll to a specific row
|
||||||
.row => |idx| self.scrollRow(idx),
|
.row => |idx| self.scrollRow(idx),
|
||||||
@ -1518,7 +1520,7 @@ fn scrollRow(self: *Screen, idx: RowIndex) void {
|
|||||||
assert(screen_pt.inViewport(self));
|
assert(screen_pt.inViewport(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scrollDelta(self: *Screen, delta: isize, grow: bool) !void {
|
fn scrollDelta(self: *Screen, delta: isize, viewport_only: bool) !void {
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
@ -1532,9 +1534,8 @@ fn scrollDelta(self: *Screen, delta: isize, grow: bool) !void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're scrolling down and not growing, then we just
|
// If we're scrolling only the viewport, then we just add to the viewport.
|
||||||
// add to the viewport and clamp at the bottom.
|
if (viewport_only) {
|
||||||
if (!grow) {
|
|
||||||
self.viewport = @min(
|
self.viewport = @min(
|
||||||
self.history,
|
self.history,
|
||||||
self.viewport + @as(usize, @intCast(delta)),
|
self.viewport + @as(usize, @intCast(delta)),
|
||||||
@ -1982,7 +1983,7 @@ pub fn resizeWithoutReflow(self: *Screen, rows: usize, cols: usize) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
y -= 1;
|
y -= 1;
|
||||||
try self.scroll(.{ .delta = 1 });
|
try self.scroll(.{ .screen = 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get this row
|
// Get this row
|
||||||
@ -2065,7 +2066,7 @@ pub fn resize(self: *Screen, rows: usize, cols: usize) !void {
|
|||||||
while (iter.next()) |old_row| {
|
while (iter.next()) |old_row| {
|
||||||
// If we're past the end, scroll
|
// If we're past the end, scroll
|
||||||
if (y >= self.rows) {
|
if (y >= self.rows) {
|
||||||
try self.scroll(.{ .delta = 1 });
|
try self.scroll(.{ .screen = 1 });
|
||||||
y -= 1;
|
y -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2170,7 +2171,7 @@ pub fn resize(self: *Screen, rows: usize, cols: usize) !void {
|
|||||||
// If we're past the end, scroll
|
// If we're past the end, scroll
|
||||||
if (y >= self.rows) {
|
if (y >= self.rows) {
|
||||||
y -= 1;
|
y -= 1;
|
||||||
try self.scroll(.{ .delta = 1 });
|
try self.scroll(.{ .screen = 1 });
|
||||||
}
|
}
|
||||||
new_row = self.getRow(.{ .active = y });
|
new_row = self.getRow(.{ .active = y });
|
||||||
new_row.setSemanticPrompt(old_row.getSemanticPrompt());
|
new_row.setSemanticPrompt(old_row.getSemanticPrompt());
|
||||||
@ -2244,7 +2245,7 @@ pub fn resize(self: *Screen, rows: usize, cols: usize) !void {
|
|||||||
|
|
||||||
// If our y is more than our rows, we need to scroll
|
// If our y is more than our rows, we need to scroll
|
||||||
if (y >= self.rows) {
|
if (y >= self.rows) {
|
||||||
try self.scroll(.{ .delta = 1 });
|
try self.scroll(.{ .screen = 1 });
|
||||||
y -= 1;
|
y -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2290,7 +2291,7 @@ pub fn resize(self: *Screen, rows: usize, cols: usize) !void {
|
|||||||
// Wrapping can cause us to overflow our visible area.
|
// Wrapping can cause us to overflow our visible area.
|
||||||
// If so, scroll.
|
// If so, scroll.
|
||||||
if (y >= self.rows) {
|
if (y >= self.rows) {
|
||||||
try self.scroll(.{ .delta = 1 });
|
try self.scroll(.{ .screen = 1 });
|
||||||
y -= 1;
|
y -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2417,7 +2418,7 @@ pub fn testWriteString(self: *Screen, text: []const u8) !void {
|
|||||||
// If we're writing past the end of the active area, scroll.
|
// If we're writing past the end of the active area, scroll.
|
||||||
if (y >= self.rows) {
|
if (y >= self.rows) {
|
||||||
y -= 1;
|
y -= 1;
|
||||||
try self.scroll(.{ .delta = 1 });
|
try self.scroll(.{ .screen = 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get our row
|
// Get our row
|
||||||
@ -2474,7 +2475,7 @@ pub fn testWriteString(self: *Screen, text: []const u8) !void {
|
|||||||
x = 0;
|
x = 0;
|
||||||
if (y >= self.rows) {
|
if (y >= self.rows) {
|
||||||
y -= 1;
|
y -= 1;
|
||||||
try self.scroll(.{ .delta = 1 });
|
try self.scroll(.{ .screen = 1 });
|
||||||
}
|
}
|
||||||
row = self.getRow(.{ .active = y });
|
row = self.getRow(.{ .active = y });
|
||||||
}
|
}
|
||||||
@ -2502,7 +2503,7 @@ pub fn testWriteString(self: *Screen, text: []const u8) !void {
|
|||||||
x = 0;
|
x = 0;
|
||||||
if (y >= self.rows) {
|
if (y >= self.rows) {
|
||||||
y -= 1;
|
y -= 1;
|
||||||
try self.scroll(.{ .delta = 1 });
|
try self.scroll(.{ .screen = 1 });
|
||||||
}
|
}
|
||||||
row = self.getRow(.{ .active = y });
|
row = self.getRow(.{ .active = y });
|
||||||
}
|
}
|
||||||
@ -2796,7 +2797,7 @@ test "Screen: scrolling" {
|
|||||||
try testing.expect(s.viewportIsBottom());
|
try testing.expect(s.viewportIsBottom());
|
||||||
|
|
||||||
// Scroll down, should still be bottom
|
// Scroll down, should still be bottom
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
try testing.expect(s.viewportIsBottom());
|
try testing.expect(s.viewportIsBottom());
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -2826,7 +2827,7 @@ test "Screen: scroll down from 0" {
|
|||||||
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
||||||
|
|
||||||
// Scrolling up does nothing, but allows it
|
// Scrolling up does nothing, but allows it
|
||||||
try s.scroll(.{ .delta = -1 });
|
try s.scroll(.{ .screen = -1 });
|
||||||
try testing.expect(s.viewportIsBottom());
|
try testing.expect(s.viewportIsBottom());
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -2844,7 +2845,7 @@ test "Screen: scrollback" {
|
|||||||
var s = try init(alloc, 3, 5, 1);
|
var s = try init(alloc, 3, 5, 1);
|
||||||
defer s.deinit();
|
defer s.deinit();
|
||||||
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
|
|
||||||
{
|
{
|
||||||
// Test our contents rotated
|
// Test our contents rotated
|
||||||
@ -2865,7 +2866,7 @@ test "Screen: scrollback" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrolling back should make it visible again
|
// Scrolling back should make it visible again
|
||||||
try s.scroll(.{ .delta = -1 });
|
try s.scroll(.{ .screen = -1 });
|
||||||
try testing.expect(!s.viewportIsBottom());
|
try testing.expect(!s.viewportIsBottom());
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -2876,7 +2877,7 @@ test "Screen: scrollback" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrolling back again should do nothing
|
// Scrolling back again should do nothing
|
||||||
try s.scroll(.{ .delta = -1 });
|
try s.scroll(.{ .screen = -1 });
|
||||||
|
|
||||||
{
|
{
|
||||||
// Test our contents rotated
|
// Test our contents rotated
|
||||||
@ -2896,7 +2897,7 @@ test "Screen: scrollback" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrolling forward with no grow should do nothing
|
// Scrolling forward with no grow should do nothing
|
||||||
try s.scroll(.{ .delta_no_grow = 1 });
|
try s.scroll(.{ .viewport = 1 });
|
||||||
|
|
||||||
{
|
{
|
||||||
// Test our contents rotated
|
// Test our contents rotated
|
||||||
@ -2954,7 +2955,7 @@ test "Screen: scrollback with large delta" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scroll down a ton
|
// Scroll down a ton
|
||||||
try s.scroll(.{ .delta_no_grow = 5 });
|
try s.scroll(.{ .viewport = 5 });
|
||||||
try testing.expect(s.viewportIsBottom());
|
try testing.expect(s.viewportIsBottom());
|
||||||
{
|
{
|
||||||
// Test our contents rotated
|
// Test our contents rotated
|
||||||
@ -2971,7 +2972,7 @@ test "Screen: scrollback empty" {
|
|||||||
var s = try init(alloc, 3, 5, 50);
|
var s = try init(alloc, 3, 5, 50);
|
||||||
defer s.deinit();
|
defer s.deinit();
|
||||||
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
||||||
try s.scroll(.{ .delta_no_grow = 1 });
|
try s.scroll(.{ .viewport = 1 });
|
||||||
|
|
||||||
{
|
{
|
||||||
// Test our contents
|
// Test our contents
|
||||||
@ -2990,7 +2991,7 @@ test "Screen: scrollback doesn't move viewport if not at bottom" {
|
|||||||
try s.testWriteString("1ABCD\n2EFGH\n3IJKL\n4ABCD\n5EFGH");
|
try s.testWriteString("1ABCD\n2EFGH\n3IJKL\n4ABCD\n5EFGH");
|
||||||
|
|
||||||
// First test: we scroll up by 1, so we're not at the bottom anymore.
|
// First test: we scroll up by 1, so we're not at the bottom anymore.
|
||||||
try s.scroll(.{ .delta = -1 });
|
try s.scroll(.{ .screen = -1 });
|
||||||
try testing.expect(!s.viewportIsBottom());
|
try testing.expect(!s.viewportIsBottom());
|
||||||
{
|
{
|
||||||
var contents = try s.testString(alloc, .viewport);
|
var contents = try s.testString(alloc, .viewport);
|
||||||
@ -3000,7 +3001,7 @@ test "Screen: scrollback doesn't move viewport if not at bottom" {
|
|||||||
|
|
||||||
// Next, we scroll back down by 1, this grows the scrollback but we
|
// Next, we scroll back down by 1, this grows the scrollback but we
|
||||||
// shouldn't move.
|
// shouldn't move.
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
try testing.expect(!s.viewportIsBottom());
|
try testing.expect(!s.viewportIsBottom());
|
||||||
{
|
{
|
||||||
var contents = try s.testString(alloc, .viewport);
|
var contents = try s.testString(alloc, .viewport);
|
||||||
@ -3010,7 +3011,7 @@ test "Screen: scrollback doesn't move viewport if not at bottom" {
|
|||||||
|
|
||||||
// Scroll again, this clears scrollback so we should move viewports
|
// Scroll again, this clears scrollback so we should move viewports
|
||||||
// but still see the same thing since our original view fits.
|
// but still see the same thing since our original view fits.
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
try testing.expect(!s.viewportIsBottom());
|
try testing.expect(!s.viewportIsBottom());
|
||||||
{
|
{
|
||||||
var contents = try s.testString(alloc, .viewport);
|
var contents = try s.testString(alloc, .viewport);
|
||||||
@ -3020,7 +3021,7 @@ test "Screen: scrollback doesn't move viewport if not at bottom" {
|
|||||||
|
|
||||||
// Scroll again, this again goes into scrollback but is now deleting
|
// Scroll again, this again goes into scrollback but is now deleting
|
||||||
// what we were looking at. We should see changes.
|
// what we were looking at. We should see changes.
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
try testing.expect(!s.viewportIsBottom());
|
try testing.expect(!s.viewportIsBottom());
|
||||||
{
|
{
|
||||||
var contents = try s.testString(alloc, .viewport);
|
var contents = try s.testString(alloc, .viewport);
|
||||||
@ -3045,7 +3046,7 @@ test "Screen: scrolling moves selection" {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Scroll down, should still be bottom
|
// Scroll down, should still be bottom
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
try testing.expect(s.viewportIsBottom());
|
try testing.expect(s.viewportIsBottom());
|
||||||
|
|
||||||
// Our selection should've moved up
|
// Our selection should've moved up
|
||||||
@ -3078,7 +3079,7 @@ test "Screen: scrolling moves selection" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scroll up again
|
// Scroll up again
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
|
|
||||||
// Our selection should be null because it left the screen.
|
// Our selection should be null because it left the screen.
|
||||||
try testing.expect(s.selection == null);
|
try testing.expect(s.selection == null);
|
||||||
@ -3100,7 +3101,7 @@ test "Screen: scrolling with scrollback available doesn't move selection" {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Scroll down, should still be bottom
|
// Scroll down, should still be bottom
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
try testing.expect(s.viewportIsBottom());
|
try testing.expect(s.viewportIsBottom());
|
||||||
|
|
||||||
// Our selection should NOT move since we have scrollback
|
// Our selection should NOT move since we have scrollback
|
||||||
@ -3117,7 +3118,7 @@ test "Screen: scrolling with scrollback available doesn't move selection" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scrolling back should make it visible again
|
// Scrolling back should make it visible again
|
||||||
try s.scroll(.{ .delta = -1 });
|
try s.scroll(.{ .screen = -1 });
|
||||||
try testing.expect(!s.viewportIsBottom());
|
try testing.expect(!s.viewportIsBottom());
|
||||||
|
|
||||||
// Our selection should NOT move since we have scrollback
|
// Our selection should NOT move since we have scrollback
|
||||||
@ -3134,7 +3135,7 @@ test "Screen: scrolling with scrollback available doesn't move selection" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scroll down, this sends us off the scrollback
|
// Scroll down, this sends us off the scrollback
|
||||||
try s.scroll(.{ .delta = 2 });
|
try s.scroll(.{ .screen = 2 });
|
||||||
|
|
||||||
// Selection should be gone since we selected a line that went off.
|
// Selection should be gone since we selected a line that went off.
|
||||||
try testing.expect(s.selection == null);
|
try testing.expect(s.selection == null);
|
||||||
@ -3210,7 +3211,7 @@ test "Screen: row copy" {
|
|||||||
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
||||||
|
|
||||||
// Copy
|
// Copy
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
try s.copyRow(.{ .active = 2 }, .{ .active = 0 });
|
try s.copyRow(.{ .active = 2 }, .{ .active = 0 });
|
||||||
|
|
||||||
// Test our contents
|
// Test our contents
|
||||||
@ -3761,7 +3762,7 @@ test "Screen: scrollRegionUp buffer wrap" {
|
|||||||
|
|
||||||
// Scroll down, should still be bottom, but should wrap because
|
// Scroll down, should still be bottom, but should wrap because
|
||||||
// we're out of space.
|
// we're out of space.
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
s.cursor.x = 0;
|
s.cursor.x = 0;
|
||||||
try s.testWriteString("1ABCD\n2EFGH\n3IJKL\n4ABCD");
|
try s.testWriteString("1ABCD\n2EFGH\n3IJKL\n4ABCD");
|
||||||
|
|
||||||
@ -3787,7 +3788,7 @@ test "Screen: scrollRegionUp buffer wrap alternate" {
|
|||||||
|
|
||||||
// Scroll down, should still be bottom, but should wrap because
|
// Scroll down, should still be bottom, but should wrap because
|
||||||
// we're out of space.
|
// we're out of space.
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
s.cursor.x = 0;
|
s.cursor.x = 0;
|
||||||
try s.testWriteString("1ABCD\n2EFGH\n3IJKL\n4ABCD");
|
try s.testWriteString("1ABCD\n2EFGH\n3IJKL\n4ABCD");
|
||||||
|
|
||||||
@ -4025,7 +4026,7 @@ test "Screen: selectionString wrap around" {
|
|||||||
|
|
||||||
// Scroll down, should still be bottom, but should wrap because
|
// Scroll down, should still be bottom, but should wrap because
|
||||||
// we're out of space.
|
// we're out of space.
|
||||||
try s.scroll(.{ .delta = 1 });
|
try s.scroll(.{ .screen = 1 });
|
||||||
try testing.expect(s.viewportIsBottom());
|
try testing.expect(s.viewportIsBottom());
|
||||||
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
try s.testWriteString("1ABCD\n2EFGH\n3IJKL");
|
||||||
|
|
||||||
|
@ -883,7 +883,7 @@ pub fn index(self: *Terminal) !void {
|
|||||||
if (self.scrolling_region.top == 0 and
|
if (self.scrolling_region.top == 0 and
|
||||||
self.scrolling_region.bottom == self.rows - 1)
|
self.scrolling_region.bottom == self.rows - 1)
|
||||||
{
|
{
|
||||||
try self.screen.scroll(.{ .delta = 1 });
|
try self.screen.scroll(.{ .screen = 1 });
|
||||||
} else {
|
} else {
|
||||||
self.screen.scrollRegionUp(
|
self.screen.scrollRegionUp(
|
||||||
.{ .active = self.scrolling_region.top },
|
.{ .active = self.scrolling_region.top },
|
||||||
@ -1465,7 +1465,7 @@ pub fn scrollViewport(self: *Terminal, behavior: ScrollViewport) !void {
|
|||||||
try self.screen.scroll(switch (behavior) {
|
try self.screen.scroll(switch (behavior) {
|
||||||
.top => .{ .top = {} },
|
.top => .{ .top = {} },
|
||||||
.bottom => .{ .bottom = {} },
|
.bottom => .{ .bottom = {} },
|
||||||
.delta => |delta| .{ .delta_no_grow = delta },
|
.delta => |delta| .{ .viewport = delta },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,14 +41,14 @@ pub const Viewport = struct {
|
|||||||
defer s.deinit();
|
defer s.deinit();
|
||||||
|
|
||||||
// At the bottom
|
// At the bottom
|
||||||
try s.scroll(.{ .delta = 6 });
|
try s.scroll(.{ .screen = 6 });
|
||||||
try testing.expectEqual(ScreenPoint{
|
try testing.expectEqual(ScreenPoint{
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 3,
|
.y = 3,
|
||||||
}, (Viewport{ .x = 0, .y = 0 }).toScreen(&s));
|
}, (Viewport{ .x = 0, .y = 0 }).toScreen(&s));
|
||||||
|
|
||||||
// Move the viewport a bit up
|
// Move the viewport a bit up
|
||||||
try s.scroll(.{ .delta = -1 });
|
try s.scroll(.{ .screen = -1 });
|
||||||
try testing.expectEqual(ScreenPoint{
|
try testing.expectEqual(ScreenPoint{
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 2,
|
.y = 2,
|
||||||
|
Reference in New Issue
Block a user