Skip to content

Commit c36bf60

Browse files
committed
Use visibleRect to compute visible character ranges; add textRange(in:) helper
- Derive visibleCharacterRanges and accessibilityVisibleCharacterRange from contentView.visibleRect via NSTextLayoutManager.textRange(in:) instead of viewportRange for more accurate results. - Add NSTextLayoutManager.textRange(in:) to map a rect to a text range. - Minor cleanup: rename local var to viewportLayoutController and make liveResizeLayoutSuppression private.
1 parent 1a6f355 commit c36bf60

5 files changed

Lines changed: 18 additions & 8 deletions

File tree

Sources/STTextViewAppKit/STTextFinderClient.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,15 @@ final class STTextFinderClient: NSObject, NSTextFinderClient {
140140

141141
/// An array of visible character ranges.
142142
var visibleCharacterRanges: [NSValue] {
143-
guard let textLayoutManager = textView?.textLayoutManager,
144-
let viewportTextRange = textLayoutManager.textViewportLayoutController.viewportRange,
143+
guard let contentViewVisibleRect = textView?.contentView.visibleRect,
144+
let textLayoutManager = textView?.textLayoutManager,
145+
let visibleTextRange = textLayoutManager.textRange(in: contentViewVisibleRect),
145146
let textContentManager = textLayoutManager.textContentManager
146147
else {
147148
return []
148149
}
149150

150-
return [NSRange(viewportTextRange, in: textContentManager).nsValue]
151+
return [NSRange(visibleTextRange, in: textContentManager).nsValue]
151152
}
152153

153154
func rects(forCharacterRange range: NSRange) -> [NSValue]? {

Sources/STTextViewAppKit/STTextView+Accessibility.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ extension STTextView {
113113
// NSAccessibilityStaticText
114114

115115
override open func accessibilityVisibleCharacterRange() -> NSRange {
116-
if let viewportRange = textLayoutManager.textViewportLayoutController.viewportRange {
117-
return NSRange(viewportRange, in: textContentManager)
116+
if let visibleTextRange = textLayoutManager.textRange(in: contentView.visibleRect) {
117+
return NSRange(visibleTextRange, in: textContentManager)
118118
}
119119

120120
return NSRange()

Sources/STTextViewAppKit/STTextView+Scrolling.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ extension STTextView {
1212

1313
@discardableResult
1414
func scrollToVisible(_ textRange: NSTextRange, type: NSTextLayoutManager.SegmentType) -> Bool {
15-
let controller = textLayoutManager.textViewportLayoutController
15+
let viewportLayoutController = textLayoutManager.textViewportLayoutController
1616

1717
// Ensure layout for the target range before computing its rect
1818
textLayoutManager.ensureLayout(for: textRange)
1919

2020
// If the range is outside the current viewport, relocate the viewport anchor
2121
// so that TextKit2 lays out around the target location (O(1) jump)
2222
let isInViewport: Bool
23-
if let viewportRange = controller.viewportRange {
23+
if let viewportRange = viewportLayoutController.viewportRange {
2424
if textRange.isEmpty {
2525
isInViewport = viewportRange.contains(textRange.location)
2626
} else {

Sources/STTextViewAppKit/STTextView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ open class STTextView: NSView, NSTextInput, NSTextContent, STTextViewProtocol {
619619
}
620620
}
621621

622-
var liveResizeLayoutSuppression = false
622+
private var liveResizeLayoutSuppression = false
623623
private var inLayout = false
624624
private var needsRelayout = false
625625

Sources/STTextViewCommon/Extensions/NSTextLayoutManager+Selection.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,13 @@ package extension NSTextLayoutManager {
9393
}
9494
return attributedString
9595
}
96+
97+
/// Return text range that intesect the rect
98+
func textRange(in rect: CGRect) -> NSTextRange? {
99+
if let startLocation = self.caretLocation(interactingAt: CGPoint(x: rect.minX, y: rect.minY), options: .allowOutside, inContainerAt: documentRange.location) {
100+
let endLocation = self.caretLocation(interactingAt: CGPoint(x: rect.maxX, y: rect.maxY), options: .allowOutside, inContainerAt: documentRange.location)
101+
return NSTextRange(location: startLocation, end: endLocation)
102+
}
103+
return nil
104+
}
96105
}

0 commit comments

Comments
 (0)