@@ -20,6 +20,7 @@ import { CharacterMapping, RenderLineInput, renderViewLine } from '../../../comm
20
20
import { foldingCollapsedIcon , foldingExpandedIcon } from '../../folding/browser/foldingDecorations.js' ;
21
21
import { FoldingModel } from '../../folding/browser/foldingModel.js' ;
22
22
import { Emitter } from '../../../../base/common/event.js' ;
23
+ import { IViewModel } from '../../../common/viewModel.js' ;
23
24
24
25
export class StickyScrollWidgetState {
25
26
constructor (
@@ -58,7 +59,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
58
59
59
60
private readonly _editor : ICodeEditor ;
60
61
61
- private _previousState : StickyScrollWidgetState | undefined ;
62
+ private _state : StickyScrollWidgetState | undefined ;
62
63
private _lineHeight : number ;
63
64
private _renderedStickyLines : RenderedStickyLine [ ] = [ ] ;
64
65
private _lineNumbers : number [ ] = [ ] ;
@@ -142,49 +143,48 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
142
143
return this . _lineNumbers ;
143
144
}
144
145
145
- setState ( _state : StickyScrollWidgetState | undefined , foldingModel : FoldingModel | undefined , _rebuildFromLine ?: number ) : void {
146
- if ( _rebuildFromLine === undefined &&
147
- ( ( ! this . _previousState && ! _state ) || ( this . _previousState && this . _previousState . equals ( _state ) ) )
148
- ) {
146
+ setState ( state : StickyScrollWidgetState | undefined , foldingModel : FoldingModel | undefined , rebuildFromIndexCandidate ?: number ) : void {
147
+ const currentStateAndPreviousStateUndefined = ! this . _state && ! state ;
148
+ const currentStateDefinedAndEqualsPreviousState = this . _state && this . _state . equals ( state ) ;
149
+ if ( currentStateAndPreviousStateUndefined || currentStateDefinedAndEqualsPreviousState ) {
149
150
return ;
150
151
}
151
- const isWidgetHeightZero = this . _isWidgetHeightZero ( _state ) ;
152
- const state = isWidgetHeightZero ? undefined : _state ;
153
- const rebuildFromLine = isWidgetHeightZero ? 0 : this . _findLineToRebuildWidgetFrom ( _state , _rebuildFromLine ) ;
154
-
155
- this . _renderRootNode ( state , foldingModel , rebuildFromLine ) ;
156
- this . _previousState = _state ;
152
+ const data = this . _findRenderingData ( state ) ;
153
+ const previousLineNumbers = this . _lineNumbers ;
154
+ this . _lineNumbers = data . lineNumbers ;
155
+ this . _lastLineRelativePosition = data . lastLineRelativePosition ;
156
+ const rebuildFromIndex = this . _findIndexToRebuildFrom ( previousLineNumbers , this . _lineNumbers , rebuildFromIndexCandidate ) ;
157
+ this . _renderRootNode ( this . _lineNumbers , this . _lastLineRelativePosition , foldingModel , rebuildFromIndex ) ;
158
+ this . _state = state ;
157
159
}
158
160
159
- private _isWidgetHeightZero ( state : StickyScrollWidgetState | undefined ) : boolean {
161
+ private _findRenderingData ( state : StickyScrollWidgetState | undefined ) : { lineNumbers : number [ ] ; lastLineRelativePosition : number } {
160
162
if ( ! state ) {
161
- return true ;
163
+ return { lineNumbers : [ ] , lastLineRelativePosition : 0 } ;
162
164
}
163
- const futureWidgetHeight = this . _getHeightOfLines ( state . startLineNumbers , state . lastLineRelativePosition ) ;
164
- if ( futureWidgetHeight > 0 ) {
165
- this . _lastLineRelativePosition = state . lastLineRelativePosition ;
166
- const lineNumbers = [ ...state . startLineNumbers ] ;
167
- if ( state . showEndForLine !== null ) {
168
- lineNumbers [ state . showEndForLine ] = state . endLineNumbers [ state . showEndForLine ] ;
169
- }
170
- this . _lineNumbers = lineNumbers ;
171
- } else {
172
- this . _lastLineRelativePosition = 0 ;
173
- this . _lineNumbers = [ ] ;
165
+ const candidateLineNumbers = [ ...state . startLineNumbers ] ;
166
+ if ( state . showEndForLine !== null ) {
167
+ candidateLineNumbers [ state . showEndForLine ] = state . endLineNumbers [ state . showEndForLine ] ;
168
+ }
169
+ let totalHeight = 0 ;
170
+ for ( let i = 0 ; i < candidateLineNumbers . length ; i ++ ) {
171
+ totalHeight += this . _editor . getLineHeightForPosition ( new Position ( candidateLineNumbers [ i ] , 1 ) ) ;
174
172
}
175
- return futureWidgetHeight === 0 ;
173
+ if ( totalHeight === 0 ) {
174
+ return { lineNumbers : [ ] , lastLineRelativePosition : 0 } ;
175
+ }
176
+ return { lineNumbers : candidateLineNumbers , lastLineRelativePosition : state . lastLineRelativePosition } ;
176
177
}
177
178
178
- private _findLineToRebuildWidgetFrom ( state : StickyScrollWidgetState | undefined , _rebuildFromLine ?: number ) : number {
179
- if ( ! state || ! this . _previousState ) {
179
+ private _findIndexToRebuildFrom ( previousLineNumbers : number [ ] , newLineNumbers : number [ ] , rebuildFromIndexCandidate ?: number ) : number {
180
+ if ( newLineNumbers . length === 0 ) {
180
181
return 0 ;
181
182
}
182
- if ( _rebuildFromLine !== undefined ) {
183
- return _rebuildFromLine ;
183
+ if ( rebuildFromIndexCandidate !== undefined ) {
184
+ return rebuildFromIndexCandidate ;
184
185
}
185
- const previousState = this . _previousState ;
186
- const indexOfLinesAlreadyRendered = state . startLineNumbers . findIndex ( startLineNumber => ! previousState . startLineNumbers . includes ( startLineNumber ) ) ;
187
- return ( indexOfLinesAlreadyRendered === - 1 ) ? 0 : indexOfLinesAlreadyRendered ;
186
+ const validIndex = newLineNumbers . findIndex ( startLineNumber => ! previousLineNumbers . includes ( startLineNumber ) ) ;
187
+ return validIndex === - 1 ? 0 : validIndex ;
188
188
}
189
189
190
190
private _updateWidgetWidth ( ) : void {
@@ -195,18 +195,6 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
195
195
this . _rootDomNode . style . width = `${ layoutInfo . width - layoutInfo . verticalScrollbarWidth } px` ;
196
196
}
197
197
198
- private _clearStickyLinesFromLine ( clearFromLine : number ) {
199
- this . _foldingIconStore . clear ( ) ;
200
- // Removing only the lines that need to be rerendered
201
- for ( let i = clearFromLine ; i < this . _renderedStickyLines . length ; i ++ ) {
202
- const stickyLine = this . _renderedStickyLines [ i ] ;
203
- stickyLine . lineNumberDomNode . remove ( ) ;
204
- stickyLine . lineDomNode . remove ( ) ;
205
- }
206
- // Keep the lines that need to be updated
207
- this . _renderedStickyLines = this . _renderedStickyLines . slice ( 0 , clearFromLine ) ;
208
- }
209
-
210
198
private _useFoldingOpacityTransition ( requireTransitions : boolean ) {
211
199
this . _lineNumbersDomNode . style . setProperty ( '--vscode-editorStickyScroll-foldingOpacityTransition' , `opacity ${ requireTransitions ? 0.5 : 0 } s` ) ;
212
200
}
@@ -221,51 +209,55 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
221
209
}
222
210
}
223
211
224
- private async _renderRootNode ( state : StickyScrollWidgetState | undefined , foldingModel : FoldingModel | undefined , rebuildFromLine : number ) : Promise < void > {
225
- this . _clearStickyLinesFromLine ( rebuildFromLine ) ;
226
- if ( ! state ) {
227
- // make sure the dom is 0 height and display:none
228
- this . _setHeight ( 0 ) ;
212
+ private async _renderRootNode ( lineNumbers : number [ ] , lastLineRelativePosition : number , foldingModel : FoldingModel | undefined , rebuildFromIndex : number ) : Promise < void > {
213
+ const viewModel = this . _editor . _getViewModel ( ) ;
214
+ if ( ! viewModel ) {
215
+ this . _clearWidget ( ) ;
216
+ return ;
217
+ }
218
+ if ( lineNumbers . length === 0 ) {
219
+ this . _clearWidget ( ) ;
229
220
return ;
230
221
}
222
+ const renderedStickyLines : RenderedStickyLine [ ] = [ ] ;
223
+ const lastLineNumber = lineNumbers [ lineNumbers . length - 1 ] ;
231
224
let top : number = 0 ;
232
- // For existing sticky lines update the top and z-index
233
- for ( const stickyLine of this . _renderedStickyLines ) {
234
- this . _updatePosition ( stickyLine , top ) ;
235
- top += stickyLine . height ;
225
+ for ( let i = 0 ; i < this . _renderedStickyLines . length ; i ++ ) {
226
+ if ( i < rebuildFromIndex ) {
227
+ const renderedLine = this . _renderedStickyLines [ i ] ;
228
+ renderedStickyLines . push ( this . _updatePosition ( renderedLine , top , renderedLine . lineNumber === lastLineNumber ) ) ;
229
+ top += renderedLine . height ;
230
+ } else {
231
+ const renderedLine = this . _renderedStickyLines [ i ] ;
232
+ renderedLine . lineNumberDomNode . remove ( ) ;
233
+ renderedLine . lineDomNode . remove ( ) ;
234
+ }
236
235
}
237
- // For new sticky lines
238
236
const layoutInfo = this . _editor . getLayoutInfo ( ) ;
239
- const linesToRender = this . _lineNumbers . slice ( rebuildFromLine ) ;
240
- for ( const [ index , line ] of linesToRender . entries ( ) ) {
241
- const stickyLine = this . _renderChildNode ( index + rebuildFromLine , line , top , foldingModel , layoutInfo ) ;
242
- if ( ! stickyLine ) {
243
- continue ;
244
- }
237
+ for ( let i = rebuildFromIndex ; i < lineNumbers . length ; i ++ ) {
238
+ const stickyLine = this . _renderChildNode ( viewModel , i , lineNumbers [ i ] , top , lastLineNumber === lineNumbers [ i ] , foldingModel , layoutInfo ) ;
245
239
top += stickyLine . height ;
246
240
this . _linesDomNode . appendChild ( stickyLine . lineDomNode ) ;
247
241
this . _lineNumbersDomNode . appendChild ( stickyLine . lineNumberDomNode ) ;
248
- this . _renderedStickyLines . push ( stickyLine ) ;
242
+ renderedStickyLines . push ( stickyLine ) ;
249
243
}
250
244
if ( foldingModel ) {
251
245
this . _setFoldingHoverListeners ( ) ;
252
246
this . _useFoldingOpacityTransition ( ! this . _isOnGlyphMargin ) ;
253
247
}
254
-
255
- const widgetHeight = top + this . _lastLineRelativePosition ;
256
- this . _setHeight ( widgetHeight ) ;
257
-
258
- this . _rootDomNode . style . marginLeft = '0px' ;
259
248
this . _minContentWidthInPx = Math . max ( ...this . _renderedStickyLines . map ( l => l . scrollWidth ) ) + layoutInfo . verticalScrollbarWidth ;
249
+ this . _renderedStickyLines = renderedStickyLines ;
250
+ this . _setHeight ( top + lastLineRelativePosition ) ;
260
251
this . _editor . layoutOverlayWidget ( this ) ;
261
252
}
262
253
263
- private _getHeightOfLines ( lineNumbers : number [ ] , lastLineRelativePosition : number ) : number {
264
- let totalHeight = 0 ;
265
- for ( let i = 0 ; i < lineNumbers . length ; i ++ ) {
266
- totalHeight += this . _editor . getLineHeightForPosition ( new Position ( lineNumbers [ i ] , 1 ) ) ;
254
+ private _clearWidget ( ) : void {
255
+ for ( let i = 0 ; i < this . _renderedStickyLines . length ; i ++ ) {
256
+ const stickyLine = this . _renderedStickyLines [ i ] ;
257
+ stickyLine . lineNumberDomNode . remove ( ) ;
258
+ stickyLine . lineDomNode . remove ( ) ;
267
259
}
268
- return totalHeight + lastLineRelativePosition ;
260
+ this . _setHeight ( 0 ) ;
269
261
}
270
262
271
263
private _setHeight ( height : number ) : void {
@@ -302,11 +294,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
302
294
} ) ) ;
303
295
}
304
296
305
- private _renderChildNode ( index : number , line : number , top : number , foldingModel : FoldingModel | undefined , layoutInfo : EditorLayoutInfo ) : RenderedStickyLine | undefined {
306
- const viewModel = this . _editor . _getViewModel ( ) ;
307
- if ( ! viewModel ) {
308
- return ;
309
- }
297
+ private _renderChildNode ( viewModel : IViewModel , index : number , line : number , top : number , isLastLine : boolean , foldingModel : FoldingModel | undefined , layoutInfo : EditorLayoutInfo ) : RenderedStickyLine {
310
298
const viewLineNumber = viewModel . coordinatesConverter . convertModelPositionToViewPosition ( new Position ( line , 1 ) ) . lineNumber ;
311
299
const lineRenderingData = viewModel . getViewLineRenderingData ( viewLineNumber ) ;
312
300
const lineNumberOption = this . _editor . getOption ( EditorOption . lineNumbers ) ;
@@ -376,21 +364,27 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
376
364
this . _editor . applyFontInfo ( lineHTMLNode ) ;
377
365
this . _editor . applyFontInfo ( lineNumberHTMLNode ) ;
378
366
379
-
380
367
lineNumberHTMLNode . style . lineHeight = `${ lineHeight } px` ;
381
368
lineHTMLNode . style . lineHeight = `${ lineHeight } px` ;
382
369
lineNumberHTMLNode . style . height = `${ lineHeight } px` ;
383
370
lineHTMLNode . style . height = `${ lineHeight } px` ;
384
371
385
- const renderedLine = new RenderedStickyLine ( index , line , lineHTMLNode , lineNumberHTMLNode , foldingIcon , renderOutput . characterMapping , lineHTMLNode . scrollWidth , lineHeight ) ;
386
- return this . _updatePosition ( renderedLine , top ) ;
372
+ const renderedLine = new RenderedStickyLine (
373
+ index ,
374
+ line ,
375
+ lineHTMLNode ,
376
+ lineNumberHTMLNode ,
377
+ foldingIcon ,
378
+ renderOutput . characterMapping ,
379
+ lineHTMLNode . scrollWidth ,
380
+ lineHeight
381
+ ) ;
382
+ return this . _updatePosition ( renderedLine , top , isLastLine ) ;
387
383
}
388
384
389
- private _updatePosition ( stickyLine : RenderedStickyLine , top : number ) : RenderedStickyLine {
390
- const index = stickyLine . index ;
385
+ private _updatePosition ( stickyLine : RenderedStickyLine , top : number , isLastLine : boolean ) : RenderedStickyLine {
391
386
const lineHTMLNode = stickyLine . lineDomNode ;
392
387
const lineNumberHTMLNode = stickyLine . lineNumberDomNode ;
393
- const isLastLine = index === this . _lineNumbers . length - 1 ;
394
388
if ( isLastLine ) {
395
389
const zIndex = '0' ;
396
390
lineHTMLNode . style . zIndex = zIndex ;
0 commit comments