Make selection part of the cache key for GPU cells

If the selection state changes for a given row, the row must be
invalidated.
This commit is contained in:
Mitchell Hashimoto
2022-09-14 19:58:36 -07:00
parent 77851b30a2
commit c68c487e14
3 changed files with 36 additions and 0 deletions

View File

@ -20,6 +20,7 @@ const log = std.log.scoped(.grid);
// separately for alt screens. By storing that in the key, we very likely // separately for alt screens. By storing that in the key, we very likely
// have the cache already for when the primary screen is reactivated. // have the cache already for when the primary screen is reactivated.
const CellsLRU = lru.AutoHashMap(struct { const CellsLRU = lru.AutoHashMap(struct {
selection: ?terminal.Selection,
screen: terminal.Terminal.ScreenType, screen: terminal.Terminal.ScreenType,
row_id: terminal.Screen.RowHeader.Id, row_id: terminal.Screen.RowHeader.Id,
}, std.ArrayListUnmanaged(GPUCell)); }, std.ArrayListUnmanaged(GPUCell));
@ -384,8 +385,26 @@ pub fn rebuildCells(self: *Grid, term: *Terminal) !void {
while (rowIter.next()) |row| { while (rowIter.next()) |row| {
defer y += 1; defer y += 1;
// Our selection value is only non-null if this selection happens
// to contain this row. If the selection changes for any reason,
// then we invalidate the cache.
const selection = sel: {
if (term.selection) |sel| {
const screen_point = (terminal.point.Viewport{
.x = 0,
.y = y,
}).toScreen(&term.screen);
// If we are selected, we our colors are just inverted fg/bg
if (sel.containsRow(screen_point)) break :sel sel;
}
break :sel null;
};
// Get our value from the cache. // Get our value from the cache.
const gop = try self.cells_lru.getOrPut(self.alloc, .{ const gop = try self.cells_lru.getOrPut(self.alloc, .{
.selection = selection,
.screen = term.active_screen, .screen = term.active_screen,
.row_id = row.getId(), .row_id = row.getId(),
}); });

View File

@ -40,6 +40,14 @@ pub fn contains(self: Selection, p: ScreenPoint) bool {
return p.y > tl.y and p.y < br.y; return p.y > tl.y and p.y < br.y;
} }
/// Returns true if the selection contains the row of the given point,
/// regardless of the x value.
pub fn containsRow(self: Selection, p: ScreenPoint) bool {
const tl = self.topLeft();
const br = self.bottomRight();
return p.y >= tl.y and p.y <= br.y;
}
/// Returns the top left point of the selection. /// Returns the top left point of the selection.
pub fn topLeft(self: Selection) ScreenPoint { pub fn topLeft(self: Selection) ScreenPoint {
return switch (self.order()) { return switch (self.order()) {
@ -78,6 +86,9 @@ test "Selection: contains" {
try testing.expect(sel.contains(.{ .x = 1, .y = 2 })); try testing.expect(sel.contains(.{ .x = 1, .y = 2 }));
try testing.expect(!sel.contains(.{ .x = 1, .y = 1 })); try testing.expect(!sel.contains(.{ .x = 1, .y = 1 }));
try testing.expect(!sel.contains(.{ .x = 5, .y = 2 })); try testing.expect(!sel.contains(.{ .x = 5, .y = 2 }));
try testing.expect(!sel.containsRow(.{ .x = 1, .y = 3 }));
try testing.expect(sel.containsRow(.{ .x = 1, .y = 1 }));
try testing.expect(sel.containsRow(.{ .x = 5, .y = 2 }));
} }
// Reverse // Reverse

View File

@ -76,6 +76,12 @@ pub const ScreenPoint = struct {
(self.y == other.y and self.x < other.x); (self.y == other.y and self.x < other.x);
} }
/// Returns true if this screen point is currently in the active viewport.
pub fn inViewport(self: ScreenPoint, screen: *const Screen) bool {
return self.y >= screen.viewport and
self.y < screen.viewport + screen.rows;
}
/// Converts this to a viewport point. If the point is above the /// Converts this to a viewport point. If the point is above the
/// viewport this will move the point to (0, 0) and if it is below /// viewport this will move the point to (0, 0) and if it is below
/// the viewport it'll move it to (cols - 1, rows - 1). /// the viewport it'll move it to (cols - 1, rows - 1).