@@ -9,56 +9,42 @@ import Foundation
99
1010extension TextSelectionManager {
1111 /// Calculate a set of rects for a text selection suitable for filling with the selection color to indicate a
12- /// multi-line selection.
13- ///
14- /// The returned rects are inset by edge insets passed to the text view, the given `rect` parameter can be the 'raw'
15- /// rect to draw in, no need to inset it before this method call.
12+ /// multi-line selection. The returned rects surround all selected line fragments for the given selection,
13+ /// following the available text layout space, rather than the available selection layout space.
1614 ///
1715 /// - Parameters:
1816 /// - rect: The bounding rect of available draw space.
1917 /// - textSelection: The selection to use.
2018 /// - Returns: An array of rects that the selection overlaps.
2119 func getFillRects( in rect: NSRect , for textSelection: TextSelection ) -> [ CGRect ] {
22- guard let layoutManager else { return [ ] }
23- let range = textSelection. range
24-
25- var fillRects : [ CGRect ] = [ ]
26- guard let firstLinePosition = layoutManager. lineStorage. getLine ( atOffset: range. location) ,
27- let lastLinePosition = range. max == layoutManager. lineStorage. length
28- ? layoutManager. lineStorage. last
29- : layoutManager. lineStorage. getLine ( atOffset: range. max) else {
20+ guard let layoutManager,
21+ let range = textSelection. range. intersection ( textView? . visibleTextRange ?? . zero) else {
3022 return [ ]
3123 }
3224
33- let insetXPos = max ( edgeInsets. left, rect. minX)
34- let insetWidth = max ( 0 , rect. maxX - insetXPos - edgeInsets. right)
35- let insetRect = NSRect ( x: insetXPos, y: rect. origin. y, width: insetWidth, height: rect. height)
36-
37- // Calculate the first line and any rects selected
38- // If the last line position is not the same as the first, calculate any rects from that line.
39- // If there's > 0 space between the first and last positions, add a rect between them to cover any
40- // intermediate lines.
25+ var fillRects : [ CGRect ] = [ ]
4126
42- let firstLineRects = getFillRects ( in: rect, selectionRange: range, forPosition: firstLinePosition)
43- let lastLineRects : [ CGRect ] = if lastLinePosition. range != firstLinePosition. range {
44- getFillRects ( in: rect, selectionRange: range, forPosition: lastLinePosition)
27+ let textWidth = if layoutManager. maxLineLayoutWidth == . greatestFiniteMagnitude {
28+ layoutManager. maxLineWidth
4529 } else {
46- [ ]
30+ layoutManager . maxLineLayoutWidth
4731 }
32+ let maxWidth = max ( textWidth, layoutManager. wrapLinesWidth)
33+ let validTextDrawingRect = CGRect (
34+ x: layoutManager. edgeInsets. left,
35+ y: rect. minY,
36+ width: maxWidth,
37+ height: rect. height
38+ ) . intersection ( rect)
4839
49- fillRects. append ( contentsOf: firstLineRects + lastLineRects)
50-
51- if firstLinePosition. yPos + firstLinePosition. height < lastLinePosition. yPos {
52- fillRects. append ( CGRect (
53- x: insetXPos,
54- y: firstLinePosition. yPos + firstLinePosition. height,
55- width: insetWidth,
56- height: lastLinePosition. yPos - ( firstLinePosition. yPos + firstLinePosition. height)
57- ) )
40+ for linePosition in layoutManager. lineStorage. linesInRange ( range) {
41+ fillRects. append (
42+ contentsOf: getFillRects ( in: validTextDrawingRect, selectionRange: range, forPosition: linePosition)
43+ )
5844 }
5945
6046 // Pixel align these to avoid aliasing on the edges of each rect that should be a solid box.
61- return fillRects. map { $0. intersection ( insetRect ) . pixelAligned }
47+ return fillRects. map { $0. intersection ( validTextDrawingRect ) . pixelAligned }
6248 }
6349
6450 /// Find fill rects for a specific line position.
0 commit comments