macos: SplitNode must be hashable to detect change

Fixes #761

SplitNode not being hashable meant that when it was set to a value of
the same enum case, SwiftUI could not detect a change for re-render.
This commit is contained in:
Mitchell Hashimoto
2023-10-29 17:37:39 -07:00
parent c182093934
commit c28a0e9ef0

View File

@ -46,7 +46,7 @@ extension Ghostty {
/// "container" which has a recursive top/left SplitNode and bottom/right SplitNode. These /// "container" which has a recursive top/left SplitNode and bottom/right SplitNode. These
/// values can further be split infinitely. /// values can further be split infinitely.
/// ///
enum SplitNode { enum SplitNode: Equatable, Hashable {
case noSplit(Leaf) case noSplit(Leaf)
case horizontal(Container) case horizontal(Container)
case vertical(Container) case vertical(Container)
@ -113,7 +113,22 @@ extension Ghostty {
} }
} }
class Leaf: ObservableObject { // MARK: - Equatable
static func == (lhs: SplitNode, rhs: SplitNode) -> Bool {
switch (lhs, rhs) {
case (.noSplit(let lhs_v), .noSplit(let rhs_v)):
return lhs_v === rhs_v
case (.horizontal(let lhs_v), .horizontal(let rhs_v)):
return lhs_v === rhs_v
case (.vertical(let lhs_v), .vertical(let rhs_v)):
return lhs_v === rhs_v
default:
return false
}
}
class Leaf: ObservableObject, Equatable, Hashable {
let app: ghostty_app_t let app: ghostty_app_t
@Published var surface: SurfaceView @Published var surface: SurfaceView
@ -122,9 +137,22 @@ extension Ghostty {
self.app = app self.app = app
self.surface = SurfaceView(app, baseConfig) self.surface = SurfaceView(app, baseConfig)
} }
// MARK: - Hashable
func hash(into hasher: inout Hasher) {
hasher.combine(app)
hasher.combine(surface)
}
// MARK: - Equatable
static func == (lhs: Leaf, rhs: Leaf) -> Bool {
return lhs.app == rhs.app && lhs.surface === rhs.surface
}
} }
class Container: ObservableObject { class Container: ObservableObject, Equatable, Hashable {
let app: ghostty_app_t let app: ghostty_app_t
@Published var topLeft: SplitNode @Published var topLeft: SplitNode
@Published var bottomRight: SplitNode @Published var bottomRight: SplitNode
@ -140,6 +168,22 @@ extension Ghostty {
self.topLeft = .noSplit(from) self.topLeft = .noSplit(from)
self.bottomRight = .noSplit(.init(app, baseConfig)) self.bottomRight = .noSplit(.init(app, baseConfig))
} }
// MARK: - Hashable
func hash(into hasher: inout Hasher) {
hasher.combine(app)
hasher.combine(topLeft)
hasher.combine(bottomRight)
}
// MARK: - Equatable
static func == (lhs: Container, rhs: Container) -> Bool {
return lhs.app == rhs.app &&
lhs.topLeft == rhs.topLeft &&
lhs.bottomRight == rhs.bottomRight
}
} }
/// This keeps track of the "neighbors" of a split: the immediately above/below/left/right /// This keeps track of the "neighbors" of a split: the immediately above/below/left/right
@ -265,6 +309,7 @@ extension Ghostty {
} }
} }
.navigationTitle(surfaceTitle ?? "Ghostty") .navigationTitle(surfaceTitle ?? "Ghostty")
.id(node) // Required to detect node changes
} else { } else {
// On these events we want to reset the split state and call it. // On these events we want to reset the split state and call it.
let pubSplit = center.publisher(for: Notification.ghosttyNewSplit, object: zoomedSurface!) let pubSplit = center.publisher(for: Notification.ghosttyNewSplit, object: zoomedSurface!)