@@ -67,7 +67,7 @@ extension TextViewController {
67
67
var selectionIndex = 0
68
68
textView. editSelections { textView, selection in
69
69
// get lineindex, i.e line-numbers+1
70
- guard let lineIndexes = getHighlightedLines ( for: selection. range) else { return }
70
+ guard let lineIndexes = getOverlappingLines ( for: selection. range) else { return }
71
71
72
72
adjustIndentation ( lineIndexes: lineIndexes, inwards: inwards)
73
73
@@ -129,7 +129,24 @@ extension TextViewController {
129
129
return false
130
130
}
131
131
132
- private func getHighlightedLines( for range: NSRange ) -> ClosedRange < Int > ? {
132
+ /// Find the range of lines overlapping a text range.
133
+ ///
134
+ /// Use this method to determine what lines to apply a text transformation on using a text selection. For instance,
135
+ /// when indenting a selected line.
136
+ ///
137
+ /// Does not determine the *visible* lines, which is a very slight change from most
138
+ /// ``CodeEditTextView/TextLayoutManager`` APIs.
139
+ /// Given the text:
140
+ /// ```
141
+ /// A
142
+ /// B
143
+ /// ```
144
+ /// This method will return lines `0...0` for the text range `0..<2`. The layout manager might return lines
145
+ /// `0...1`, as the text range contains the newline, which appears *visually* in line index `1`.
146
+ ///
147
+ /// - Parameter range: The text range in the document to find contained lines for.
148
+ /// - Returns: A closed range of line indexes (0-indexed) where each line is overlapping the given text range.
149
+ func getOverlappingLines( for range: NSRange ) -> ClosedRange < Int > ? {
133
150
guard let startLineInfo = textView. layoutManager. textLineForOffset ( range. lowerBound) else {
134
151
return nil
135
152
}
@@ -139,7 +156,16 @@ extension TextViewController {
139
156
return startLineInfo. index... startLineInfo. index
140
157
}
141
158
142
- return startLineInfo. index... endLineInfo. index
159
+ // If we've selected up to the start of a line (just over the newline character), the layout manager tells us
160
+ // we've selected the next line. However, we aren't overlapping the *text line* with that range, so we
161
+ // decrement it if it's not the end of the document
162
+ var endLineIndex = endLineInfo. index
163
+ if endLineInfo. range. lowerBound == range. upperBound
164
+ && endLineInfo. index != textView. layoutManager. lineCount - 1 {
165
+ endLineIndex -= 1
166
+ }
167
+
168
+ return startLineInfo. index... endLineIndex
143
169
}
144
170
145
171
private func adjustIndentation( lineIndexes: ClosedRange < Int > , inwards: Bool ) {
0 commit comments