@@ -12,6 +12,7 @@ import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/v
1212import { DomReadingContext , ViewLine , ViewLineOptions } from 'vs/editor/browser/viewParts/lines/viewLine' ;
1313import { Position } from 'vs/editor/common/core/position' ;
1414import { Range } from 'vs/editor/common/core/range' ;
15+ import { Selection } from 'vs/editor/common/core/selection' ;
1516import { ScrollType } from 'vs/editor/common/editorCommon' ;
1617import { IViewLines , LineVisibleRanges , VisibleRanges , HorizontalPosition } from 'vs/editor/common/view/renderingContext' ;
1718import { ViewContext } from 'vs/editor/common/view/viewContext' ;
@@ -38,25 +39,49 @@ class LastRenderedData {
3839 }
3940}
4041
41- class HorizontalRevealRequest {
42-
43- public readonly lineNumber : number ;
44- public readonly startColumn : number ;
45- public readonly endColumn : number ;
46- public readonly startScrollTop : number ;
47- public readonly stopScrollTop : number ;
48- public readonly scrollType : ScrollType ;
42+ class HorizontalRevealRangeRequest {
43+ public readonly type = 'range' ;
44+ public readonly minLineNumber : number ;
45+ public readonly maxLineNumber : number ;
46+
47+ constructor (
48+ public readonly lineNumber : number ,
49+ public readonly startColumn : number ,
50+ public readonly endColumn : number ,
51+ public readonly startScrollTop : number ,
52+ public readonly stopScrollTop : number ,
53+ public readonly scrollType : ScrollType
54+ ) {
55+ this . minLineNumber = lineNumber ;
56+ this . maxLineNumber = lineNumber ;
57+ }
58+ }
4959
50- constructor ( lineNumber : number , startColumn : number , endColumn : number , startScrollTop : number , stopScrollTop : number , scrollType : ScrollType ) {
51- this . lineNumber = lineNumber ;
52- this . startColumn = startColumn ;
53- this . endColumn = endColumn ;
54- this . startScrollTop = startScrollTop ;
55- this . stopScrollTop = stopScrollTop ;
56- this . scrollType = scrollType ;
60+ class HorizontalRevealSelectionsRequest {
61+ public readonly type = 'selections' ;
62+ public readonly minLineNumber : number ;
63+ public readonly maxLineNumber : number ;
64+
65+ constructor (
66+ public readonly selections : Selection [ ] ,
67+ public readonly startScrollTop : number ,
68+ public readonly stopScrollTop : number ,
69+ public readonly scrollType : ScrollType
70+ ) {
71+ let minLineNumber = selections [ 0 ] . startLineNumber ;
72+ let maxLineNumber = selections [ 0 ] . endLineNumber ;
73+ for ( let i = 1 , len = selections . length ; i < len ; i ++ ) {
74+ const selection = selections [ i ] ;
75+ minLineNumber = Math . min ( minLineNumber , selection . startLineNumber ) ;
76+ maxLineNumber = Math . max ( maxLineNumber , selection . endLineNumber ) ;
77+ }
78+ this . minLineNumber = minLineNumber ;
79+ this . maxLineNumber = maxLineNumber ;
5780 }
5881}
5982
83+ type HorizontalRevealRequest = HorizontalRevealRangeRequest | HorizontalRevealSelectionsRequest ;
84+
6085export class ViewLines extends ViewPart implements IVisibleLinesHost < ViewLine > , IViewLines {
6186 /**
6287 * Adds this amount of pixels to the right of lines (no-one wants to type near the edge of the viewport)
@@ -221,21 +246,28 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
221246 public onRevealRangeRequest ( e : viewEvents . ViewRevealRangeRequestEvent ) : boolean {
222247 // Using the future viewport here in order to handle multiple
223248 // incoming reveal range requests that might all desire to be animated
224- const desiredScrollTop = this . _computeScrollTopToRevealRange ( this . _context . viewLayout . getFutureViewport ( ) , e . source , e . range , e . verticalType ) ;
249+ const desiredScrollTop = this . _computeScrollTopToRevealRange ( this . _context . viewLayout . getFutureViewport ( ) , e . source , e . range , e . selections , e . verticalType ) ;
250+
251+ if ( desiredScrollTop === - 1 ) {
252+ // marker to abort the reveal range request
253+ return false ;
254+ }
225255
226256 // validate the new desired scroll top
227257 let newScrollPosition = this . _context . viewLayout . validateScrollPosition ( { scrollTop : desiredScrollTop } ) ;
228258
229259 if ( e . revealHorizontal ) {
230- if ( e . range . startLineNumber !== e . range . endLineNumber ) {
260+ if ( e . range && e . range . startLineNumber !== e . range . endLineNumber ) {
231261 // Two or more lines? => scroll to base (That's how you see most of the two lines)
232262 newScrollPosition = {
233263 scrollTop : newScrollPosition . scrollTop ,
234264 scrollLeft : 0
235265 } ;
236- } else {
266+ } else if ( e . range ) {
237267 // We don't necessarily know the horizontal offset of this range since the line might not be in the view...
238- this . _horizontalRevealRequest = new HorizontalRevealRequest ( e . range . startLineNumber , e . range . startColumn , e . range . endColumn , this . _context . viewLayout . getCurrentScrollTop ( ) , newScrollPosition . scrollTop , e . scrollType ) ;
268+ this . _horizontalRevealRequest = new HorizontalRevealRangeRequest ( e . range . startLineNumber , e . range . startColumn , e . range . endColumn , this . _context . viewLayout . getCurrentScrollTop ( ) , newScrollPosition . scrollTop , e . scrollType ) ;
269+ } else if ( e . selections && e . selections . length > 0 ) {
270+ this . _horizontalRevealRequest = new HorizontalRevealSelectionsRequest ( e . selections , this . _context . viewLayout . getCurrentScrollTop ( ) , newScrollPosition . scrollTop , e . scrollType ) ;
239271 }
240272 } else {
241273 this . _horizontalRevealRequest = null ;
@@ -501,37 +533,34 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
501533 // - it might change `scrollWidth` and `scrollLeft`
502534 if ( this . _horizontalRevealRequest ) {
503535
504- const revealLineNumber = this . _horizontalRevealRequest . lineNumber ;
505- const revealStartColumn = this . _horizontalRevealRequest . startColumn ;
506- const revealEndColumn = this . _horizontalRevealRequest . endColumn ;
507- const scrollType = this . _horizontalRevealRequest . scrollType ;
536+ const horizontalRevealRequest = this . _horizontalRevealRequest ;
508537
509538 // Check that we have the line that contains the horizontal range in the viewport
510- if ( viewportData . startLineNumber <= revealLineNumber && revealLineNumber <= viewportData . endLineNumber ) {
539+ if ( viewportData . startLineNumber <= horizontalRevealRequest . minLineNumber && horizontalRevealRequest . maxLineNumber <= viewportData . endLineNumber ) {
511540
512541 this . _horizontalRevealRequest = null ;
513542
514543 // allow `visibleRangesForRange2` to work
515544 this . onDidRender ( ) ;
516545
517546 // compute new scroll position
518- const newScrollLeft = this . _computeScrollLeftToRevealRange ( revealLineNumber , revealStartColumn , revealEndColumn ) ;
519-
520- const isViewportWrapping = this . _isViewportWrapping ;
521- if ( ! isViewportWrapping ) {
522- // ensure `scrollWidth` is large enough
523- this . _ensureMaxLineWidth ( newScrollLeft . maxHorizontalOffset ) ;
524- }
525-
526- // set `scrollLeft`
527- if ( scrollType === ScrollType . Smooth ) {
528- this . _context . viewLayout . setScrollPositionSmooth ( {
529- scrollLeft : newScrollLeft . scrollLeft
530- } ) ;
531- } else {
532- this . _context . viewLayout . setScrollPositionNow ( {
533- scrollLeft : newScrollLeft . scrollLeft
534- } ) ;
547+ const newScrollLeft = this . _computeScrollLeftToReveal ( horizontalRevealRequest ) ;
548+
549+ if ( newScrollLeft ) {
550+ if ( ! this . _isViewportWrapping ) {
551+ // ensure `scrollWidth` is large enough
552+ this . _ensureMaxLineWidth ( newScrollLeft . maxHorizontalOffset ) ;
553+ }
554+ // set `scrollLeft`
555+ if ( horizontalRevealRequest . scrollType === ScrollType . Smooth ) {
556+ this . _context . viewLayout . setScrollPositionSmooth ( {
557+ scrollLeft : newScrollLeft . scrollLeft
558+ } ) ;
559+ } else {
560+ this . _context . viewLayout . setScrollPositionNow ( {
561+ scrollLeft : newScrollLeft . scrollLeft
562+ } ) ;
563+ }
535564 }
536565 }
537566 }
@@ -560,16 +589,33 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
560589 }
561590 }
562591
563- private _computeScrollTopToRevealRange ( viewport : Viewport , source : string , range : Range , verticalType : viewEvents . VerticalRevealType ) : number {
592+ private _computeScrollTopToRevealRange ( viewport : Viewport , source : string , range : Range | null , selections : Selection [ ] | null , verticalType : viewEvents . VerticalRevealType ) : number {
564593 const viewportStartY = viewport . top ;
565594 const viewportHeight = viewport . height ;
566595 const viewportEndY = viewportStartY + viewportHeight ;
596+ let boxIsSingleRange : boolean ;
567597 let boxStartY : number ;
568598 let boxEndY : number ;
569599
570600 // Have a box that includes one extra line height (for the horizontal scrollbar)
571- boxStartY = this . _context . viewLayout . getVerticalOffsetForLineNumber ( range . startLineNumber ) ;
572- boxEndY = this . _context . viewLayout . getVerticalOffsetForLineNumber ( range . endLineNumber ) + this . _lineHeight ;
601+ if ( selections && selections . length > 0 ) {
602+ let minLineNumber = selections [ 0 ] . startLineNumber ;
603+ let maxLineNumber = selections [ 0 ] . endLineNumber ;
604+ for ( let i = 1 , len = selections . length ; i < len ; i ++ ) {
605+ const selection = selections [ i ] ;
606+ minLineNumber = Math . min ( minLineNumber , selection . startLineNumber ) ;
607+ maxLineNumber = Math . max ( maxLineNumber , selection . endLineNumber ) ;
608+ }
609+ boxIsSingleRange = false ;
610+ boxStartY = this . _context . viewLayout . getVerticalOffsetForLineNumber ( minLineNumber ) ;
611+ boxEndY = this . _context . viewLayout . getVerticalOffsetForLineNumber ( maxLineNumber ) + this . _lineHeight ;
612+ } else if ( range ) {
613+ boxIsSingleRange = true ;
614+ boxStartY = this . _context . viewLayout . getVerticalOffsetForLineNumber ( range . startLineNumber ) ;
615+ boxEndY = this . _context . viewLayout . getVerticalOffsetForLineNumber ( range . endLineNumber ) + this . _lineHeight ;
616+ } else {
617+ return - 1 ;
618+ }
573619
574620 const shouldIgnoreScrollOff = source === 'mouse' && this . _cursorSurroundingLinesStyle === 'default' ;
575621
@@ -588,6 +634,10 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
588634
589635 if ( boxEndY - boxStartY > viewportHeight ) {
590636 // the box is larger than the viewport ... scroll to its top
637+ if ( ! boxIsSingleRange ) {
638+ // do not reveal multiple cursors if there are more than fit the viewport
639+ return - 1 ;
640+ }
591641 newScrollTop = boxStartY ;
592642 } else if ( verticalType === viewEvents . VerticalRevealType . NearTop || verticalType === viewEvents . VerticalRevealType . NearTopIfOutsideViewport ) {
593643 if ( verticalType === viewEvents . VerticalRevealType . NearTopIfOutsideViewport && viewportStartY <= boxStartY && boxEndY <= viewportEndY ) {
@@ -618,44 +668,50 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
618668 return newScrollTop ;
619669 }
620670
621- private _computeScrollLeftToRevealRange ( lineNumber : number , startColumn : number , endColumn : number ) : { scrollLeft : number ; maxHorizontalOffset : number ; } {
622-
623- let maxHorizontalOffset = 0 ;
671+ private _computeScrollLeftToReveal ( horizontalRevealRequest : HorizontalRevealRequest ) : { scrollLeft : number ; maxHorizontalOffset : number ; } | null {
624672
625673 const viewport = this . _context . viewLayout . getCurrentViewport ( ) ;
626674 const viewportStartX = viewport . left ;
627675 const viewportEndX = viewportStartX + viewport . width ;
628676
629- const visibleRanges = this . _visibleRangesForLineRange ( lineNumber , startColumn , endColumn ) ;
630677 let boxStartX = Constants . MAX_SAFE_SMALL_INTEGER ;
631678 let boxEndX = 0 ;
632-
633- if ( ! visibleRanges ) {
634- // Unknown
635- return {
636- scrollLeft : viewportStartX ,
637- maxHorizontalOffset : maxHorizontalOffset
638- } ;
639- }
640-
641- for ( const visibleRange of visibleRanges . ranges ) {
642- if ( visibleRange . left < boxStartX ) {
643- boxStartX = visibleRange . left ;
679+ if ( horizontalRevealRequest . type === 'range' ) {
680+ const visibleRanges = this . _visibleRangesForLineRange ( horizontalRevealRequest . lineNumber , horizontalRevealRequest . startColumn , horizontalRevealRequest . endColumn ) ;
681+ if ( ! visibleRanges ) {
682+ return null ;
683+ }
684+ for ( const visibleRange of visibleRanges . ranges ) {
685+ boxStartX = Math . min ( boxStartX , visibleRange . left ) ;
686+ boxEndX = Math . max ( boxEndX , visibleRange . left + visibleRange . width ) ;
644687 }
645- if ( visibleRange . left + visibleRange . width > boxEndX ) {
646- boxEndX = visibleRange . left + visibleRange . width ;
688+ } else {
689+ for ( const selection of horizontalRevealRequest . selections ) {
690+ if ( selection . startLineNumber !== selection . endLineNumber ) {
691+ return null ;
692+ }
693+ const visibleRanges = this . _visibleRangesForLineRange ( selection . startLineNumber , selection . startColumn , selection . endColumn ) ;
694+ if ( ! visibleRanges ) {
695+ return null ;
696+ }
697+ for ( const visibleRange of visibleRanges . ranges ) {
698+ boxStartX = Math . min ( boxStartX , visibleRange . left ) ;
699+ boxEndX = Math . max ( boxEndX , visibleRange . left + visibleRange . width ) ;
700+ }
647701 }
648702 }
649703
650- maxHorizontalOffset = boxEndX ;
651-
652704 boxStartX = Math . max ( 0 , boxStartX - ViewLines . HORIZONTAL_EXTRA_PX ) ;
653705 boxEndX += this . _revealHorizontalRightPadding ;
654706
707+ if ( horizontalRevealRequest . type === 'selections' && boxEndX - boxStartX > viewport . width ) {
708+ return null ;
709+ }
710+
655711 const newScrollLeft = this . _computeMinimumScrolling ( viewportStartX , viewportEndX , boxStartX , boxEndX ) ;
656712 return {
657713 scrollLeft : newScrollLeft ,
658- maxHorizontalOffset : maxHorizontalOffset
714+ maxHorizontalOffset : boxEndX
659715 } ;
660716 }
661717
0 commit comments