From 69cab3d8085d0731574f4498864ced901e55c8b0 Mon Sep 17 00:00:00 2001 From: Nolin McFarland Date: Sun, 17 May 2026 11:26:32 -0400 Subject: [PATCH] feat: select needle when reading from pasteboard --- .../Ghostty/Surface View/OSSurfaceView.swift | 5 ++ .../Ghostty/Surface View/SurfaceView.swift | 6 ++- macos/Sources/Helpers/Backport.swift | 46 +++++++++++++++++++ .../SurfaceView+SearchStateTests.swift | 12 +++++ 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/macos/Sources/Ghostty/Surface View/OSSurfaceView.swift b/macos/Sources/Ghostty/Surface View/OSSurfaceView.swift index 3af562744..d9c01b089 100644 --- a/macos/Sources/Ghostty/Surface View/OSSurfaceView.swift +++ b/macos/Sources/Ghostty/Surface View/OSSurfaceView.swift @@ -1,5 +1,6 @@ import Foundation import GhosttyKit +import SwiftUI extension Ghostty { class OSSurfaceView: OSView, ObservableObject { @@ -125,6 +126,9 @@ extension Ghostty.OSSurfaceView { @Published var selected: UInt? @Published var total: UInt? + /// The range of the needle's text selection in the find bar. + @Published var needleSelection: Range? + init( from startSearch: Ghostty.Action.StartSearch, pasteboard: OSPasteboard = OSPasteboard(name: .find) @@ -142,6 +146,7 @@ extension Ghostty.OSSurfaceView { let pasteboardNeedle = pasteboard.string(forType: .string) if let pasteboardNeedle, pasteboardNeedle != needle { needle = pasteboardNeedle + needleSelection = needle.startIndex..? + + init( + _ titleKey: LocalizedStringKey, + text: Binding, + selection: Binding?> + ) { + self.titleKey = titleKey + self._text = text + self._textSelection = selection + } + + var body: some View { + if #available(macOS 15, *) { + TextField( + titleKey, + text: _text, + selection: Binding( + get: { + if let textSelection { + TextSelection(range: textSelection) + } else { + nil + } + }, + set: { selection in + if let selection, + case .selection(let range) = selection.indices { + self.textSelection = range + } else { + self.textSelection = nil + } + } + ) + ) + } else { + TextField(titleKey, text: _text) + } + } +} diff --git a/macos/Tests/Ghostty/Surface View/SurfaceView+SearchStateTests.swift b/macos/Tests/Ghostty/Surface View/SurfaceView+SearchStateTests.swift index 7b3c1942e..00a37f67f 100644 --- a/macos/Tests/Ghostty/Surface View/SurfaceView+SearchStateTests.swift +++ b/macos/Tests/Ghostty/Surface View/SurfaceView+SearchStateTests.swift @@ -84,4 +84,16 @@ import Testing sut.readPasteboardNeedle() #expect(sut.needle == "pb") } + + @Test func readPasteboardNeedle_setsNeedleSelectionRange() { + let sut = SearchState( + from: StartSearch(c: .init(needle: nil)), + pasteboard: pasteboard + ) + sut.needle = "sut" + sut.readPasteboardNeedle() + + let expected = "pb".startIndex..<"pb".endIndex + #expect(sut.needleSelection == expected) + } }