terminal: hyperlink data structures beginning, alloc into page

This commit is contained in:
Mitchell Hashimoto
2024-07-03 10:52:37 -07:00
parent a71b487d58
commit 2a7755c515
3 changed files with 97 additions and 4 deletions

View File

@ -0,0 +1,51 @@
const std = @import("std");
const assert = std.debug.assert;
const hash_map = @import("hash_map.zig");
const AutoOffsetHashMap = hash_map.AutoOffsetHashMap;
const size = @import("size.zig");
const Offset = size.Offset;
const Cell = @import("page.zig").Cell;
const RefCountedSet = @import("ref_counted_set.zig").RefCountedSet;
/// The unique identifier for a hyperlink. This is at most the number of cells
/// that can fit in a single terminal page.
pub const Id = size.CellCountInt;
// The mapping of cell to hyperlink. We use an offset hash map to save space
// since its very unlikely a cell is a hyperlink, so its a waste to store
// the hyperlink ID in the cell itself.
pub const Map = AutoOffsetHashMap(Offset(Cell), Id);
/// The main entry for hyperlinks.
pub const Hyperlink = struct {
id: union(enum) {
/// An explicitly provided ID via the OSC8 sequence.
explicit: Offset(u8).Slice,
/// No ID was provided so we auto-generate the ID based on an
/// incrementing counter. TODO: implement the counter
implicit: size.OffsetInt,
},
/// The URI for the actual link.
uri: Offset(u8).Slice,
};
/// The set of hyperlinks. This is ref-counted so that a set of cells
/// can share the same hyperlink without duplicating the data.
pub const Set = RefCountedSet(
Hyperlink,
Id,
size.CellCountInt,
struct {
pub fn hash(self: *const @This(), link: Hyperlink) u64 {
_ = self;
return link.hash();
}
pub fn eql(self: *const @This(), a: Hyperlink, b: Hyperlink) bool {
_ = self;
return a.eql(b);
}
},
);

View File

@ -7,6 +7,7 @@ const testing = std.testing;
const posix = std.posix;
const fastmem = @import("../fastmem.zig");
const color = @import("color.zig");
const hyperlink = @import("hyperlink.zig");
const sgr = @import("sgr.zig");
const style = @import("style.zig");
const size = @import("size.zig");
@ -114,6 +115,13 @@ pub const Page = struct {
/// The available set of styles in use on this page.
styles: style.Set,
/// The structures used for tracking hyperlinks within the page.
/// The map maps cell offsets to hyperlink IDs and the IDs are in
/// the ref counted set. The strings within the hyperlink structures
/// are allocated in the string allocator.
hyperlink_map: hyperlink.Map,
hyperlink_set: hyperlink.Set,
/// The offset to the first mask of dirty bits in the page.
///
/// The dirty bits is a contiguous array of usize where each bit represents
@ -234,6 +242,15 @@ pub const Page = struct {
buf.add(l.grapheme_map_start),
l.grapheme_map_layout,
),
.hyperlink_map = hyperlink.Map.init(
buf.add(l.hyperlink_map_start),
l.hyperlink_map_layout,
),
.hyperlink_set = hyperlink.Set.init(
buf.add(l.hyperlink_set_start),
l.hyperlink_set_layout,
.{},
),
.size = .{ .cols = cap.cols, .rows = cap.rows },
.capacity = cap,
};
@ -1006,6 +1023,10 @@ pub const Page = struct {
grapheme_map_layout: GraphemeMap.Layout,
string_alloc_start: usize,
string_alloc_layout: StringAlloc.Layout,
hyperlink_map_start: usize,
hyperlink_map_layout: hyperlink.Map.Layout,
hyperlink_set_start: usize,
hyperlink_set_layout: hyperlink.Set.Layout,
capacity: Capacity,
};
@ -1048,7 +1069,15 @@ pub const Page = struct {
const string_start = alignForward(usize, grapheme_map_end, StringAlloc.base_align);
const string_end = string_start + string_layout.total_size;
const total_size = alignForward(usize, string_end, std.mem.page_size);
const hyperlink_map_layout = hyperlink.Map.layout(@intCast(cap.hyperlink_cells));
const hyperlink_map_start = alignForward(usize, string_end, hyperlink.Map.base_align);
const hyperlink_map_end = hyperlink_map_start + hyperlink_map_layout.total_size;
const hyperlink_set_layout = hyperlink.Set.layout(@intCast(cap.hyperlink_entries));
const hyperlink_set_start = alignForward(usize, hyperlink_map_end, hyperlink.Set.base_align);
const hyperlink_set_end = hyperlink_set_start + hyperlink_set_layout.total_size;
const total_size = alignForward(usize, hyperlink_set_end, std.mem.page_size);
return .{
.total_size = total_size,
@ -1066,6 +1095,10 @@ pub const Page = struct {
.grapheme_map_layout = grapheme_map_layout,
.string_alloc_start = string_start,
.string_alloc_layout = string_layout,
.hyperlink_map_start = hyperlink_map_start,
.hyperlink_map_layout = hyperlink_map_layout,
.hyperlink_set_start = hyperlink_set_start,
.hyperlink_set_layout = hyperlink_set_layout,
.capacity = cap,
};
}
@ -1080,6 +1113,8 @@ pub const std_capacity: Capacity = .{
.cols = 215,
.rows = 215,
.styles = 128,
.hyperlink_cells = 32, // TODO: think about these numbers
.hyperlink_entries = 4,
.grapheme_bytes = 8192,
.string_bytes = 2048,
};
@ -1099,6 +1134,12 @@ pub const Capacity = struct {
/// Number of unique styles that can be used on this page.
styles: usize = 16,
/// The cells is the number of cells in the terminal that can have
/// a hyperlink and the entries is the number of unique hyperlinks
/// itself.
hyperlink_cells: usize = 32,
hyperlink_entries: usize = 4,
/// Number of bytes to allocate for grapheme data.
grapheme_bytes: usize = grapheme_bytes_default,
@ -1130,7 +1171,9 @@ pub const Capacity = struct {
// for rows & cells (which will allow us to calculate the number of
// rows we can fit at a certain column width) we need to layout the
// "meta" members of the page (i.e. everything else) from the end.
const string_alloc_start = alignBackward(usize, layout.total_size, StringAlloc.base_align);
const hyperlink_set_start = alignBackward(usize, layout.total_size - layout.hyperlink_set_layout.total_size, hyperlink.Set.base_align);
const hyperlink_map_start = alignBackward(usize, hyperlink_set_start - layout.hyperlink_map_layout.total_size, hyperlink.Map.base_align);
const string_alloc_start = alignBackward(usize, hyperlink_map_start - layout.string_alloc_layout.total_size, StringAlloc.base_align);
const grapheme_map_start = alignBackward(usize, string_alloc_start - layout.grapheme_map_layout.total_size, GraphemeMap.base_align);
const grapheme_alloc_start = alignBackward(usize, grapheme_map_start - layout.grapheme_alloc_layout.total_size, GraphemeAlloc.base_align);
const styles_start = alignBackward(usize, grapheme_alloc_start - layout.styles_layout.total_size, style.Set.base_align);

View File

@ -6,12 +6,11 @@ const page = @import("page.zig");
const size = @import("size.zig");
const Offset = size.Offset;
const OffsetBuf = size.OffsetBuf;
const RefCountedSet = @import("ref_counted_set.zig").RefCountedSet;
const Wyhash = std.hash.Wyhash;
const autoHash = std.hash.autoHash;
const RefCountedSet = @import("ref_counted_set.zig").RefCountedSet;
/// 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;