5
5
6
6
import { $ , addDisposableListener , h , reset } from 'vs/base/browser/dom' ;
7
7
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels' ;
8
+ import { Codicon } from 'vs/base/common/codicons' ;
9
+ import { MarkdownString } from 'vs/base/common/htmlContent' ;
8
10
import { Disposable } from 'vs/base/common/lifecycle' ;
9
11
import { IObservable , observableFromEvent , transaction } from 'vs/base/common/observable' ;
10
12
import { autorun , autorunWithStore2 } from 'vs/base/common/observableImpl/autorun' ;
11
13
import { derived , derivedWithStore } from 'vs/base/common/observableImpl/derived' ;
14
+ import { ThemeIcon } from 'vs/base/common/themables' ;
12
15
import { isDefined } from 'vs/base/common/types' ;
13
16
import { ICodeEditor , IViewZone } from 'vs/editor/browser/editorBrowser' ;
14
17
import { DiffEditorEditors } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorEditors' ;
15
18
import { DiffEditorOptions } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorOptions' ;
16
19
import { DiffEditorViewModel , UnchangedRegion } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorViewModel' ;
17
20
import { PlaceholderViewZone , ViewZoneOverlayWidget , applyObservableDecorations , applyStyle , applyViewZones } from 'vs/editor/browser/widget/diffEditorWidget2/utils' ;
18
21
import { EditorOption } from 'vs/editor/common/config/editorOptions' ;
22
+ import { LineRange } from 'vs/editor/common/core/lineRange' ;
23
+ import { Position } from 'vs/editor/common/core/position' ;
24
+ import { Range } from 'vs/editor/common/core/range' ;
19
25
import { CursorChangeReason } from 'vs/editor/common/cursorEvents' ;
20
26
import { IModelDecorationOptions , IModelDeltaDecoration } from 'vs/editor/common/model' ;
27
+ import { localize } from 'vs/nls' ;
21
28
22
29
export class UnchangedRangesFeature extends Disposable {
23
30
private _isUpdatingViewZones = false ;
@@ -90,21 +97,45 @@ export class UnchangedRangesFeature extends Disposable {
90
97
className : 'diff-unchanged-lines' ,
91
98
isWholeLine : true ,
92
99
} ;
100
+ const unchangedLinesDecorationShow : IModelDecorationOptions = {
101
+ description : 'Fold Unchanged' ,
102
+ glyphMarginHoverMessage : new MarkdownString ( undefined , { isTrusted : true , supportThemeIcons : true } ) . appendMarkdown ( localize ( 'foldUnchanged' , 'Fold Unchanged Region' ) ) ,
103
+ glyphMarginClassName : 'fold-unchanged ' + ThemeIcon . asClassName ( Codicon . fold ) ,
104
+ zIndex : 10001 ,
105
+ } ;
93
106
94
107
this . _register ( applyObservableDecorations ( this . _editors . original , derived ( 'decorations' , ( reader ) => {
95
108
const curUnchangedRegions = unchangedRegions . read ( reader ) ;
96
- return curUnchangedRegions . map < IModelDeltaDecoration > ( r => ( {
109
+ const result = curUnchangedRegions . map < IModelDeltaDecoration > ( r => ( {
97
110
range : r . originalRange . toInclusiveRange ( ) ! ,
98
111
options : unchangedLinesDecoration ,
99
112
} ) ) ;
113
+ for ( const r of curUnchangedRegions ) {
114
+ if ( r . shouldHideControls ( reader ) ) {
115
+ result . push ( {
116
+ range : Range . fromPositions ( new Position ( r . originalLineNumber , 1 ) ) ,
117
+ options : unchangedLinesDecorationShow
118
+ } ) ;
119
+ }
120
+ }
121
+ return result ;
100
122
} ) ) ) ;
101
123
102
124
this . _register ( applyObservableDecorations ( this . _editors . modified , derived ( 'decorations' , ( reader ) => {
103
125
const curUnchangedRegions = unchangedRegions . read ( reader ) ;
104
- return curUnchangedRegions . map < IModelDeltaDecoration > ( r => ( {
126
+ const result = curUnchangedRegions . map < IModelDeltaDecoration > ( r => ( {
105
127
range : r . modifiedRange . toInclusiveRange ( ) ! ,
106
128
options : unchangedLinesDecoration ,
107
129
} ) ) ;
130
+ for ( const r of curUnchangedRegions ) {
131
+ if ( r . shouldHideControls ( reader ) ) {
132
+ result . push ( {
133
+ range : LineRange . ofLength ( r . modifiedLineNumber , 1 ) . toInclusiveRange ( ) ! ,
134
+ options : unchangedLinesDecorationShow
135
+ } ) ;
136
+ }
137
+ }
138
+ return result ;
108
139
} ) ) ) ;
109
140
110
141
this . _register ( applyViewZones ( this . _editors . original , viewZones . map ( v => v . origViewZones ) , v => this . _isUpdatingViewZones = v ) ) ;
@@ -115,6 +146,32 @@ export class UnchangedRangesFeature extends Disposable {
115
146
this . _editors . original . setHiddenAreas ( curUnchangedRegions . map ( r => r . getHiddenOriginalRange ( reader ) . toInclusiveRange ( ) ) . filter ( isDefined ) ) ;
116
147
this . _editors . modified . setHiddenAreas ( curUnchangedRegions . map ( r => r . getHiddenModifiedRange ( reader ) . toInclusiveRange ( ) ) . filter ( isDefined ) ) ;
117
148
} ) ) ;
149
+
150
+ this . _register ( this . _editors . modified . onMouseUp ( event => {
151
+ if ( ! event . event . rightButton && event . target . position && event . target . element ?. className . includes ( 'fold-unchanged' ) ) {
152
+ const lineNumber = event . target . position . lineNumber ;
153
+ const model = this . _diffModel . get ( ) ;
154
+ if ( ! model ) { return ; }
155
+ const region = model . unchangedRegions . get ( ) . find ( r => r . modifiedRange . includes ( lineNumber ) ) ;
156
+ if ( ! region ) { return ; }
157
+ region . setState ( 0 , 0 , undefined ) ;
158
+ event . event . stopPropagation ( ) ;
159
+ event . event . preventDefault ( ) ;
160
+ }
161
+ } ) ) ;
162
+
163
+ this . _register ( this . _editors . original . onMouseUp ( event => {
164
+ if ( ! event . event . rightButton && event . target . position && event . target . element ?. className . includes ( 'fold-unchanged' ) ) {
165
+ const lineNumber = event . target . position . lineNumber ;
166
+ const model = this . _diffModel . get ( ) ;
167
+ if ( ! model ) { return ; }
168
+ const region = model . unchangedRegions . get ( ) . find ( r => r . originalRange . includes ( lineNumber ) ) ;
169
+ if ( ! region ) { return ; }
170
+ region . setState ( 0 , 0 , undefined ) ;
171
+ event . event . stopPropagation ( ) ;
172
+ event . event . preventDefault ( ) ;
173
+ }
174
+ } ) ) ;
118
175
}
119
176
}
120
177
@@ -165,7 +222,7 @@ class CollapsedCodeOverlayWidget extends ViewZoneOverlayWidget {
165
222
this . _unchangedRegion . isDragged . set ( true , undefined ) ;
166
223
167
224
168
- const mouseMoveListener = addDisposableListener ( document . body , 'mousemove' , e => {
225
+ const mouseMoveListener = addDisposableListener ( window , 'mousemove' , e => {
169
226
const currentTop = e . clientY ;
170
227
const delta = currentTop - startTop ;
171
228
didMove = didMove || Math . abs ( delta ) > 2 ;
@@ -174,7 +231,7 @@ class CollapsedCodeOverlayWidget extends ViewZoneOverlayWidget {
174
231
this . _unchangedRegion . visibleLineCountTop . set ( newVal , undefined ) ;
175
232
} ) ;
176
233
177
- const mouseUpListener = addDisposableListener ( document . body , 'mouseup' , e => {
234
+ const mouseUpListener = addDisposableListener ( window , 'mouseup' , e => {
178
235
if ( ! didMove ) {
179
236
this . _unchangedRegion . showMoreAbove ( 20 , undefined ) ;
180
237
}
@@ -198,26 +255,26 @@ class CollapsedCodeOverlayWidget extends ViewZoneOverlayWidget {
198
255
const cur = this . _unchangedRegion . visibleLineCountBottom . get ( ) ;
199
256
this . _unchangedRegion . isDragged . set ( true , undefined ) ;
200
257
201
- const mouseMoveListener = addDisposableListener ( document . body , 'mousemove' , e => {
258
+ const mouseMoveListener = addDisposableListener ( window , 'mousemove' , e => {
202
259
const currentTop = e . clientY ;
203
260
const delta = currentTop - startTop ;
204
261
didMove = didMove || Math . abs ( delta ) > 2 ;
205
262
const lineDelta = Math . round ( delta / editor . getOption ( EditorOption . lineHeight ) ) ;
206
263
const newVal = Math . max ( 0 , Math . min ( cur - lineDelta , this . _unchangedRegion . getMaxVisibleLineCountBottom ( ) ) ) ;
207
- const top = editor . getTopForLineNumber ( this . _unchangedRegion . modifiedRange . endLineNumberExclusive ) ;
264
+ const top = editor . getTopForLineNumber ( this . _unchangedRegion . originalRange . endLineNumberExclusive ) ;
208
265
this . _unchangedRegion . visibleLineCountBottom . set ( newVal , undefined ) ;
209
- const top2 = editor . getTopForLineNumber ( this . _unchangedRegion . modifiedRange . endLineNumberExclusive ) ;
266
+ const top2 = editor . getTopForLineNumber ( this . _unchangedRegion . originalRange . endLineNumberExclusive ) ;
210
267
editor . setScrollTop ( editor . getScrollTop ( ) + ( top2 - top ) ) ;
211
268
} ) ;
212
269
213
- const mouseUpListener = addDisposableListener ( document . body , 'mouseup' , e => {
270
+ const mouseUpListener = addDisposableListener ( window , 'mouseup' , e => {
214
271
this . _unchangedRegion . isDragged . set ( false , undefined ) ;
215
272
216
273
if ( ! didMove ) {
217
- const top = editor . getTopForLineNumber ( this . _unchangedRegion . modifiedRange . endLineNumberExclusive ) ;
274
+ const top = editor . getTopForLineNumber ( this . _unchangedRegion . originalRange . endLineNumberExclusive ) ;
218
275
219
276
this . _unchangedRegion . showMoreBelow ( 20 , undefined ) ;
220
- const top2 = editor . getTopForLineNumber ( this . _unchangedRegion . modifiedRange . endLineNumberExclusive ) ;
277
+ const top2 = editor . getTopForLineNumber ( this . _unchangedRegion . originalRange . endLineNumberExclusive ) ;
221
278
editor . setScrollTop ( editor . getScrollTop ( ) + ( top2 - top ) ) ;
222
279
}
223
280
this . _nodes . bottom . classList . toggle ( 'dragging' , false ) ;
0 commit comments