Introduce scrollback-limit-lines to limit scrollback by lines instead of bytes (#13473)

This adds a new config `scrollback-limit-lines` to limit scrollback by
lines instead of bytes. This also renames `scrollback-limit` to
`scrollback-limit-bytes` to make it clear what it does but we have a
compatibility entry so old configurations will continue to work, so its
not breaking.

**This is NOT exclusive to `scrollback-limit-bytes`**. When both are
set, then the _first limit reached_ is used. Since lines is affected by
viewport size and bytes are affected by entries (more styles, more
graphemes, etc.), they serve somewhat different purposes and it might be
useful to set both.

The default remains 50MB of bytes, unlimited lines.

This is not exposed to libghostty yet. I have that coming as a follow up
change.
This commit is contained in:
Mitchell Hashimoto
2026-07-27 05:57:27 -07:00
committed by GitHub
17 changed files with 1283 additions and 652 deletions

View File

@@ -138,7 +138,7 @@ pub fn create(
.terminal = try .init(global.io(), alloc, .{
.rows = opts.@"terminal-rows",
.cols = opts.@"terminal-cols",
.max_scrollback = opts.@"max-scrollback",
.max_scrollback_bytes = opts.@"max-scrollback",
}),
};
return ptr;

View File

@@ -41,6 +41,7 @@ const ClipboardCodepointMap = @import("ClipboardCodepointMap.zig");
const KeyRemapSet = @import("../input/key_mods.zig").RemapSet;
pub const WindowPaddingBalance = @import("../renderer/size.zig").PaddingBalance;
const string = @import("string.zig");
const Limit = @import("limit.zig").Limit;
// We do this instead of importing all of terminal/main.zig to
// limit the dependency graph. This is important because some things
@@ -95,6 +96,10 @@ pub const compatibility = std.StaticStringMap(
// Ghostty 1.3 rename the "window" option to "new-window".
// See: https://github.com/ghostty-org/ghostty/pull/9764
.{ "macos-dock-drop-behavior", compatMacOSDockDropBehavior },
// Ghostty 1.4 renamed `scrollback-limit` to `scrollback-limit-bytes`
// when `scrollback-limit-lines` was added so the units are explicit.
.{ "scrollback-limit", cli.compatibilityRenamed(Config, "scrollback-limit-bytes") },
});
/// Set Ghostty's graphical user interface language to a language other than the
@@ -1375,11 +1380,32 @@ input: RepeatableReadableIO = .{},
///
/// This size is per terminal surface, not for the entire application.
///
/// It is not currently possible to set an unlimited scrollback buffer.
/// This is a future planned feature.
/// A separate maximum can be set with `scrollback-limit-lines`; if both limits
/// are set, then the first one reached will determine when scrollback is
/// removed.
///
/// The default is 50 MB. Set this to `unlimited` to remove the byte limit.
///
/// This can be changed at runtime but will only affect new terminal surfaces.
@"scrollback-limit": usize = 50_000_000, // 50MB
@"scrollback-limit-bytes": Limit(usize, 50_000_000) = .default,
/// The maximum number of lines of scrollback to retain. This excludes
/// the active screen. Soft-wrapped lines count as multiple lines.
///
/// This limit is an estimate. Internally, Ghostty will only trim lines
/// up to the minimum allocation unit that is used internally (called a
/// "page"). The size of a page depends on how many styles, graphemes, etc.
/// take up the screen. In practice, this can be anywhere from a handful to
/// a couple hundred lines. Importantly, memory is capped either way.
/// This means that the actual limited lines will likely be slightly
/// higher in practice.
///
/// The default is `unlimited`. A separate maximum can be set with
/// `scrollback-limit-bytes`; if both limits are set, then the first one reached
/// will determine when scrollback is removed.
///
/// This can be changed at runtime but will only affect new terminal surfaces.
@"scrollback-limit-lines": Limit(usize, std.math.maxInt(usize)) = .default,
/// Whether to compress scrollback pages while the terminal is idle.
///
@@ -10825,6 +10851,94 @@ test "theme specifying light/dark sets theme usage in conditional state" {
}
}
test "scrollback limits" {
const testing = std.testing;
const alloc = testing.allocator;
var cfg = try Config.default(alloc);
defer cfg.deinit();
try testing.expectEqual(
@as(usize, 50_000_000),
cfg.@"scrollback-limit-bytes".value,
);
try testing.expectEqual(
std.math.maxInt(usize),
cfg.@"scrollback-limit-lines".value,
);
var it: TestIterator = .{ .data = &.{
"--scrollback-limit-bytes=1234",
"--scrollback-limit-lines=567",
} };
try cfg.loadIter(alloc, &it);
try testing.expectEqual(
@as(usize, 1234),
cfg.@"scrollback-limit-bytes".value,
);
try testing.expectEqual(
@as(usize, 567),
cfg.@"scrollback-limit-lines".value,
);
var unlimited_it: TestIterator = .{ .data = &.{
"--scrollback-limit-bytes=unlimited",
"--scrollback-limit-lines=unlimited",
} };
try cfg.loadIter(alloc, &unlimited_it);
try testing.expectEqual(
std.math.maxInt(usize),
cfg.@"scrollback-limit-bytes".value,
);
try testing.expectEqual(
std.math.maxInt(usize),
cfg.@"scrollback-limit-lines".value,
);
var reset_it: TestIterator = .{ .data = &.{
"--scrollback-limit-bytes=",
"--scrollback-limit-lines=",
} };
try cfg.loadIter(alloc, &reset_it);
try testing.expectEqual(
@as(usize, 50_000_000),
cfg.@"scrollback-limit-bytes".value,
);
try testing.expectEqual(
std.math.maxInt(usize),
cfg.@"scrollback-limit-lines".value,
);
}
test "compatibility: scrollback-limit renamed to bytes" {
const testing = std.testing;
const alloc = testing.allocator;
var cfg = try Config.default(alloc);
defer cfg.deinit();
var it: TestIterator = .{ .data = &.{
"--scrollback-limit=1234",
} };
try cfg.loadIter(alloc, &it);
try testing.expectEqual(
@as(usize, 1234),
cfg.@"scrollback-limit-bytes".value,
);
var unlimited_it: TestIterator = .{ .data = &.{
"--scrollback-limit=unlimited",
} };
try cfg.loadIter(alloc, &unlimited_it);
try testing.expectEqual(
std.math.maxInt(usize),
cfg.@"scrollback-limit-bytes".value,
);
}
test "compatibility: gtk-single-instance desktop" {
const testing = std.testing;
const alloc = testing.allocator;

115
src/config/limit.zig Normal file
View File

@@ -0,0 +1,115 @@
const std = @import("std");
const formatterpkg = @import("formatter.zig");
/// A configurable integer limit with a declared default and support for the
/// special value `unlimited`.
///
/// Unlimited is stored as the maximum value of the integer type so the value
/// remains directly comparable without optional unwrapping.
pub fn Limit(comptime T: type, comptime default_value: T) type {
comptime std.debug.assert(@typeInfo(T) == .int);
return struct {
const Self = @This();
value: T = default_value,
/// The limit initialized with its declared default value.
pub const default: Self = .{};
/// Parses an integer limit or the special value "unlimited".
pub fn parseCLI(input_: ?[]const u8) !Self {
const input = input_ orelse return error.ValueRequired;
if (std.mem.eql(u8, input, "unlimited")) {
return .{ .value = std.math.maxInt(T) };
}
return .{
.value = std.fmt.parseInt(T, input, 0) catch
return error.InvalidValue,
};
}
/// Formats the maximum integer value as "unlimited" and all other
/// values as integers.
pub fn formatEntry(
self: Self,
formatter: formatterpkg.EntryFormatter,
) !void {
if (self.value == std.math.maxInt(T)) {
try formatter.formatEntry([]const u8, "unlimited");
} else {
try formatter.formatEntry(T, self.value);
}
}
/// Returns the configured value, or null for the unlimited sentinel.
pub fn optional(self: Self) ?T {
if (self.value == std.math.maxInt(T)) return null;
return self.value;
}
/// Returns an independent copy of this value for Config cloning.
pub fn clone(
self: Self,
_: std.mem.Allocator,
) std.mem.Allocator.Error!Self {
return self;
}
};
}
test "Limit default and parsing" {
const testing = std.testing;
const TestLimit = Limit(usize, 42);
try testing.expectEqual(@as(usize, 42), TestLimit.default.value);
try testing.expectEqual(
@as(usize, 123),
(try TestLimit.parseCLI("123")).value,
);
try testing.expectEqual(
std.math.maxInt(usize),
(try TestLimit.parseCLI("unlimited")).value,
);
try testing.expectError(error.InvalidValue, TestLimit.parseCLI("invalid"));
}
test "Limit optional" {
const testing = std.testing;
const TestLimit = Limit(u16, 42);
try testing.expectEqual(@as(?u16, 42), (TestLimit{}).optional());
try testing.expectEqual(
@as(?u16, null),
(TestLimit{ .value = std.math.maxInt(u16) }).optional(),
);
}
test "Limit formatting" {
const testing = std.testing;
const TestLimit = Limit(usize, 42);
{
var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
try (TestLimit{ .value = 123 }).formatEntry(
formatterpkg.entryFormatter("limit", &buf.writer),
);
try testing.expectEqualStrings("limit = 123\n", buf.written());
}
{
var buf: std.Io.Writer.Allocating = .init(testing.allocator);
defer buf.deinit();
try (TestLimit{ .value = std.math.maxInt(usize) }).formatEntry(
formatterpkg.entryFormatter("limit", &buf.writer),
);
try testing.expectEqualStrings(
"limit = unlimited\n",
buf.written(),
);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -512,7 +512,7 @@ pub fn adjust(
test "Selection: adjust right" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("A1234\nB5678\nC1234\nD5678");
@@ -579,7 +579,7 @@ test "Selection: adjust right" {
test "Selection: adjust left" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("A1234\nB5678\nC1234\nD5678");
@@ -628,7 +628,7 @@ test "Selection: adjust left" {
test "Selection: adjust left skips blanks" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("A1234\nB5678\nC12\nD56");
@@ -677,7 +677,7 @@ test "Selection: adjust left skips blanks" {
test "Selection: adjust up" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("A\nB\nC\nD\nE");
@@ -724,7 +724,7 @@ test "Selection: adjust up" {
test "Selection: adjust down" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("A\nB\nC\nD\nE");
@@ -771,7 +771,7 @@ test "Selection: adjust down" {
test "Selection: adjust down with not full screen" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("A\nB\nC");
@@ -799,7 +799,7 @@ test "Selection: adjust down with not full screen" {
test "Selection: adjust home" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("A\nB\nC");
@@ -827,7 +827,7 @@ test "Selection: adjust home" {
test "Selection: adjust end with not full screen" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("A\nB\nC");
@@ -855,7 +855,7 @@ test "Selection: adjust end with not full screen" {
test "Selection: adjust beginning of line" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 8, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 8, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("A12 B34\nC12 D34");
@@ -925,7 +925,7 @@ test "Selection: adjust beginning of line" {
test "Selection: adjust end of line" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 8, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 8, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("A12 B34\nC12 D34");
@@ -996,7 +996,7 @@ test "Selection: order, standard" {
const alloc = testing.allocator;
const io = testing.io;
var s = try Screen.init(io, alloc, .{ .cols = 100, .rows = 100, .max_scrollback = 1 });
var s = try Screen.init(io, alloc, .{ .cols = 100, .rows = 100, .max_scrollback_bytes = 1 });
defer s.deinit();
{
@@ -1061,7 +1061,7 @@ test "Selection: rectangle corners clamp across mixed-width pages" {
var s = try Screen.init(testing.io, testing.allocator, .{
.cols = 4,
.rows = 2,
.max_scrollback = 0,
.max_scrollback_bytes = 0,
});
defer s.deinit();
@@ -1087,7 +1087,7 @@ test "Selection: order, rectangle" {
const alloc = testing.allocator;
const io = testing.io;
var s = try Screen.init(io, alloc, .{ .cols = 100, .rows = 100, .max_scrollback = 1 });
var s = try Screen.init(io, alloc, .{ .cols = 100, .rows = 100, .max_scrollback_bytes = 1 });
defer s.deinit();
// Conventions:
@@ -1199,7 +1199,7 @@ test "Selection: order, rectangle" {
test "topLeft" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
{
// forward
@@ -1262,7 +1262,7 @@ test "topLeft" {
test "bottomRight" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
{
// forward
@@ -1325,7 +1325,7 @@ test "bottomRight" {
test "ordered" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
{
// forward
@@ -1406,7 +1406,7 @@ test "ordered" {
test "Selection: contains" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 10, .max_scrollback_bytes = 0 });
defer s.deinit();
{
const sel = Selection.init(
@@ -1452,7 +1452,7 @@ test "Selection: contains" {
test "Selection: contains, rectangle" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 15, .rows = 15, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 15, .rows = 15, .max_scrollback_bytes = 0 });
defer s.deinit();
{
const sel = Selection.init(
@@ -1514,7 +1514,7 @@ test "Selection: contains, rectangle" {
test "Selection: containedRow" {
const testing = std.testing;
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 5, .max_scrollback = 0 });
var s = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 5, .max_scrollback_bytes = 0 });
defer s.deinit();
{
@@ -1637,7 +1637,7 @@ test "Selection: containedRow clamps mixed-width pages" {
var s = try Screen.init(testing.io, testing.allocator, .{
.cols = 4,
.rows = 3,
.max_scrollback = 0,
.max_scrollback_bytes = 0,
});
defer s.deinit();

View File

@@ -1029,7 +1029,7 @@ fn testDragSelection(
.padding_left = 5,
.screen_height = 110,
};
var screen = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 5, .max_scrollback = 0 });
var screen = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 5, .max_scrollback_bytes = 0 });
defer screen.deinit();
const click_pin = screen.pages.pin(.{
@@ -1090,7 +1090,7 @@ fn testDragSelectionIsNull(
.padding_left = 5,
.screen_height = 110,
};
var screen = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 5, .max_scrollback = 0 });
var screen = try Screen.init(testing.io, testing.allocator, .{ .cols = 10, .rows = 5, .max_scrollback_bytes = 0 });
defer screen.deinit();
const click_pin = screen.pages.pin(.{
@@ -1724,7 +1724,7 @@ test "SelectionGesture autoscroll tick scrolls and continues drag" {
}
test "SelectionGesture autoscroll tick resolves drag pin after scrolling" {
var t = try Terminal.init(testing.io, testing.allocator, .{ .cols = 5, .rows = 3, .max_scrollback = 10 });
var t = try Terminal.init(testing.io, testing.allocator, .{ .cols = 5, .rows = 3, .max_scrollback_bytes = 10 });
defer t.deinit(testing.allocator);
try t.printString("1111\n2222\n3333\n4444\n5555");
t.scrollViewport(.{ .delta = -2 });

View File

@@ -131,7 +131,7 @@ test "StringMap searchIterator" {
defer re.deinit();
// Initialize our screen
var s = try Screen.init(io, alloc, .{ .cols = 5, .rows = 5, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 5, .rows = 5, .max_scrollback_bytes = 0 });
defer s.deinit();
const str = "1ABCD2EFGH\n3IJKL";
try s.testWriteString(str);
@@ -190,7 +190,7 @@ test "StringMap searchIterator URL detection" {
defer re.deinit();
// Initialize our screen with text containing a URL
var s = try Screen.init(io, alloc, .{ .cols = 40, .rows = 5, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 40, .rows = 5, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("hello https://example.com/path world");
@@ -252,7 +252,7 @@ test "StringMap searchIterator URL with click position" {
defer re.deinit();
// Initialize our screen with text containing a URL
var s = try Screen.init(io, alloc, .{ .cols = 40, .rows = 5, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 40, .rows = 5, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("hello https://example.com world");

View File

@@ -256,7 +256,16 @@ pub const Cursor = struct {
pub const Options = struct {
cols: size.CellCountInt,
rows: size.CellCountInt,
max_scrollback: usize = 10_000,
/// The maximum size of scrollback in bytes. Null is unlimited and zero
/// disables scrollback.
max_scrollback_bytes: ?usize = 10_000,
/// The maximum number of physical scrollback rows, excluding the active
/// area. Null is unlimited. The effective limit permits at least one
/// standard page and only complete historical pages are pruned.
max_scrollback_lines: ?usize = null,
colors: Colors = .default,
/// The default mode state. When the terminal gets a reset, it
@@ -300,7 +309,8 @@ pub fn init(
var screen_set: ScreenSet = try .init(io_impl, alloc, .{
.cols = cols,
.rows = rows,
.max_scrollback = opts.max_scrollback,
.max_scrollback_bytes = opts.max_scrollback_bytes,
.max_scrollback_lines = opts.max_scrollback_lines,
.kitty_image_storage_limit = opts.kitty_image_storage_limit,
.kitty_image_loading_limits = opts.kitty_image_loading_limits,
});
@@ -3830,7 +3840,7 @@ pub fn resize(
.{
.cols = opts.cols,
.rows = opts.rows,
.max_scrollback = 0,
.max_scrollback_bytes = 0,
.kitty_image_storage_limit = if (comptime build_options.kitty_graphics)
primary.kitty_images.total_limit
else
@@ -3878,6 +3888,26 @@ pub fn resize(
};
}
test "Terminal forwards optional scrollback limits" {
const max_lines: usize = 123;
var t = try init(testing.io, testing.allocator, .{
.cols = 80,
.rows = 24,
.max_scrollback_bytes = null,
.max_scrollback_lines = max_lines,
});
defer t.deinit(testing.allocator);
try testing.expectEqual(
std.math.maxInt(usize),
t.screens.active.pages.explicit_max_size,
);
try testing.expectEqual(
max_lines,
t.screens.active.pages.explicit_max_lines,
);
}
test "Terminal: resize resets synchronized output" {
const alloc = testing.allocator;
const io_impl = testing.io;
@@ -4294,7 +4324,7 @@ pub fn switchScreen(self: *Terminal, key: ScreenSet.Key) !?*Screen {
.{
.cols = self.cols,
.rows = self.rows,
.max_scrollback = switch (key) {
.max_scrollback_bytes = switch (key) {
.primary => primary.pages.explicit_max_size,
.alternate => 0,
},
@@ -7663,7 +7693,7 @@ test "Terminal: insertLines top/bottom scroll region" {
test "Terminal: insertLines across page boundary marks all shifted rows dirty" {
const alloc = testing.allocator;
const io_impl = testing.io;
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 10, .max_scrollback = 1024 });
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 10, .max_scrollback_bytes = 1024 });
defer t.deinit(alloc);
const first_page = t.screens.active.pages.pages.first.?;
@@ -7718,7 +7748,7 @@ test "Terminal: insertLines hyperlink-dense row crosses page boundary" {
// page's capacity and retry rather than corrupting the page list.
const alloc = testing.allocator;
const io_impl = testing.io;
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 10, .max_scrollback = 1024 });
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 10, .max_scrollback_bytes = 1024 });
defer t.deinit(alloc);
const pages = &t.screens.active.pages;
@@ -8410,7 +8440,7 @@ test "Terminal: scrollUp creates scrollback in primary screen" {
// scrollUp (CSI S) should push lines into scrollback like xterm.
const alloc = testing.allocator;
const io_impl = testing.io;
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback = 10 });
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback_bytes = 10 });
defer t.deinit(alloc);
// Fill the screen with content
@@ -8453,11 +8483,11 @@ test "Terminal: scrollUp creates scrollback in primary screen" {
}
}
test "Terminal: scrollUp with max_scrollback zero" {
// When max_scrollback is 0, scrollUp should still work but not retain history
test "Terminal: scrollUp with max_scrollback_bytes zero" {
// When max_scrollback_bytes is 0, scrollUp should still work but not retain history
const alloc = testing.allocator;
const io_impl = testing.io;
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback = 0 });
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback_bytes = 0 });
defer t.deinit(alloc);
try t.printString("AAAAA");
@@ -8486,11 +8516,11 @@ test "Terminal: scrollUp with max_scrollback zero" {
}
}
test "Terminal: scrollUp with max_scrollback zero and top margin" {
// When max_scrollback is 0 and top margin is set, should use deleteLines path
test "Terminal: scrollUp with max_scrollback_bytes zero and top margin" {
// When max_scrollback_bytes is 0 and top margin is set, should use deleteLines path
const alloc = testing.allocator;
const io_impl = testing.io;
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback = 0 });
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback_bytes = 0 });
defer t.deinit(alloc);
try t.printString("AAAAA");
@@ -8517,11 +8547,11 @@ test "Terminal: scrollUp with max_scrollback zero and top margin" {
}
}
test "Terminal: scrollUp with max_scrollback zero and left/right margin" {
// When max_scrollback is 0 with left/right margins, uses deleteLines path
test "Terminal: scrollUp with max_scrollback_bytes zero and left/right margin" {
// When max_scrollback_bytes is 0 with left/right margins, uses deleteLines path
const alloc = testing.allocator;
const io_impl = testing.io;
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 10, .max_scrollback = 0 });
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 10, .max_scrollback_bytes = 0 });
defer t.deinit(alloc);
try t.printString("AAAAABBBBB");
@@ -9703,7 +9733,7 @@ test "Terminal: index bottom of scroll region with hyperlinks" {
test "Terminal: index bottom of scroll region clear hyperlinks" {
const alloc = testing.allocator;
const io_impl = testing.io;
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback = 0 });
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback_bytes = 0 });
defer t.deinit(alloc);
t.setTopAndBottomMargin(2, 3);
@@ -9896,7 +9926,7 @@ test "Terminal: index bottom of scroll region creates scrollback" {
test "Terminal: index bottom of scroll region no scrollback" {
const alloc = testing.allocator;
const io_impl = testing.io;
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback = 0 });
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback_bytes = 0 });
defer t.deinit(alloc);
t.setTopAndBottomMargin(1, 3);
@@ -10063,7 +10093,7 @@ test "Terminal: index bottom of alt screen top region" {
test "Terminal: scrollUp top region no scrollback" {
const alloc = testing.allocator;
const io_impl = testing.io;
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback = 0 });
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 5, .max_scrollback_bytes = 0 });
defer t.deinit(alloc);
try t.printString("A\nB\nC\nD\nE");
@@ -10648,7 +10678,7 @@ test "Terminal: deleteLines colors with bg color" {
test "Terminal: deleteLines across page boundary marks all shifted rows dirty" {
const alloc = testing.allocator;
const io_impl = testing.io;
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 10, .max_scrollback = 1024 });
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 10, .max_scrollback_bytes = 1024 });
defer t.deinit(alloc);
const first_page = t.screens.active.pages.pages.first.?;
@@ -10708,7 +10738,7 @@ test "Terminal: deleteLines hyperlink-dense row crosses page boundary" {
// this exercises the cursor accounting of the capacity increase.
const alloc = testing.allocator;
const io_impl = testing.io;
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 10, .max_scrollback = 1024 });
var t = try init(io_impl, alloc, .{ .rows = 5, .cols = 10, .max_scrollback_bytes = 1024 });
defer t.deinit(alloc);
const pages = &t.screens.active.pages;

View File

@@ -365,7 +365,7 @@ fn new_(
.{
.cols = opts.cols,
.rows = opts.rows,
.max_scrollback = opts.max_scrollback,
.max_scrollback_bytes = opts.max_scrollback,
},
);
errdefer t.deinit(alloc);

View File

@@ -1427,7 +1427,7 @@ test "incremental updates match full rebuild" {
var t = try Terminal.init(io, alloc, .{
.cols = 20,
.rows = 8,
.max_scrollback = 500,
.max_scrollback_bytes = 500,
});
defer t.deinit(alloc);
@@ -2010,7 +2010,7 @@ test "linkCells with scrollback spanning pages" {
var t = try Terminal.init(io, alloc, .{
.cols = page.std_capacity.cols,
.rows = viewport_rows,
.max_scrollback = 10_000,
.max_scrollback_bytes = 10_000,
});
defer t.deinit(alloc);

View File

@@ -381,7 +381,7 @@ test "compressed history match spanning page boundary remains compressed" {
var t: Terminal = try .init(io, alloc, .{
.cols = 80,
.rows = 24,
.max_scrollback = 10 * 1024 * 1024,
.max_scrollback_bytes = 10 * 1024 * 1024,
});
defer t.deinit(alloc);
@@ -487,7 +487,11 @@ test "feed with pruned page" {
const alloc = testing.allocator;
// Zero here forces minimum max size to effectively two pages.
var p: PageList = try .init(alloc, 80, 24, 0);
var p: PageList = try .init(alloc, .{
.cols = 80,
.rows = 24,
.max_size = 0,
});
defer p.deinit();
// Grow to capacity
@@ -530,7 +534,10 @@ test "feed with pruned page" {
test "feed keeps its tracked pin within a shorter page" {
const alloc = testing.allocator;
var pages: PageList = try .init(alloc, 10, 2, null);
var pages: PageList = try .init(alloc, .{
.cols = 10,
.rows = 2,
});
defer pages.deinit();
const first = pages.pages.first.?;

View File

@@ -977,7 +977,7 @@ test "simple search with history" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1019,7 +1019,7 @@ test "reload active with history change" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1207,7 +1207,7 @@ test "select after resize resets stale flattened results" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 3,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
@@ -1307,7 +1307,7 @@ test "select into history" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1485,7 +1485,7 @@ test "select prev with history" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1540,7 +1540,7 @@ test "select prev wraps when all matches are in history" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1605,7 +1605,7 @@ test "select after partial history erase drops a pruned selection" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1638,7 +1638,7 @@ test "select after history compaction ignores replaced results" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1673,7 +1673,7 @@ test "select after partial history page erase ignores shifted results" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1707,7 +1707,7 @@ test "reload defers pruning unselected history results" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1742,7 +1742,7 @@ test "reload after partial history page erase drops shifted selection first" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1781,7 +1781,7 @@ test "select after history page split ignores moved results" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1815,7 +1815,7 @@ test "screen search no scrollback has no history" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = 0,
.max_scrollback_bytes = 0,
});
defer t.deinit(alloc);
@@ -1852,7 +1852,7 @@ test "reloadActive partial history cleanup on appendSlice error" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1900,7 +1900,7 @@ test "reloadActive partial history cleanup on loop append error" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;
@@ -1947,7 +1947,7 @@ test "select after clearing scrollback" {
var t: Terminal = try .init(io, alloc, .{
.cols = 10,
.rows = 2,
.max_scrollback = std.math.maxInt(usize),
.max_scrollback_bytes = std.math.maxInt(usize),
});
defer t.deinit(alloc);
const list: *PageList = &t.screens.active.pages;

View File

@@ -722,7 +722,7 @@ test "SlidingWindow empty needle has no matches" {
var s = try Screen.init(io, alloc, .{
.cols = 80,
.rows = 24,
.max_scrollback = 0,
.max_scrollback_bytes = 0,
});
defer s.deinit();
try s.testWriteString("hello");
@@ -739,7 +739,7 @@ test "SlidingWindow single append" {
var w: SlidingWindow = try .init(alloc, .forward, "boo!");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("hello. boo! hello. boo!");
@@ -785,7 +785,7 @@ test "SlidingWindow single append case insensitive ASCII" {
var w: SlidingWindow = try .init(alloc, .forward, "Boo!");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("hello. boo! hello. boo!");
@@ -831,7 +831,7 @@ test "SlidingWindow single append single char" {
var w: SlidingWindow = try .init(alloc, .forward, "b");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("hello. boo! hello. boo!");
@@ -877,7 +877,7 @@ test "SlidingWindow single append no match" {
var w: SlidingWindow = try .init(alloc, .forward, "nope!");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("hello. boo! hello. boo!");
@@ -902,7 +902,7 @@ test "SlidingWindow two pages" {
var w: SlidingWindow = try .init(alloc, .forward, "boo!");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 1000 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 1000 });
defer s.deinit();
// Fill up the first page. The final bytes in the first page
@@ -958,7 +958,7 @@ test "SlidingWindow two pages single char" {
var w: SlidingWindow = try .init(alloc, .forward, "b");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 1000 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 1000 });
defer s.deinit();
// Fill up the first page. The final bytes in the first page
@@ -1014,7 +1014,7 @@ test "SlidingWindow two pages match across boundary" {
var w: SlidingWindow = try .init(alloc, .forward, "hello, world");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 1000 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 1000 });
defer s.deinit();
// Fill up the first page. The final bytes in the first page
@@ -1060,7 +1060,7 @@ test "SlidingWindow two pages no match across boundary with newline" {
var w: SlidingWindow = try .init(alloc, .forward, "hello, world");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 1000 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 1000 });
defer s.deinit();
// Fill up the first page. The final bytes in the first page
@@ -1094,7 +1094,7 @@ test "SlidingWindow two pages no match across boundary with newline reverse" {
var w: SlidingWindow = try .init(alloc, .reverse, "hello, world");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 1000 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 1000 });
defer s.deinit();
// Fill up the first page. The final bytes in the first page
@@ -1125,7 +1125,7 @@ test "SlidingWindow two pages no match prunes first page" {
var w: SlidingWindow = try .init(alloc, .forward, "nope!");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 1000 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 1000 });
defer s.deinit();
// Fill up the first page. The final bytes in the first page
@@ -1158,7 +1158,7 @@ test "SlidingWindow two pages no match keeps both pages" {
const alloc = testing.allocator;
const io = testing.io;
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 1000 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 1000 });
defer s.deinit();
// Fill up the first page. The final bytes in the first page
@@ -1202,7 +1202,7 @@ test "SlidingWindow single append across circular buffer boundary" {
var w: SlidingWindow = try .init(alloc, .forward, "abc");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("XXXXXXXXXXXXXXXXXXXboo!XXXXX");
@@ -1259,7 +1259,7 @@ test "SlidingWindow single append match on boundary" {
var w: SlidingWindow = try .init(alloc, .forward, "abcd");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("o!XXXXXXXXXXXXXXXXXXXbo");
@@ -1319,7 +1319,7 @@ test "SlidingWindow single append reversed" {
var w: SlidingWindow = try .init(alloc, .reverse, "boo!");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("hello. boo! hello. boo!");
@@ -1365,7 +1365,7 @@ test "SlidingWindow single append no match reversed" {
var w: SlidingWindow = try .init(alloc, .reverse, "nope!");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("hello. boo! hello. boo!");
@@ -1390,7 +1390,7 @@ test "SlidingWindow two pages reversed" {
var w: SlidingWindow = try .init(alloc, .reverse, "boo!");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 1000 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 1000 });
defer s.deinit();
// Fill up the first page. The final bytes in the first page
@@ -1446,7 +1446,7 @@ test "SlidingWindow two pages match across boundary reversed" {
var w: SlidingWindow = try .init(alloc, .reverse, "hello, world");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 1000 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 1000 });
defer s.deinit();
// Fill up the first page. The final bytes in the first page
@@ -1502,7 +1502,7 @@ test "SlidingWindow two pages no match prunes first page reversed" {
var w: SlidingWindow = try .init(alloc, .reverse, "nope!");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 1000 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 1000 });
defer s.deinit();
// Fill up the first page. The final bytes in the first page
@@ -1535,7 +1535,7 @@ test "SlidingWindow two pages no match keeps both pages reversed" {
const alloc = testing.allocator;
const io = testing.io;
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 1000 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 1000 });
defer s.deinit();
// Fill up the first page. The final bytes in the first page
@@ -1579,7 +1579,7 @@ test "SlidingWindow single append across circular buffer boundary reversed" {
var w: SlidingWindow = try .init(alloc, .reverse, "abc");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("XXXXXXXXXXXXXXXXXXXboo!XXXXX");
@@ -1637,7 +1637,7 @@ test "SlidingWindow single append match on boundary reversed" {
var w: SlidingWindow = try .init(alloc, .reverse, "abcd");
defer w.deinit();
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback = 0 });
var s = try Screen.init(io, alloc, .{ .cols = 80, .rows = 24, .max_scrollback_bytes = 0 });
defer s.deinit();
try s.testWriteString("o!XXXXXXXXXXXXXXXXXXXbo");
@@ -1779,7 +1779,7 @@ test "SlidingWindow append whitespace only node" {
var s = try Screen.init(io, alloc, .{
.cols = 80,
.rows = 24,
.max_scrollback = 0,
.max_scrollback_bytes = 0,
});
defer s.deinit();

View File

@@ -2239,7 +2239,7 @@ test "stream: CSI W with intermediate but no params" {
var t: Terminal = try .init(testing.io, testing.allocator, .{
.cols = 80,
.rows = 24,
.max_scrollback = 100,
.max_scrollback_bytes = 100,
});
defer t.deinit(testing.allocator);

View File

@@ -246,7 +246,8 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void {
break :opts .{
.cols = grid_size.columns,
.rows = grid_size.rows,
.max_scrollback = opts.full_config.@"scrollback-limit",
.max_scrollback_bytes = opts.full_config.@"scrollback-limit-bytes".optional(),
.max_scrollback_lines = opts.full_config.@"scrollback-limit-lines".optional(),
.default_modes = default_modes,
.default_cursor_style = opts.config.cursor_style,
.default_cursor_blink = opts.config.cursor_blink,

View File

@@ -44,7 +44,7 @@ pub export fn zig_fuzz_test(
var t = Terminal.init(threaded.io(), alloc, .{
.cols = 80,
.rows = 24,
.max_scrollback = 100,
.max_scrollback_bytes = 100,
}) catch return;
defer t.deinit(alloc);