mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 17:26:09 +03:00
terminal: bunch of junk for paged terminal
This commit is contained in:
@ -50,4 +50,8 @@ pub usingnamespace if (builtin.target.isWasm()) struct {
|
|||||||
|
|
||||||
test {
|
test {
|
||||||
@import("std").testing.refAllDecls(@This());
|
@import("std").testing.refAllDecls(@This());
|
||||||
|
|
||||||
|
_ = @import("new/page.zig");
|
||||||
|
_ = @import("new/size.zig");
|
||||||
|
_ = @import("new/style.zig");
|
||||||
}
|
}
|
||||||
|
95
src/terminal/new/page.zig
Normal file
95
src/terminal/new/page.zig
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const color = @import("../color.zig");
|
||||||
|
const sgr = @import("../sgr.zig");
|
||||||
|
const size = @import("size.zig");
|
||||||
|
const Offset = size.Offset;
|
||||||
|
|
||||||
|
/// A page represents a specific section of terminal screen. The primary
|
||||||
|
/// idea of a page is that it is a fully self-contained unit that can be
|
||||||
|
/// serialized, copied, etc. as a convenient way to represent a section
|
||||||
|
/// of the screen.
|
||||||
|
///
|
||||||
|
/// This property is useful for renderers which want to copy just the pages
|
||||||
|
/// for the visible portion of the screen, or for infinite scrollback where
|
||||||
|
/// we may want to serialize and store pages that are sufficiently far
|
||||||
|
/// away from the current viewport.
|
||||||
|
///
|
||||||
|
/// Pages are always backed by a single contiguous block of memory that is
|
||||||
|
/// aligned on a page boundary. This makes it easy and fast to copy pages
|
||||||
|
/// around. Within the contiguous block of memory, the contents of a page are
|
||||||
|
/// thoughtfully laid out to optimize primarily for terminal IO (VT streams)
|
||||||
|
/// and to minimize memory usage.
|
||||||
|
pub const Page = struct {
|
||||||
|
/// The backing memory for the page. A page is always made up of a
|
||||||
|
/// a single contiguous block of memory that is aligned on a page
|
||||||
|
/// boundary and is a multiple of the system page size.
|
||||||
|
///
|
||||||
|
/// The backing memory is always zero initialized, so the zero value
|
||||||
|
/// of all data within the page must always be valid.
|
||||||
|
memory: []align(std.mem.page_size) u8,
|
||||||
|
|
||||||
|
/// The array of rows in the page. The rows are always in row order
|
||||||
|
/// (i.e. index 0 is the top row, index 1 is the row below that, etc.)
|
||||||
|
rows: Offset(Row),
|
||||||
|
|
||||||
|
/// The array of cells in the page. The cells are NOT in row order,
|
||||||
|
/// but they are in column order. To determine the mapping of cells
|
||||||
|
/// to row, you must use the `rows` field. From the pointer to the
|
||||||
|
/// first column, all cells in that row are laid out in column order.
|
||||||
|
cells: Offset(Cell),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Row = packed struct {
|
||||||
|
/// The cells in the row offset from the page.
|
||||||
|
cells: Offset(Cell),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A cell represents a single terminal grid cell.
|
||||||
|
///
|
||||||
|
/// The zero value of this struct must be a valid cell representing empty,
|
||||||
|
/// since we zero initialize the backing memory for a page.
|
||||||
|
pub const Cell = packed struct(u32) {
|
||||||
|
codepoint: u21 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The style attributes for a cell.
|
||||||
|
pub const Style = struct {
|
||||||
|
/// Various colors, all self-explanatory.
|
||||||
|
fg_color: Color = .none,
|
||||||
|
bg_color: Color = .none,
|
||||||
|
underline_color: Color = .none,
|
||||||
|
|
||||||
|
/// On/off attributes that don't require much bit width so we use
|
||||||
|
/// a packed struct to make this take up significantly less space.
|
||||||
|
flags: packed struct {
|
||||||
|
bold: bool = false,
|
||||||
|
italic: bool = false,
|
||||||
|
faint: bool = false,
|
||||||
|
blink: bool = false,
|
||||||
|
inverse: bool = false,
|
||||||
|
invisible: bool = false,
|
||||||
|
strikethrough: bool = false,
|
||||||
|
underline: sgr.Attribute.Underline = .none,
|
||||||
|
} = .{},
|
||||||
|
|
||||||
|
/// The color for an SGR attribute. A color can come from multiple
|
||||||
|
/// sources so we use this to track the source plus color value so that
|
||||||
|
/// we can properly react to things like palette changes.
|
||||||
|
pub const Color = union(enum) {
|
||||||
|
none: void,
|
||||||
|
palette: u8,
|
||||||
|
rgb: color.RGB,
|
||||||
|
};
|
||||||
|
|
||||||
|
test {
|
||||||
|
// The size of the struct so we can be aware of changes.
|
||||||
|
const testing = std.testing;
|
||||||
|
try testing.expectEqual(@as(usize, 14), @sizeOf(Style));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = Page;
|
||||||
|
_ = Style;
|
||||||
|
}
|
60
src/terminal/new/size.zig
Normal file
60
src/terminal/new/size.zig
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
|
/// The maximum size of a page in bytes. We use a u16 here because any
|
||||||
|
/// smaller bit size by Zig is upgraded anyways to a u16 on mainstream
|
||||||
|
/// CPU architectures, and because 65KB is a reasonable page size. To
|
||||||
|
/// support better configurability, we derive everything from this.
|
||||||
|
pub const max_page_size = 65_536;
|
||||||
|
|
||||||
|
/// The int type that can contain the maximum memory offset in bytes,
|
||||||
|
/// derived from the maximum terminal page size.
|
||||||
|
pub const OffsetInt = std.math.IntFittingRange(0, max_page_size - 1);
|
||||||
|
|
||||||
|
/// The int type that can contain the maximum number of cells in a page.
|
||||||
|
pub const CellCountInt = u16; // TODO: derive
|
||||||
|
//
|
||||||
|
/// The offset from the base address of the page to the start of some data.
|
||||||
|
/// This is typed for ease of use.
|
||||||
|
///
|
||||||
|
/// This is a packed struct so we can attach methods to an int.
|
||||||
|
pub fn Offset(comptime T: type) type {
|
||||||
|
return packed struct(OffsetInt) {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
offset: OffsetInt = 0,
|
||||||
|
|
||||||
|
/// Returns a pointer to the start of the data, properly typed.
|
||||||
|
pub fn ptr(self: Self, base: anytype) [*]T {
|
||||||
|
// The offset must be properly aligned for the type since
|
||||||
|
// our return type is naturally aligned. We COULD modify this
|
||||||
|
// to return arbitrary alignment, but its not something we need.
|
||||||
|
assert(@mod(self.offset, @alignOf(T)) == 0);
|
||||||
|
return @ptrFromInt(@intFromPtr(base) + self.offset);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Offset" {
|
||||||
|
// This test is here so that if Offset changes, we can be very aware
|
||||||
|
// of this effect and think about the implications of it.
|
||||||
|
const testing = std.testing;
|
||||||
|
try testing.expect(OffsetInt == u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Offset ptr u8" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const offset: Offset(u8) = .{ .offset = 42 };
|
||||||
|
const base_int: usize = @intFromPtr(&offset);
|
||||||
|
const actual = offset.ptr(&offset);
|
||||||
|
try testing.expectEqual(@as(usize, base_int + 42), @intFromPtr(actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Offset ptr structural" {
|
||||||
|
const Struct = struct { x: u32, y: u32 };
|
||||||
|
const testing = std.testing;
|
||||||
|
const offset: Offset(Struct) = .{ .offset = @alignOf(Struct) * 4 };
|
||||||
|
const base_int: usize = @intFromPtr(&offset);
|
||||||
|
const actual = offset.ptr(&offset);
|
||||||
|
try testing.expectEqual(@as(usize, base_int + offset.offset), @intFromPtr(actual));
|
||||||
|
}
|
62
src/terminal/new/style.zig
Normal file
62
src/terminal/new/style.zig
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const color = @import("../color.zig");
|
||||||
|
const sgr = @import("../sgr.zig");
|
||||||
|
const size = @import("size.zig");
|
||||||
|
|
||||||
|
/// The unique identifier for a style. This is at most the number of cells
|
||||||
|
/// that can fit into a terminal page.
|
||||||
|
pub const Id = size.CellCountInt;
|
||||||
|
|
||||||
|
/// The style attributes for a cell.
|
||||||
|
pub const Style = struct {
|
||||||
|
/// Various colors, all self-explanatory.
|
||||||
|
fg_color: Color = .none,
|
||||||
|
bg_color: Color = .none,
|
||||||
|
underline_color: Color = .none,
|
||||||
|
|
||||||
|
/// On/off attributes that don't require much bit width so we use
|
||||||
|
/// a packed struct to make this take up significantly less space.
|
||||||
|
flags: packed struct {
|
||||||
|
bold: bool = false,
|
||||||
|
italic: bool = false,
|
||||||
|
faint: bool = false,
|
||||||
|
blink: bool = false,
|
||||||
|
inverse: bool = false,
|
||||||
|
invisible: bool = false,
|
||||||
|
strikethrough: bool = false,
|
||||||
|
underline: sgr.Attribute.Underline = .none,
|
||||||
|
} = .{},
|
||||||
|
|
||||||
|
/// The color for an SGR attribute. A color can come from multiple
|
||||||
|
/// sources so we use this to track the source plus color value so that
|
||||||
|
/// we can properly react to things like palette changes.
|
||||||
|
pub const Color = union(enum) {
|
||||||
|
none: void,
|
||||||
|
palette: u8,
|
||||||
|
rgb: color.RGB,
|
||||||
|
};
|
||||||
|
|
||||||
|
test {
|
||||||
|
// The size of the struct so we can be aware of changes.
|
||||||
|
const testing = std.testing;
|
||||||
|
try testing.expectEqual(@as(usize, 14), @sizeOf(Style));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Maps a style definition to metadata about that style.
|
||||||
|
pub const MetadataMap = std.AutoHashMapUnmanaged(Style, Metadata);
|
||||||
|
|
||||||
|
/// Maps the unique style ID to the concrete style definition.
|
||||||
|
pub const IdMap = std.AutoHashMapUnmanaged(size.CellCountInt, Style);
|
||||||
|
|
||||||
|
/// Metadata about a style. This is used to track the reference count
|
||||||
|
/// and the unique identifier for a style. The unique identifier is used
|
||||||
|
/// to track the style in the full style map.
|
||||||
|
pub const Metadata = struct {
|
||||||
|
ref: size.CellCountInt = 0,
|
||||||
|
id: size.CellCountInt = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = Style;
|
||||||
|
}
|
Reference in New Issue
Block a user