diff options
Diffstat (limited to 'vendor/libghostty-vt/src/terminal/ScreenSet.zig')
| -rw-r--r-- | vendor/libghostty-vt/src/terminal/ScreenSet.zig | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/terminal/ScreenSet.zig b/vendor/libghostty-vt/src/terminal/ScreenSet.zig index d0856da5..4d3689e3 100644 --- a/vendor/libghostty-vt/src/terminal/ScreenSet.zig +++ b/vendor/libghostty-vt/src/terminal/ScreenSet.zig @@ -30,6 +30,11 @@ active: *Screen, /// All screens that are initialized. all: std.EnumMap(Key, *Screen), +/// Monotonic generation counter for each screen key. This changes whenever a +/// screen is removed so external handles can distinguish a newly initialized +/// screen from stale references into destroyed screen storage. +generations: std.EnumMap(Key, usize), + pub fn init( alloc: Allocator, opts: Screen.Options, @@ -42,6 +47,7 @@ pub fn init( .active_key = .primary, .active = screen, .all = .init(.{ .primary = screen }), + .generations = .initFull(0), }; } @@ -59,6 +65,11 @@ pub fn get(self: *const ScreenSet, key: Key) ?*Screen { return self.all.get(key); } +/// Get the current generation for the given screen key. +pub fn generation(self: *const ScreenSet, key: Key) usize { + return self.generations.get(key).?; +} + /// Get the screen for the given key, initializing it if necessary. pub fn getInit( self: *ScreenSet, @@ -82,6 +93,7 @@ pub fn remove( ) void { assert(key != .primary); if (self.all.fetchRemove(key)) |screen| { + self.generations.put(key, self.generation(key) +% 1); screen.deinit(); alloc.destroy(screen); } @@ -99,9 +111,40 @@ test ScreenSet { var set: ScreenSet = try .init(alloc, .default); defer set.deinit(alloc); try testing.expectEqual(.primary, set.active_key); + try testing.expectEqual(@as(usize, 0), set.generation(.primary)); + try testing.expectEqual(@as(usize, 0), set.generation(.alternate)); // Initialize a secondary screen _ = try set.getInit(alloc, .alternate, .default); + try testing.expectEqual(@as(usize, 0), set.generation(.alternate)); + set.switchTo(.alternate); try testing.expectEqual(.alternate, set.active_key); } + +test "ScreenSet generations" { + const alloc = testing.allocator; + var set: ScreenSet = try .init(alloc, .default); + defer set.deinit(alloc); + + try testing.expectEqual(@as(usize, 0), set.generation(.primary)); + try testing.expectEqual(@as(usize, 0), set.generation(.alternate)); + + // A no-op removal doesn't change the generation. + set.remove(alloc, .alternate); + try testing.expectEqual(@as(usize, 0), set.generation(.alternate)); + + // Initializing a screen doesn't change the generation. + _ = try set.getInit(alloc, .alternate, .default); + try testing.expectEqual(@as(usize, 0), set.generation(.alternate)); + + const alternate_generation = set.generation(.alternate); + set.remove(alloc, .alternate); + try testing.expectEqual(alternate_generation +% 1, set.generation(.alternate)); + + // Reinitializing keeps the generation from the last removal, so stale + // handles can distinguish the new screen from the destroyed screen. + _ = try set.getInit(alloc, .alternate, .default); + try testing.expectEqual(alternate_generation +% 1, set.generation(.alternate)); + try testing.expectEqual(@as(usize, 0), set.generation(.primary)); +} |
