terminal: setup selection state on render state

pull/9662/head
Mitchell Hashimoto 2025-11-18 14:02:56 -10:00
parent 0e13fd6b73
commit 29db3e0295
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
2 changed files with 36 additions and 6 deletions

View File

@ -1801,7 +1801,7 @@ pub const Row = packed struct(u64) {
/// Returns true if this row has any managed memory outside of the /// Returns true if this row has any managed memory outside of the
/// row structure (graphemes, styles, etc.) /// row structure (graphemes, styles, etc.)
pub inline fn managedMemory(self: Row) bool { pub inline fn managedMemory(self: Row) bool {
// Ordered on purpose for likelyhood. // Ordered on purpose for likelihood.
return self.styled or self.hyperlink or self.grapheme; return self.styled or self.hyperlink or self.grapheme;
} }
}; };

View File

@ -87,6 +87,9 @@ pub const RenderState = struct {
/// its own draw state. `update` will mark this true whenever /// its own draw state. `update` will mark this true whenever
/// this row is changed, too. /// this row is changed, too.
dirty: bool, dirty: bool,
/// The x range of the selection within this row.
selection: [2]size.CellCountInt,
}; };
pub const Cell = struct { pub const Cell = struct {
@ -179,18 +182,27 @@ pub const RenderState = struct {
@branchHint(.unlikely); @branchHint(.unlikely);
if (self.row_data.len < self.rows) { if (self.row_data.len < self.rows) {
try self.row_data.ensureTotalCapacity(alloc, self.rows); // Resize our rows to the desired length, marking any added
for (self.row_data.len..self.rows) |_| { // values undefined.
self.row_data.appendAssumeCapacity(.{ const old_len = self.row_data.len;
try self.row_data.resize(alloc, self.rows);
// Initialize all our values. Its faster to use slice() + set()
// because appendAssumeCapacity does this multiple times.
var row_data = self.row_data.slice();
for (old_len..self.rows) |y| {
row_data.set(y, .{
.arena = .{}, .arena = .{},
.cells = .empty, .cells = .empty,
.dirty = true, .dirty = true,
.selection = .{ 0, 0 },
}); });
} }
} else { } else {
const row_data = self.row_data.slice();
for ( for (
self.row_data.items(.arena)[self.rows..], row_data.items(.arena)[self.rows..],
self.row_data.items(.cells)[self.rows..], row_data.items(.cells)[self.rows..],
) |state, *cell| { ) |state, *cell| {
var arena: ArenaAllocator = state.promote(alloc); var arena: ArenaAllocator = state.promote(alloc);
arena.deinit(); arena.deinit();
@ -307,6 +319,24 @@ pub const RenderState = struct {
} }
assert(y == self.rows); assert(y == self.rows);
// If our screen has a selection, then mark the rows with the
// selection.
if (s.selection) |*sel| {
@branchHint(.unlikely);
// TODO:
// - Mark the rows with selections
// - Cache the selection (untracked) so we can avoid redoing
// this expensive work every frame.
// We need to determine if our selection is within the viewport.
// The viewport is generally very small so the efficient way to
// do this is to traverse the viewport pages and check for the
// matching selection pages.
_ = sel;
}
// Clear our dirty flags // Clear our dirty flags
t.flags.dirty = .{}; t.flags.dirty = .{};
s.dirty = .{}; s.dirty = .{};