From 49e4df78333ccdeb262e59d0f3c4de9d4b0bc7fd Mon Sep 17 00:00:00 2001 From: Lukas <134181853+bo2themax@users.noreply.github.com> Date: Sun, 9 Aug 2026 23:19:21 +0200 Subject: [PATCH] macOS: rework for #12712 and #13645 --- .../Ghostty/Surface View/OSSurfaceView.swift | 51 +++++++------------ .../Ghostty/Surface View/SurfaceView.swift | 14 ++--- .../Surface View/SurfaceView_AppKit.swift | 1 + .../SurfaceView+SearchStateTests.swift | 31 ++++------- 4 files changed, 31 insertions(+), 66 deletions(-) diff --git a/macos/Sources/Ghostty/Surface View/OSSurfaceView.swift b/macos/Sources/Ghostty/Surface View/OSSurfaceView.swift index 2f559f2ae..5176a958b 100644 --- a/macos/Sources/Ghostty/Surface View/OSSurfaceView.swift +++ b/macos/Sources/Ghostty/Surface View/OSSurfaceView.swift @@ -117,18 +117,25 @@ extension Ghostty { extension Ghostty.OSSurfaceView { @MainActor class SearchState: ObservableObject { + + /// We should always change needle's text and its selection together + struct Needle: Equatable { + var text: String + var selection: Range? + + static let empty = Needle(text: "", selection: nil) + } + /// The pasteboard used to persist the search needle. /// /// The `.find` pasteboard lets us sync our needle across the system and other find bars. private let pasteboard: OSPasteboard - @Published private(set) var needle: String = "" + @Published var needle = Needle.empty + @Published var selected: UInt? @Published var total: UInt? - /// The range of the needle's text selection in the find bar. - @Published private(set) var needleSelection: Range? - init( from startSearch: Ghostty.Action.StartSearch, pasteboard: OSPasteboard = OSPasteboard.find @@ -144,45 +151,21 @@ extension Ghostty.OSSurfaceView { /// Replaces the search needle while keeping its selection valid. func setNeedle(_ needle: String, selectAll: Bool = false) { - if needle != self.needle { - // String.Index values are only valid for the string that created - // them, so publish a nil selection before changing the string. - needleSelection = nil - self.needle = needle - } - - if selectAll { - needleSelection = self.needle.startIndex..?) { - guard let selection else { - needleSelection = nil - return - } - - guard - let lowerBound = String.Index(selection.lowerBound, within: needle), - let upperBound = String.Index(selection.upperBound, within: needle) - else { - needleSelection = nil - return - } - - needleSelection = lowerBound.. AnyPublisher in if needle.isEmpty || needle.count >= 3 { diff --git a/macos/Tests/Ghostty/Surface View/SurfaceView+SearchStateTests.swift b/macos/Tests/Ghostty/Surface View/SurfaceView+SearchStateTests.swift index 95dab178a..609bc48f7 100644 --- a/macos/Tests/Ghostty/Surface View/SurfaceView+SearchStateTests.swift +++ b/macos/Tests/Ghostty/Surface View/SurfaceView+SearchStateTests.swift @@ -19,7 +19,7 @@ import Testing from: StartSearch(c: .init(needle: nil)), pasteboard: pasteboard ) - #expect(sut.needle == "pb") + #expect(sut.needle.text == "pb") } @Test func init_withEmptyNeedle_readsPasteboardNeedle() { @@ -28,7 +28,7 @@ import Testing from: StartSearch(c: .init(needle: needle)), pasteboard: pasteboard ) - #expect(sut.needle == "pb") + #expect(sut.needle.text == "pb") } } @@ -38,7 +38,7 @@ import Testing from: StartSearch(c: .init(needle: needle)), pasteboard: pasteboard ) - #expect(sut.needle == "start") + #expect(sut.needle.text == "start") } } @@ -67,25 +67,12 @@ import Testing from: StartSearch(c: .init(needle: nil)), pasteboard: pasteboard ) - sut.setNeedleSelection(sut.needle.startIndex..