@@ -222,7 +222,9 @@ static IEnumerable<Rect> ProcessTextLines(TextView textView, VisualLine visualLi
222222 double y = visualLine . GetTextLineVisualYPosition ( line , VisualYPosition . LineTop ) ;
223223 int visualStartCol = visualLine . GetTextLineVisualStartColumn ( line ) ;
224224 int visualEndCol = visualStartCol + line . Length ;
225- if ( line != lastTextLine )
225+ if ( line == lastTextLine )
226+ visualEndCol -= 1 ; // 1 position for the TextEndOfParagraph
227+ else
226228 visualEndCol -= line . TrailingWhitespaceLength ;
227229
228230 if ( segmentEndVC < visualStartCol )
@@ -232,6 +234,7 @@ static IEnumerable<Rect> ProcessTextLines(TextView textView, VisualLine visualLi
232234 int segmentStartVCInLine = Math . Max ( segmentStartVC , visualStartCol ) ;
233235 int segmentEndVCInLine = Math . Min ( segmentEndVC , visualEndCol ) ;
234236 y -= scrollOffset . Y ;
237+ Rect lastRect = Rect . Empty ;
235238 if ( segmentStartVCInLine == segmentEndVCInLine ) {
236239 // GetTextBounds crashes for length=0, so we'll handle this case with GetDistanceFromCharacterHit
237240 // We need to return a rectangle to ensure empty lines are still visible
@@ -244,9 +247,8 @@ static IEnumerable<Rect> ProcessTextLines(TextView textView, VisualLine visualLi
244247 continue ;
245248 if ( segmentStartVCInLine == visualStartCol && i > 0 && segmentStartVC < segmentStartVCInLine && visualLine . TextLines [ i - 1 ] . TrailingWhitespaceLength == 0 )
246249 continue ;
247- yield return new Rect ( pos , y , textView . EmptyLineSelectionWidth , line . Height ) ;
250+ lastRect = new Rect ( pos , y , textView . EmptyLineSelectionWidth , line . Height ) ;
248251 } else {
249- Rect lastRect = Rect . Empty ;
250252 if ( segmentStartVCInLine <= visualEndCol ) {
251253 foreach ( TextBounds b in line . GetTextBounds ( segmentStartVCInLine , segmentEndVCInLine - segmentStartVCInLine ) ) {
252254 double left = b . Rectangle . Left - scrollOffset . X ;
@@ -257,23 +259,45 @@ static IEnumerable<Rect> ProcessTextLines(TextView textView, VisualLine visualLi
257259 lastRect = new Rect ( Math . Min ( left , right ) , y , Math . Abs ( right - left ) , line . Height ) ;
258260 }
259261 }
260- if ( segmentEndVC >= visualLine . VisualLengthWithEndOfLineMarker ) {
261- double left = ( segmentStartVC > visualLine . VisualLengthWithEndOfLineMarker ? visualLine . GetTextLineVisualXPosition ( lastTextLine , segmentStartVC ) : line . WidthIncludingTrailingWhitespace ) - scrollOffset . X ;
262- double right = ( ( segmentEndVC == int . MaxValue || line != lastTextLine ) ? Math . Max ( ( ( IScrollInfo ) textView ) . ExtentWidth , ( ( IScrollInfo ) textView ) . ViewportWidth ) : visualLine . GetTextLineVisualXPosition ( lastTextLine , segmentEndVC ) ) - scrollOffset . X ;
263- Rect extendSelection = new Rect ( Math . Min ( left , right ) , y , Math . Abs ( right - left ) , line . Height ) ;
264- if ( ! lastRect . IsEmpty ) {
265- if ( extendSelection . IntersectsWith ( lastRect ) ) {
266- lastRect . Union ( extendSelection ) ;
267- yield return lastRect ;
268- } else {
269- yield return lastRect ;
270- yield return extendSelection ;
271- }
272- } else
262+ }
263+ // If the segment ends in virtual space, extend the last rectangle with the rectangle the portion of the selection
264+ // after the line end.
265+ // Also, when word-wrap is enabled and the segment continues into the next line, extend lastRect up to the end of the line.
266+ if ( segmentEndVC > visualEndCol ) {
267+ double left , right ;
268+ if ( segmentStartVC > visualLine . VisualLengthWithEndOfLineMarker ) {
269+ // segmentStartVC is in virtual space
270+ left = visualLine . GetTextLineVisualXPosition ( lastTextLine , segmentStartVC ) ;
271+ } else {
272+ // Otherwise, we already processed the rects from segmentStartVC up to visualEndCol,
273+ // so we only need to do the remainder starting at visualEndCol.
274+ // For word-wrapped lines, visualEndCol doesn't include the whitespace hidden by the wrap,
275+ // so we'll need to include it here.
276+ // For the last line, visualEndCol already includes the whitespace.
277+ left = ( line == lastTextLine ? line . WidthIncludingTrailingWhitespace : line . Width ) ;
278+ }
279+ if ( line != lastTextLine || segmentEndVC == int . MaxValue ) {
280+ // If word-wrap is enabled and the segment continues into the next line,
281+ // or if the extendToFullWidthAtLineEnd option is used (segmentEndVC == int.MaxValue),
282+ // we select the full width of the viewport.
283+ right = Math . Max ( ( ( IScrollInfo ) textView ) . ExtentWidth , ( ( IScrollInfo ) textView ) . ViewportWidth ) ;
284+ } else {
285+ right = visualLine . GetTextLineVisualXPosition ( lastTextLine , segmentEndVC ) ;
286+ }
287+ Rect extendSelection = new Rect ( Math . Min ( left , right ) , y , Math . Abs ( right - left ) , line . Height ) ;
288+ if ( ! lastRect . IsEmpty ) {
289+ if ( extendSelection . IntersectsWith ( lastRect ) ) {
290+ lastRect . Union ( extendSelection ) ;
291+ yield return lastRect ;
292+ } else {
293+ // If the end of the line is in an RTL segment, keep lastRect and extendSelection separate.
294+ yield return lastRect ;
273295 yield return extendSelection ;
296+ }
274297 } else
275- yield return lastRect ;
276- }
298+ yield return extendSelection ;
299+ } else
300+ yield return lastRect ;
277301 }
278302 }
279303
0 commit comments