@@ -36,8 +36,8 @@ package extension TextSelectionManager {
36
36
return extendSelectionVerticalCharacter ( from: offset, up: up, suggestedXPos: suggestedXPos)
37
37
case . word, . line, . visualLine:
38
38
return extendSelectionVerticalLine ( from: offset, up: up)
39
- case . container :
40
- return extendSelectionContainer ( from: offset, delta: up ? 1 : - 1 )
39
+ case . page :
40
+ return extendSelectionPage ( from: offset, delta: up ? 1 : - 1 , suggestedXPos : suggestedXPos )
41
41
case . document:
42
42
if up {
43
43
return NSRange ( location: 0 , length: offset)
@@ -61,7 +61,7 @@ package extension TextSelectionManager {
61
61
guard let point = layoutManager? . rectForOffset ( offset) ? . origin,
62
62
let newOffset = layoutManager? . textOffsetAtPoint (
63
63
CGPoint (
64
- x: suggestedXPos == nil ? point. x : suggestedXPos! ,
64
+ x: suggestedXPos ?? point. x,
65
65
y: point. y - ( layoutManager? . estimateLineHeight ( ) ?? 2.0 ) / 2 * ( up ? 1 : - 3 )
66
66
)
67
67
) else {
@@ -115,22 +115,36 @@ package extension TextSelectionManager {
115
115
}
116
116
}
117
117
118
- /// Extends a selection one "container " long.
118
+ /// Extends a selection one "page " long.
119
119
/// - Parameters:
120
120
/// - offset: The location to start extending the selection from.
121
121
/// - delta: The direction the selection should be extended. `1` for forwards, `-1` for backwards.
122
122
/// - Returns: The range of the extended selection.
123
- private func extendSelectionContainer( from offset: Int , delta: Int ) -> NSRange {
124
- guard let textView, let endOffset = layoutManager? . textOffsetAtPoint (
125
- CGPoint (
126
- x: delta > 0 ? textView. frame. maxX : textView. frame. minX,
127
- y: delta > 0 ? textView. frame. maxY : textView. frame. minY
128
- )
129
- ) else {
123
+ private func extendSelectionPage( from offset: Int , delta: Int , suggestedXPos: CGFloat ? ) -> NSRange {
124
+ guard let textView = textView,
125
+ let layoutManager,
126
+ let currentYPos = layoutManager. rectForOffset ( offset) ? . origin. y else {
130
127
return NSRange ( location: offset, length: 0 )
131
128
}
132
- return endOffset > offset
133
- ? NSRange ( location: offset, length: endOffset - offset)
134
- : NSRange ( location: endOffset, length: offset - endOffset)
129
+
130
+ let pageHeight = textView. visibleRect. height
131
+
132
+ // Grab the line where the next selection should be. Then use the suggestedXPos to find where in the line the
133
+ // selection should be extended to.
134
+ layoutManager. layoutLines (
135
+ in: NSRect ( x: 0 , y: currentYPos, width: layoutManager. maxLineWidth, height: pageHeight)
136
+ )
137
+ guard let nextPageOffset = layoutManager. textOffsetAtPoint ( CGPoint (
138
+ x: suggestedXPos ?? 0 ,
139
+ y: min ( textView. frame. height, max ( 0 , currentYPos + ( delta > 0 ? - pageHeight : pageHeight) ) )
140
+ ) ) else {
141
+ return NSRange ( location: offset, length: 0 )
142
+ }
143
+
144
+ if delta > 0 {
145
+ return NSRange ( location: nextPageOffset, length: offset - nextPageOffset)
146
+ } else {
147
+ return NSRange ( location: offset, length: nextPageOffset - offset)
148
+ }
135
149
}
136
150
}
0 commit comments