5
5
6
6
import { DisposableStore } from 'vs/base/common/lifecycle' ;
7
7
import { isEqual } from 'vs/base/common/resources' ;
8
+ import Severity from 'vs/base/common/severity' ;
8
9
import { URI } from 'vs/base/common/uri' ;
9
10
import { ITextModelService } from 'vs/editor/common/services/resolverService' ;
10
11
import { localize } from 'vs/nls' ;
12
+ import { ConfirmResult , IDialogService } from 'vs/platform/dialogs/common/dialogs' ;
11
13
import { IFileService } from 'vs/platform/files/common/files' ;
12
14
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' ;
13
15
import { ILabelService } from 'vs/platform/label/common/label' ;
14
- import { IUntypedEditorInput } from 'vs/workbench/common/editor' ;
16
+ import { IEditorIdentifier , IUntypedEditorInput } from 'vs/workbench/common/editor' ;
15
17
import { EditorInput } from 'vs/workbench/common/editor/editorInput' ;
16
18
import { AbstractTextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput' ;
19
+ import { autorun } from 'vs/workbench/contrib/audioCues/browser/observable' ;
17
20
import { MergeEditorModel } from 'vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel' ;
18
21
import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
19
22
import { ILanguageSupport , ITextFileEditorModel , ITextFileService } from 'vs/workbench/services/textfile/common/textfiles' ;
@@ -33,6 +36,7 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements
33
36
34
37
private _model ?: MergeEditorModel ;
35
38
private _outTextModel ?: ITextFileEditorModel ;
39
+ private _ignoreUnhandledConflictsForDirtyState ?: true ;
36
40
37
41
constructor (
38
42
public readonly base : URI ,
@@ -41,6 +45,7 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements
41
45
public readonly result : URI ,
42
46
@IInstantiationService private readonly _instaService : IInstantiationService ,
43
47
@ITextModelService private readonly _textModelService : ITextModelService ,
48
+ @IDialogService private readonly _dialogService : IDialogService ,
44
49
@IEditorService editorService : IEditorService ,
45
50
@ITextFileService textFileService : ITextFileService ,
46
51
@ILabelService labelService : ILabelService ,
@@ -112,7 +117,14 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements
112
117
this . _store . add ( input1 ) ;
113
118
this . _store . add ( input2 ) ;
114
119
this . _store . add ( result ) ;
120
+
121
+ this . _store . add ( autorun ( reader => {
122
+ this . _model ?. hasUnhandledConflicts . read ( reader ) ;
123
+ this . _onDidChangeDirty . fire ( undefined ) ;
124
+ } , 'drive::onDidChangeDirty' ) ) ;
115
125
}
126
+
127
+ this . _ignoreUnhandledConflictsForDirtyState = undefined ;
116
128
return this . _model ;
117
129
}
118
130
@@ -129,7 +141,62 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements
129
141
// ---- FileEditorInput
130
142
131
143
override isDirty ( ) : boolean {
132
- return Boolean ( this . _outTextModel ?. isDirty ( ) ) ;
144
+ const textModelDirty = Boolean ( this . _outTextModel ?. isDirty ( ) ) ;
145
+ if ( textModelDirty ) {
146
+ // text model dirty -> 3wm is dirty
147
+ return true ;
148
+ }
149
+ if ( ! this . _ignoreUnhandledConflictsForDirtyState ) {
150
+ // unhandled conflicts -> 3wm is dirty UNLESS we explicitly set this input
151
+ // to ignore unhandled conflicts for the dirty-state. This happens only
152
+ // after confirming to ignore unhandled changes
153
+ return Boolean ( this . _model && this . _model . hasUnhandledConflicts . get ( ) ) ;
154
+ }
155
+ return false ;
156
+ }
157
+
158
+ override async confirm ( editors ?: ReadonlyArray < IEditorIdentifier > ) : Promise < ConfirmResult > {
159
+
160
+ const inputs : MergeEditorInput [ ] = [ this ] ;
161
+ if ( editors ) {
162
+ for ( const { editor } of editors ) {
163
+ if ( editor instanceof MergeEditorInput ) {
164
+ inputs . push ( editor ) ;
165
+ }
166
+ }
167
+ }
168
+
169
+ const inputsWithUnhandledConflicts = inputs
170
+ . filter ( input => input . _model && input . _model . hasUnhandledConflicts . get ( ) ) ;
171
+
172
+ if ( inputsWithUnhandledConflicts . length === 0 ) {
173
+ return ConfirmResult . SAVE ;
174
+ }
175
+
176
+ const { choice } = await this . _dialogService . show (
177
+ Severity . Info ,
178
+ localize ( 'unhandledConflicts.msg' , 'Do you want to continue with unhandled conflicts?' ) ,
179
+ [
180
+ localize ( 'unhandledConflicts.ignore' , "Continue with Conflicts" ) ,
181
+ localize ( 'unhandledConflicts.cancel' , "Cancel" )
182
+ ] ,
183
+ {
184
+ cancelId : 1 ,
185
+ detail : inputsWithUnhandledConflicts . length > 1
186
+ ? localize ( 'unhandledConflicts.detailN' , 'Merge conflicts in {0} editors will remain unhandled.' , inputsWithUnhandledConflicts . length )
187
+ : localize ( 'unhandledConflicts.detail1' , 'Merge conflicts in this editor will remain unhandled.' )
188
+ }
189
+ ) ;
190
+
191
+ if ( choice !== 0 ) {
192
+ return ConfirmResult . CANCEL ;
193
+ }
194
+
195
+ // continue with conflicts, tell inputs to ignore unhandled changes
196
+ for ( const input of inputsWithUnhandledConflicts ) {
197
+ input . _ignoreUnhandledConflictsForDirtyState = true ;
198
+ }
199
+ return ConfirmResult . SAVE ;
133
200
}
134
201
135
202
setLanguageId ( languageId : string , _setExplicitly ?: boolean ) : void {
0 commit comments