mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-09-19 12:08:07 +00:00
macos: avoid publishing search selection changes
#13707 Search selection bindings update synchronously while SwiftUI is processing text edits. Publishing those changes re-entered view updates and could apply a stale String.Index range after deleting the needle. Keep selection state out of ObservableObject publishing. Needle changes still schedule view updates, while selection-only select-all operations explicitly notify observers. This is a bit of hail mary attempt at fixing #13707 because I couldn't actively reproduce it. But this keeps search working fine and conceptually addresses it.
This commit is contained in:
@@ -127,7 +127,12 @@ extension Ghostty.OSSurfaceView {
|
||||
@Published var total: UInt?
|
||||
|
||||
/// The range of the needle's text selection in the find bar.
|
||||
@Published private(set) var needleSelection: Range<String.Index>?
|
||||
///
|
||||
/// This intentionally isn't published. SwiftUI updates this binding
|
||||
/// synchronously while its text field is processing an edit. Publishing
|
||||
/// from that callback re-enters the view update and can apply a stale
|
||||
/// String.Index range to the newly edited needle.
|
||||
private(set) var needleSelection: Range<String.Index>?
|
||||
|
||||
init(
|
||||
from startSearch: Ghostty.Action.StartSearch,
|
||||
@@ -144,14 +149,22 @@ extension Ghostty.OSSurfaceView {
|
||||
|
||||
/// Replaces the search needle while keeping its selection valid.
|
||||
func setNeedle(_ needle: String, selectAll: Bool = false) {
|
||||
if needle != self.needle {
|
||||
let needleChanged = needle != self.needle
|
||||
if needleChanged {
|
||||
// String.Index values are only valid for the string that created
|
||||
// them, so publish a nil selection before changing the string.
|
||||
// them, so clear the selection before changing the string.
|
||||
needleSelection = nil
|
||||
self.needle = needle
|
||||
}
|
||||
|
||||
if selectAll {
|
||||
// A changed needle already schedules a view update through its
|
||||
// @Published setter. If only the selection changes, schedule the
|
||||
// update explicitly so programmatic select-all still takes effect.
|
||||
if !needleChanged {
|
||||
objectWillChange.send()
|
||||
}
|
||||
|
||||
needleSelection = self.needle.startIndex..<self.needle.endIndex
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user