const std = @import("std"); const assert = std.debug.assert; const color = @import("../color.zig"); const sgr = @import("../sgr.zig"); const style = @import("style.zig"); const size = @import("size.zig"); const Offset = size.Offset; const hash_map = @import("hash_map.zig"); const AutoOffsetHashMap = hash_map.AutoOffsetHashMap; /// 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; } // test { // const testing = std.testing; // const cap = try std.math.ceilPowerOfTwo(usize, 350); // const StyleIdMap = AutoOffsetHashMap(size.CellCountInt, style.Style); // const StyleMetadataMap = AutoOffsetHashMap(style.Style, style.Metadata); // // var len = StyleIdMap.bufferSize(@intCast(cap)); // len += StyleMetadataMap.bufferSize(@intCast(cap)); // try testing.expectEqual(@as(usize, 0), len); // }