@@ -12,7 +12,7 @@ import { Range } from 'vs/editor/common/core/range';
12
12
import { ITextModel } from 'vs/editor/common/model' ;
13
13
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker' ;
14
14
import { EditorModel } from 'vs/workbench/common/editor/editorModel' ;
15
- import { autorunHandleChanges , derivedObservable , derivedObservableWithCache , IObservable , ITransaction , keepAlive , ObservableValue , transaction , waitForState } from 'vs/workbench/contrib/audioCues/browser/observable' ;
15
+ import { autorunHandleChanges , derivedObservable , IObservable , IReader , ITransaction , keepAlive , ObservableValue , transaction , waitForState } from 'vs/workbench/contrib/audioCues/browser/observable' ;
16
16
import { EditorWorkerServiceDiffComputer } from 'vs/workbench/contrib/mergeEditor/browser/model/diffComputer' ;
17
17
import { DetailedLineRangeMapping , DocumentMapping , LineRangeMapping } from 'vs/workbench/contrib/mergeEditor/browser/model/mapping' ;
18
18
import { LineRangeEdit , RangeEdit } from 'vs/workbench/contrib/mergeEditor/browser/model/editing' ;
@@ -53,11 +53,7 @@ export class MergeEditorModel extends EditorModel {
53
53
54
54
public readonly onInitialized = waitForState ( this . state , state => state === MergeEditorModelState . upToDate ) ;
55
55
56
- public readonly modifiedBaseRanges = derivedObservableWithCache < ModifiedBaseRange [ ] > ( 'modifiedBaseRanges' , ( reader , lastValue ) => {
57
- if ( this . state . read ( reader ) !== MergeEditorModelState . upToDate ) {
58
- return lastValue || [ ] ;
59
- }
60
-
56
+ public readonly modifiedBaseRanges = derivedObservable < ModifiedBaseRange [ ] > ( 'modifiedBaseRanges' , ( reader ) => {
61
57
const input1Diffs = this . input1TextModelDiffs . diffs . read ( reader ) ;
62
58
const input2Diffs = this . input2TextModelDiffs . diffs . read ( reader ) ;
63
59
@@ -76,6 +72,23 @@ export class MergeEditorModel extends EditorModel {
76
72
return map ;
77
73
} ) ;
78
74
75
+ private readonly modifiedBaseRangeHandlingStateStores =
76
+ derivedObservable ( 'modifiedBaseRangeHandlingStateStores' , reader => {
77
+ const map = new Map (
78
+ this . modifiedBaseRanges . read ( reader ) . map ( s => ( [ s , new ObservableValue ( false , 'State' ) ] ) )
79
+ ) ;
80
+ return map ;
81
+ } ) ;
82
+
83
+ public readonly unhandledConflictsCount = derivedObservable ( 'unhandledConflictsCount' , reader => {
84
+ const map = this . modifiedBaseRangeHandlingStateStores . read ( reader ) ;
85
+ let handledCount = 0 ;
86
+ for ( const [ _key , value ] of map ) {
87
+ handledCount += value . read ( reader ) ? 1 : 0 ;
88
+ }
89
+ return map . size - handledCount ;
90
+ } ) ;
91
+
79
92
public readonly input1ResultMapping = derivedObservable ( 'input1ResultMapping' , reader => {
80
93
const resultDiffs = this . resultDiffs . read ( reader ) ;
81
94
const modifiedBaseRanges = DocumentMapping . betweenOutputs ( this . input1LinesDiffs . read ( reader ) , resultDiffs , this . input1 . getLineCount ( ) ) ;
@@ -124,26 +137,43 @@ export class MergeEditorModel extends EditorModel {
124
137
super ( ) ;
125
138
126
139
this . _register ( keepAlive ( this . modifiedBaseRangeStateStores ) ) ;
140
+ this . _register ( keepAlive ( this . modifiedBaseRangeHandlingStateStores ) ) ;
127
141
this . _register ( keepAlive ( this . input1ResultMapping ) ) ;
128
142
this . _register ( keepAlive ( this . input2ResultMapping ) ) ;
129
143
144
+ let shouldResetHandlingState = true ;
130
145
this . _register (
131
146
autorunHandleChanges (
132
147
'Recompute State' ,
133
148
{
134
- handleChange : ( ctx ) =>
135
- ctx . didChange ( this . resultTextModelDiffs . diffs )
149
+ handleChange : ( ctx ) => {
150
+ if ( ctx . didChange ( this . modifiedBaseRangeHandlingStateStores ) ) {
151
+ shouldResetHandlingState = true ;
152
+ }
153
+ return ctx . didChange ( this . resultTextModelDiffs . diffs )
136
154
// Ignore non-text changes as we update the state directly
137
155
? ctx . change === TextModelDiffChangeReason . textChange
138
- : true ,
156
+ : true ;
157
+ } ,
139
158
} ,
140
159
( reader ) => {
160
+ const modifiedBaseRangeHandlingStateStores = this . modifiedBaseRangeHandlingStateStores . read ( reader ) ;
141
161
if ( ! this . isUpToDate . read ( reader ) ) {
142
162
return ;
143
163
}
144
164
const resultDiffs = this . resultTextModelDiffs . diffs . read ( reader ) ;
145
165
const stores = this . modifiedBaseRangeStateStores . read ( reader ) ;
146
- this . recomputeState ( resultDiffs , stores ) ;
166
+ transaction ( tx => {
167
+ this . recomputeState ( resultDiffs , stores , tx ) ;
168
+ if ( shouldResetHandlingState ) {
169
+ shouldResetHandlingState = false ;
170
+ for ( const [ range , store ] of stores ) {
171
+ const state = store . get ( ) ;
172
+ modifiedBaseRangeHandlingStateStores . get ( range )
173
+ ?. set ( ! ( state . isEmpty || state . conflicting ) , tx ) ;
174
+ }
175
+ }
176
+ } ) ;
147
177
}
148
178
)
149
179
) ;
@@ -153,24 +183,27 @@ export class MergeEditorModel extends EditorModel {
153
183
} ) ;
154
184
}
155
185
156
- private recomputeState ( resultDiffs : DetailedLineRangeMapping [ ] , stores : Map < ModifiedBaseRange , ObservableValue < ModifiedBaseRangeState > > ) : void {
157
- transaction ( tx => {
158
- const baseRangeWithStoreAndTouchingDiffs = leftJoin (
159
- stores ,
160
- resultDiffs ,
161
- ( baseRange , diff ) =>
162
- baseRange [ 0 ] . baseRange . touches ( diff . inputRange )
163
- ? CompareResult . neitherLessOrGreaterThan
164
- : LineRange . compareByStart (
165
- baseRange [ 0 ] . baseRange ,
166
- diff . inputRange
167
- )
168
- ) ;
186
+ public getRangeInResult ( baseRange : LineRange , reader ?: IReader ) : LineRange {
187
+ return this . resultTextModelDiffs . getResultRange ( baseRange , reader ) ;
188
+ }
169
189
170
- for ( const row of baseRangeWithStoreAndTouchingDiffs ) {
171
- row . left [ 1 ] . set ( this . computeState ( row . left [ 0 ] , row . rights ) , tx ) ;
172
- }
173
- } ) ;
190
+ private recomputeState ( resultDiffs : DetailedLineRangeMapping [ ] , stores : Map < ModifiedBaseRange , ObservableValue < ModifiedBaseRangeState > > , tx : ITransaction ) : void {
191
+ const baseRangeWithStoreAndTouchingDiffs = leftJoin (
192
+ stores ,
193
+ resultDiffs ,
194
+ ( baseRange , diff ) =>
195
+ baseRange [ 0 ] . baseRange . touches ( diff . inputRange )
196
+ ? CompareResult . neitherLessOrGreaterThan
197
+ : LineRange . compareByStart (
198
+ baseRange [ 0 ] . baseRange ,
199
+ diff . inputRange
200
+ )
201
+ ) ;
202
+
203
+ for ( const row of baseRangeWithStoreAndTouchingDiffs ) {
204
+ row . left [ 1 ] . set ( this . computeState ( row . left [ 0 ] , row . rights ) , tx ) ;
205
+
206
+ }
174
207
}
175
208
176
209
public resetUnknown ( ) : void {
@@ -236,6 +269,11 @@ export class MergeEditorModel extends EditorModel {
236
269
if ( edit ) {
237
270
this . resultTextModelDiffs . applyEditRelativeToOriginal ( edit , transaction ) ;
238
271
}
272
+
273
+ this . modifiedBaseRangeHandlingStateStores
274
+ . get ( )
275
+ . get ( baseRange ) !
276
+ . set ( true , transaction ) ;
239
277
}
240
278
241
279
private computeState ( baseRange : ModifiedBaseRange , conflictingDiffs : DetailedLineRangeMapping [ ] ) : ModifiedBaseRangeState {
@@ -279,6 +317,9 @@ export class MergeEditorModel extends EditorModel {
279
317
return ModifiedBaseRangeState . conflicting ;
280
318
}
281
319
320
+ public isHandled ( baseRange : ModifiedBaseRange ) : IObservable < boolean > {
321
+ return this . modifiedBaseRangeHandlingStateStores . get ( ) . get ( baseRange ) ! ;
322
+ }
282
323
}
283
324
284
325
function getEditForBase ( baseRange : ModifiedBaseRange , state : ModifiedBaseRangeState ) : { edit : LineRangeEdit | undefined ; effectiveState : ModifiedBaseRangeState } {
0 commit comments