mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-05-24 05:40:15 +00:00
feat: select needle when reading from pasteboard
This commit is contained in:
@@ -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<String.Index>?
|
||||
|
||||
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..<needle.endIndex
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -377,7 +377,11 @@ extension Ghostty {
|
||||
var body: some View {
|
||||
GeometryReader { geo in
|
||||
HStack(spacing: 4) {
|
||||
TextField("Search", text: $searchState.needle)
|
||||
BackportSelectionTextField(
|
||||
"Search",
|
||||
text: $searchState.needle,
|
||||
selection: $searchState.needleSelection
|
||||
)
|
||||
.textFieldStyle(.plain)
|
||||
.frame(width: 180)
|
||||
.padding(.leading, 8)
|
||||
|
||||
@@ -131,3 +131,49 @@ enum BackportNSGlassStyle {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Backported `TextField` that supports text selection on macOS 15 and up. The `selection` has no
|
||||
/// effect on versions below macOS 15.
|
||||
struct BackportSelectionTextField: View {
|
||||
private let titleKey: LocalizedStringKey
|
||||
@Binding private var text: String
|
||||
@Binding private var textSelection: Range<String.Index>?
|
||||
|
||||
init(
|
||||
_ titleKey: LocalizedStringKey,
|
||||
text: Binding<String>,
|
||||
selection: Binding<Range<String.Index>?>
|
||||
) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user