@@ -8,8 +8,10 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
8
8
import { IObservable , derived , observableFromEvent , observableSignalFromEvent , observableValue } from 'vs/base/common/observable' ;
9
9
import { autorun , autorunWithStore2 } from 'vs/base/common/observableImpl/autorun' ;
10
10
import { ThemeIcon } from 'vs/base/common/themables' ;
11
+ import { assertIsDefined } from 'vs/base/common/types' ;
11
12
import { applyFontInfo } from 'vs/editor/browser/config/domFontInfo' ;
12
13
import { IViewZone } from 'vs/editor/browser/editorBrowser' ;
14
+ import { StableEditorScrollState } from 'vs/editor/browser/stableEditorScroll' ;
13
15
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget' ;
14
16
import { diffDeleteDecoration , diffRemoveIcon } from 'vs/editor/browser/widget/diffEditorWidget2/decorations' ;
15
17
import { DiffMapping , DiffModel } from 'vs/editor/browser/widget/diffEditorWidget2/diffModel' ;
@@ -26,14 +28,18 @@ import { InlineDecoration, InlineDecorationType } from 'vs/editor/common/viewMod
26
28
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService' ;
27
29
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView' ;
28
30
29
- export class ViewZoneAlignment extends Disposable {
30
- private readonly _origExtraHeight = observableValue ( 'origExtraHeight' , 0 ) ;
31
- private readonly _modExtraHeight = observableValue ( 'modExtraHeight' , 0 ) ;
32
-
31
+ /**
32
+ * Ensures both editors have the same height by aligning unchanged lines.
33
+ * In inline view mode, inserts viewzones to show deleted code from the original text model in the modified code editor.
34
+ * Synchronizes scrolling.
35
+ */
36
+ export class ViewZoneManager extends Disposable {
37
+ private readonly _originalTopPadding = observableValue ( 'originalTopPadding' , 0 ) ;
33
38
private readonly _originalScrollTop : IObservable < number > ;
34
39
private readonly _originalScrollOffset = observableValue < number , boolean > ( 'originalScrollOffset' , 0 ) ;
35
40
private readonly _originalScrollOffsetAnimated = animatedObservable ( this . _originalScrollOffset , this . _store ) ;
36
41
42
+ private readonly _modifiedTopPadding = observableValue ( 'modifiedTopPadding' , 0 ) ;
37
43
private readonly _modifiedScrollTop : IObservable < number > ;
38
44
private readonly _modifiedScrollOffset = observableValue < number , boolean > ( 'modifiedScrollOffset' , 0 ) ;
39
45
private readonly _modifiedScrollOffsetAnimated = animatedObservable ( this . _modifiedScrollOffset , this . _store ) ;
@@ -50,11 +56,11 @@ export class ViewZoneAlignment extends Disposable {
50
56
51
57
let isChangingViewZones = false ;
52
58
53
- const origViewZonesChanged = observableSignalFromEvent (
59
+ const originalViewZonesChanged = observableSignalFromEvent (
54
60
'origViewZonesChanged' ,
55
61
e => this . _originalEditor . onDidChangeViewZones ( ( args ) => { if ( ! isChangingViewZones ) { e ( args ) ; } } )
56
62
) ;
57
- const modViewZonesChanged = observableSignalFromEvent (
63
+ const modifiedViewZonesChanged = observableSignalFromEvent (
58
64
'modViewZonesChanged' ,
59
65
e => this . _modifiedEditor . onDidChangeViewZones ( ( args ) => { if ( ! isChangingViewZones ) { e ( args ) ; } } )
60
66
) ;
@@ -70,24 +76,18 @@ export class ViewZoneAlignment extends Disposable {
70
76
const diffModel = this . _diffModel . read ( reader ) ;
71
77
const diff = diffModel ?. diff . read ( reader ) ;
72
78
if ( ! diffModel || ! diff ) { return null ; }
73
-
74
- origViewZonesChanged . read ( reader ) ;
75
- modViewZonesChanged . read ( reader ) ;
76
-
79
+ originalViewZonesChanged . read ( reader ) ;
80
+ modifiedViewZonesChanged . read ( reader ) ;
77
81
return computeRangeAlignment ( this . _originalEditor , this . _modifiedEditor , diff . mappings , alignmentViewZoneIdsOrig , alignmentViewZoneIdsMod ) ;
78
82
} ) ;
79
83
80
84
const alignmentsSyncedMovedText = derived < ILineRangeAlignment [ ] | null > ( 'alignments' , ( reader ) => {
81
- origViewZonesChanged . read ( reader ) ;
82
- modViewZonesChanged . read ( reader ) ;
83
-
84
85
const syncedMovedText = this . _diffModel . read ( reader ) ?. syncedMovedTexts . read ( reader ) ;
85
- if ( ! syncedMovedText ) {
86
- return null ;
87
- }
86
+ if ( ! syncedMovedText ) { return null ; }
87
+ originalViewZonesChanged . read ( reader ) ;
88
+ modifiedViewZonesChanged . read ( reader ) ;
88
89
const mappings = syncedMovedText . changes . map ( c => new DiffMapping ( c ) ) ;
89
-
90
- // TOD dont include alignments outside syncedMovedText
90
+ // TODO dont include alignments outside syncedMovedText
91
91
return computeRangeAlignment ( this . _originalEditor , this . _modifiedEditor , mappings , alignmentViewZoneIdsOrig , alignmentViewZoneIdsMod ) ;
92
92
} ) ;
93
93
@@ -101,33 +101,33 @@ export class ViewZoneAlignment extends Disposable {
101
101
const alignmentViewZones = derived < { orig : IViewZoneWithZoneId [ ] ; mod : IViewZoneWithZoneId [ ] } > ( 'alignment viewzones' , ( reader ) => {
102
102
alignmentViewZonesDisposables . clear ( ) ;
103
103
104
- const curAlignments = alignments . read ( reader ) || [ ] ;
104
+ const alignmentsVal = alignments . read ( reader ) || [ ] ;
105
105
106
106
const origViewZones : IViewZoneWithZoneId [ ] = [ ] ;
107
107
const modViewZones : IViewZoneWithZoneId [ ] = [ ] ;
108
108
109
- const curModExtraHeight = this . _modExtraHeight . read ( reader ) ;
110
- if ( curModExtraHeight > 0 ) {
109
+ const modifiedTopPaddingVal = this . _modifiedTopPadding . read ( reader ) ;
110
+ if ( modifiedTopPaddingVal > 0 ) {
111
111
modViewZones . push ( {
112
112
afterLineNumber : 0 ,
113
113
domNode : document . createElement ( 'div' ) ,
114
- heightInPx : curModExtraHeight ,
114
+ heightInPx : modifiedTopPaddingVal ,
115
115
} ) ;
116
116
}
117
- const curOrigExtraHeight = this . _origExtraHeight . read ( reader ) ;
118
- if ( curOrigExtraHeight > 0 ) {
117
+ const originalTopPaddingVal = this . _originalTopPadding . read ( reader ) ;
118
+ if ( originalTopPaddingVal > 0 ) {
119
119
origViewZones . push ( {
120
120
afterLineNumber : 0 ,
121
121
domNode : document . createElement ( 'div' ) ,
122
- heightInPx : curOrigExtraHeight ,
122
+ heightInPx : originalTopPaddingVal ,
123
123
} ) ;
124
124
}
125
125
126
126
const renderSideBySide = this . _renderSideBySide . read ( reader ) ;
127
127
128
128
const deletedCodeLineBreaksComputer = ! renderSideBySide ? this . _modifiedEditor . _getViewModel ( ) ?. createLineBreaksComputer ( ) : undefined ;
129
129
if ( deletedCodeLineBreaksComputer ) {
130
- for ( const a of curAlignments ) {
130
+ for ( const a of alignmentsVal ) {
131
131
if ( a . diff ) {
132
132
for ( let i = a . originalRange . startLineNumber ; i < a . originalRange . endLineNumberExclusive ; i ++ ) {
133
133
deletedCodeLineBreaksComputer ?. addRequest ( this . _originalEditor . getModel ( ) ! . getLineContent ( i ) , null , null ) ;
@@ -147,13 +147,13 @@ export class ViewZoneAlignment extends Disposable {
147
147
const mightContainRTL = this . _originalEditor . getModel ( ) ?. mightContainRTL ( ) ?? false ;
148
148
const renderOptions = RenderOptions . fromEditor ( this . _modifiedEditor ) ;
149
149
150
- for ( const a of curAlignments ) {
150
+ for ( const a of alignmentsVal ) {
151
151
if ( a . diff && ! renderSideBySide ) {
152
152
if ( ! a . originalRange . isEmpty ) {
153
153
originalModelTokenizationCompleted . read ( reader ) ; // Update view-zones once tokenization completes
154
154
155
- const domNode = document . createElement ( 'div' ) ;
156
- domNode . classList . add ( 'view-lines' , 'line-delete' , 'monaco-mouse-cursor-text' ) ;
155
+ const deletedCodeDomNode = document . createElement ( 'div' ) ;
156
+ deletedCodeDomNode . classList . add ( 'view-lines' , 'line-delete' , 'monaco-mouse-cursor-text' ) ;
157
157
const source = new LineSource (
158
158
a . originalRange . mapToLineArray ( l => this . _originalEditor . getModel ( ) ! . tokenization . getLineTokens ( l ) ) ,
159
159
a . originalRange . mapToLineArray ( _ => lineBreakData [ lineBreakDataIdx ++ ] ) ,
@@ -168,7 +168,7 @@ export class ViewZoneAlignment extends Disposable {
168
168
InlineDecorationType . Regular
169
169
) ) ;
170
170
}
171
- const result = renderLines ( source , renderOptions , decorations , domNode ) ;
171
+ const result = renderLines ( source , renderOptions , decorations , deletedCodeDomNode ) ;
172
172
173
173
const marginDomNode = document . createElement ( 'div' ) ;
174
174
marginDomNode . className = 'inline-deleted-margin-view-zone' ;
@@ -183,18 +183,10 @@ export class ViewZoneAlignment extends Disposable {
183
183
}
184
184
//}
185
185
186
- let zoneId : string ;
187
- modViewZones . push ( {
188
- afterLineNumber : a . modifiedRange . startLineNumber - 1 ,
189
- domNode : domNode ,
190
- heightInPx : result . heightInLines * modLineHeight ,
191
- minWidthInPx : result . minWidthInPx ,
192
- marginDomNode,
193
- setZoneId ( id ) { zoneId = id ; } ,
194
- } ) ;
186
+ let zoneId : string | undefined = undefined ;
195
187
alignmentViewZonesDisposables . add (
196
188
new InlineDiffDeletedCodeMargin (
197
- ( ) => zoneId ,
189
+ ( ) => assertIsDefined ( zoneId ) ,
198
190
marginDomNode ,
199
191
this . _modifiedEditor ,
200
192
a . diff ,
@@ -207,7 +199,7 @@ export class ViewZoneAlignment extends Disposable {
207
199
208
200
for ( let i = 0 ; i < result . viewLineCounts . length ; i ++ ) {
209
201
const count = result . viewLineCounts [ i ] ;
210
- // Account for wrapped lines in the (collapsed) original editor (that does not have line wraps ).
202
+ // Account for wrapped lines in the (collapsed) original editor (which doesn't wrap lines ).
211
203
if ( count > 1 ) {
212
204
origViewZones . push ( {
213
205
afterLineNumber : a . originalRange . startLineNumber + i ,
@@ -216,6 +208,15 @@ export class ViewZoneAlignment extends Disposable {
216
208
} ) ;
217
209
}
218
210
}
211
+
212
+ modViewZones . push ( {
213
+ afterLineNumber : a . modifiedRange . startLineNumber - 1 ,
214
+ domNode : deletedCodeDomNode ,
215
+ heightInPx : result . heightInLines * modLineHeight ,
216
+ minWidthInPx : result . minWidthInPx ,
217
+ marginDomNode,
218
+ setZoneId ( id ) { zoneId = id ; } ,
219
+ } ) ;
219
220
}
220
221
221
222
const marginDomNode = document . createElement ( 'div' ) ;
@@ -280,6 +281,8 @@ export class ViewZoneAlignment extends Disposable {
280
281
} ) ;
281
282
282
283
this . _register ( autorunWithStore2 ( 'alignment viewzones' , ( reader ) => {
284
+ const scrollState = StableEditorScrollState . capture ( this . _modifiedEditor ) ;
285
+
283
286
const alignmentViewZones_ = alignmentViewZones . read ( reader ) ;
284
287
isChangingViewZones = true ;
285
288
this . _originalEditor . changeViewZones ( ( aOrig ) => {
@@ -305,6 +308,8 @@ export class ViewZoneAlignment extends Disposable {
305
308
}
306
309
} ) ;
307
310
isChangingViewZones = false ;
311
+
312
+ scrollState . restore ( this . _modifiedEditor ) ;
308
313
} ) ) ;
309
314
310
315
this . _originalScrollTop = observableFromEvent ( this . _originalEditor . onDidScrollChange , ( ) => this . _originalEditor . getScrollTop ( ) ) ;
@@ -321,7 +326,7 @@ export class ViewZoneAlignment extends Disposable {
321
326
this . _register ( autorun ( 'update scroll modified' , ( reader ) => {
322
327
const newScrollTopModified = this . _originalScrollTop . read ( reader )
323
328
- ( this . _originalScrollOffsetAnimated . get ( ) - this . _modifiedScrollOffsetAnimated . read ( reader ) )
324
- - ( this . _origExtraHeight . get ( ) - this . _modExtraHeight . read ( reader ) ) ;
329
+ - ( this . _originalTopPadding . get ( ) - this . _modifiedTopPadding . read ( reader ) ) ;
325
330
if ( newScrollTopModified !== this . _modifiedEditor . getScrollTop ( ) ) {
326
331
this . _modifiedEditor . setScrollTop ( newScrollTopModified , ScrollType . Immediate ) ;
327
332
}
@@ -330,7 +335,7 @@ export class ViewZoneAlignment extends Disposable {
330
335
this . _register ( autorun ( 'update scroll original' , ( reader ) => {
331
336
const newScrollTopOriginal = this . _modifiedScrollTop . read ( reader )
332
337
- ( this . _modifiedScrollOffsetAnimated . get ( ) - this . _originalScrollOffsetAnimated . read ( reader ) )
333
- - ( this . _modExtraHeight . get ( ) - this . _origExtraHeight . read ( reader ) ) ;
338
+ - ( this . _modifiedTopPadding . get ( ) - this . _originalTopPadding . read ( reader ) ) ;
334
339
if ( newScrollTopOriginal !== this . _originalEditor . getScrollTop ( ) ) {
335
340
this . _originalEditor . setScrollTop ( newScrollTopOriginal , ScrollType . Immediate ) ;
336
341
}
@@ -342,21 +347,21 @@ export class ViewZoneAlignment extends Disposable {
342
347
343
348
let deltaOrigToMod = 0 ;
344
349
if ( m ) {
345
- const trueTopOriginal = this . _originalEditor . getTopForLineNumber ( m . lineRangeMapping . originalRange . startLineNumber , true ) - this . _origExtraHeight . get ( ) ;
346
- const trueTopModified = this . _modifiedEditor . getTopForLineNumber ( m . lineRangeMapping . modifiedRange . startLineNumber , true ) - this . _modExtraHeight . get ( ) ;
350
+ const trueTopOriginal = this . _originalEditor . getTopForLineNumber ( m . lineRangeMapping . originalRange . startLineNumber , true ) - this . _originalTopPadding . get ( ) ;
351
+ const trueTopModified = this . _modifiedEditor . getTopForLineNumber ( m . lineRangeMapping . modifiedRange . startLineNumber , true ) - this . _modifiedTopPadding . get ( ) ;
347
352
deltaOrigToMod = trueTopModified - trueTopOriginal ;
348
353
}
349
354
350
355
if ( deltaOrigToMod > 0 ) {
351
- this . _modExtraHeight . set ( 0 , undefined ) ;
352
- this . _origExtraHeight . set ( deltaOrigToMod , undefined ) ;
356
+ this . _modifiedTopPadding . set ( 0 , undefined ) ;
357
+ this . _originalTopPadding . set ( deltaOrigToMod , undefined ) ;
353
358
} else if ( deltaOrigToMod < 0 ) {
354
- this . _modExtraHeight . set ( - deltaOrigToMod , undefined ) ;
355
- this . _origExtraHeight . set ( 0 , undefined ) ;
359
+ this . _modifiedTopPadding . set ( - deltaOrigToMod , undefined ) ;
360
+ this . _originalTopPadding . set ( 0 , undefined ) ;
356
361
} else {
357
362
setTimeout ( ( ) => {
358
- this . _modExtraHeight . set ( 0 , undefined ) ;
359
- this . _origExtraHeight . set ( 0 , undefined ) ;
363
+ this . _modifiedTopPadding . set ( 0 , undefined ) ;
364
+ this . _originalTopPadding . set ( 0 , undefined ) ;
360
365
} , 400 ) ;
361
366
}
362
367
0 commit comments