@@ -21,7 +21,12 @@ import { LinkedList } from 'vs/base/common/linkedList';
21
21
import { CancellationToken } from 'vs/base/common/cancellation' ;
22
22
import { ILifecycleService , ShutdownReason } from 'vs/workbench/services/lifecycle/common/lifecycle' ;
23
23
import { IDialogService } from 'vs/platform/dialogs/common/dialogs' ;
24
- import { ResourceMap } from 'vs/base/common/map' ;
24
+ import { ResourceMap , ResourceSet } from 'vs/base/common/map' ;
25
+ import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService' ;
26
+ import { URI } from 'vs/base/common/uri' ;
27
+ import { Registry } from 'vs/platform/registry/common/platform' ;
28
+ import { Extensions , IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry' ;
29
+ import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
25
30
26
31
class BulkEdit {
27
32
@@ -67,10 +72,10 @@ class BulkEdit {
67
72
}
68
73
}
69
74
70
- async perform ( ) : Promise < void > {
75
+ async perform ( ) : Promise < readonly URI [ ] > {
71
76
72
77
if ( this . _edits . length === 0 ) {
73
- return ;
78
+ return [ ] ;
74
79
}
75
80
76
81
const ranges : number [ ] = [ 1 ] ;
@@ -88,41 +93,44 @@ class BulkEdit {
88
93
// Increment by percentage points since progress API expects that
89
94
const progress : IProgress < void > = { report : _ => this . _progress . report ( { increment : 100 / this . _edits . length } ) } ;
90
95
96
+ const resources : ( readonly URI [ ] ) [ ] = [ ] ;
91
97
let index = 0 ;
92
98
for ( let range of ranges ) {
93
99
if ( this . _token . isCancellationRequested ) {
94
100
break ;
95
101
}
96
102
const group = this . _edits . slice ( index , index + range ) ;
97
103
if ( group [ 0 ] instanceof ResourceFileEdit ) {
98
- await this . _performFileEdits ( < ResourceFileEdit [ ] > group , this . _undoRedoGroup , this . _undoRedoSource , this . _confirmBeforeUndo , progress ) ;
104
+ resources . push ( await this . _performFileEdits ( < ResourceFileEdit [ ] > group , this . _undoRedoGroup , this . _undoRedoSource , this . _confirmBeforeUndo , progress ) ) ;
99
105
} else if ( group [ 0 ] instanceof ResourceTextEdit ) {
100
- await this . _performTextEdits ( < ResourceTextEdit [ ] > group , this . _undoRedoGroup , this . _undoRedoSource , progress ) ;
106
+ resources . push ( await this . _performTextEdits ( < ResourceTextEdit [ ] > group , this . _undoRedoGroup , this . _undoRedoSource , progress ) ) ;
101
107
} else if ( group [ 0 ] instanceof ResourceNotebookCellEdit ) {
102
- await this . _performCellEdits ( < ResourceNotebookCellEdit [ ] > group , this . _undoRedoGroup , this . _undoRedoSource , progress ) ;
108
+ resources . push ( await this . _performCellEdits ( < ResourceNotebookCellEdit [ ] > group , this . _undoRedoGroup , this . _undoRedoSource , progress ) ) ;
103
109
} else {
104
110
console . log ( 'UNKNOWN EDIT' ) ;
105
111
}
106
112
index = index + range ;
107
113
}
114
+
115
+ return resources . flat ( ) ;
108
116
}
109
117
110
- private async _performFileEdits ( edits : ResourceFileEdit [ ] , undoRedoGroup : UndoRedoGroup , undoRedoSource : UndoRedoSource | undefined , confirmBeforeUndo : boolean , progress : IProgress < void > ) {
118
+ private async _performFileEdits ( edits : ResourceFileEdit [ ] , undoRedoGroup : UndoRedoGroup , undoRedoSource : UndoRedoSource | undefined , confirmBeforeUndo : boolean , progress : IProgress < void > ) : Promise < readonly URI [ ] > {
111
119
this . _logService . debug ( '_performFileEdits' , JSON . stringify ( edits ) ) ;
112
120
const model = this . _instaService . createInstance ( BulkFileEdits , this . _label || localize ( 'workspaceEdit' , "Workspace Edit" ) , this . _code || 'undoredo.workspaceEdit' , undoRedoGroup , undoRedoSource , confirmBeforeUndo , progress , this . _token , edits ) ;
113
- await model . apply ( ) ;
121
+ return await model . apply ( ) ;
114
122
}
115
123
116
- private async _performTextEdits ( edits : ResourceTextEdit [ ] , undoRedoGroup : UndoRedoGroup , undoRedoSource : UndoRedoSource | undefined , progress : IProgress < void > ) : Promise < void > {
124
+ private async _performTextEdits ( edits : ResourceTextEdit [ ] , undoRedoGroup : UndoRedoGroup , undoRedoSource : UndoRedoSource | undefined , progress : IProgress < void > ) : Promise < readonly URI [ ] > {
117
125
this . _logService . debug ( '_performTextEdits' , JSON . stringify ( edits ) ) ;
118
126
const model = this . _instaService . createInstance ( BulkTextEdits , this . _label || localize ( 'workspaceEdit' , "Workspace Edit" ) , this . _code || 'undoredo.workspaceEdit' , this . _editor , undoRedoGroup , undoRedoSource , progress , this . _token , edits ) ;
119
- await model . apply ( ) ;
127
+ return await model . apply ( ) ;
120
128
}
121
129
122
- private async _performCellEdits ( edits : ResourceNotebookCellEdit [ ] , undoRedoGroup : UndoRedoGroup , undoRedoSource : UndoRedoSource | undefined , progress : IProgress < void > ) : Promise < void > {
130
+ private async _performCellEdits ( edits : ResourceNotebookCellEdit [ ] , undoRedoGroup : UndoRedoGroup , undoRedoSource : UndoRedoSource | undefined , progress : IProgress < void > ) : Promise < readonly URI [ ] > {
123
131
this . _logService . debug ( '_performCellEdits' , JSON . stringify ( edits ) ) ;
124
132
const model = this . _instaService . createInstance ( BulkCellEdits , undoRedoGroup , undoRedoSource , progress , this . _token , edits ) ;
125
- await model . apply ( ) ;
133
+ return await model . apply ( ) ;
126
134
}
127
135
}
128
136
@@ -138,7 +146,9 @@ export class BulkEditService implements IBulkEditService {
138
146
@ILogService private readonly _logService : ILogService ,
139
147
@IEditorService private readonly _editorService : IEditorService ,
140
148
@ILifecycleService private readonly _lifecycleService : ILifecycleService ,
141
- @IDialogService private readonly _dialogService : IDialogService
149
+ @IDialogService private readonly _dialogService : IDialogService ,
150
+ @IWorkingCopyService private readonly _workingCopyService : IWorkingCopyService ,
151
+ @IConfigurationService private readonly _configService : IConfigurationService ,
142
152
) { }
143
153
144
154
setPreviewHandler ( handler : IBulkEditPreviewHandler ) : IDisposable {
@@ -212,8 +222,15 @@ export class BulkEditService implements IBulkEditService {
212
222
213
223
let listener : IDisposable | undefined ;
214
224
try {
215
- listener = this . _lifecycleService . onBeforeShutdown ( e => e . veto ( this . shouldVeto ( label , e . reason ) , 'veto.blukEditService' ) ) ;
216
- await bulkEdit . perform ( ) ;
225
+ listener = this . _lifecycleService . onBeforeShutdown ( e => e . veto ( this . _shouldVeto ( label , e . reason ) , 'veto.blukEditService' ) ) ;
226
+ const resources = await bulkEdit . perform ( ) ;
227
+
228
+ // when enabled (option AND setting) loop over all dirty working copies and trigger save
229
+ // for those that were involved in this bulk edit operation.
230
+ if ( options ?. respectAutoSaveConfig && this . _configService . getValue ( autoSaveSetting ) === true && resources . length > 1 ) {
231
+ await this . _saveAll ( resources ) ;
232
+ }
233
+
217
234
return { ariaSummary : bulkEdit . ariaMessage ( ) } ;
218
235
} catch ( err ) {
219
236
// console.log('apply FAILED');
@@ -226,7 +243,23 @@ export class BulkEditService implements IBulkEditService {
226
243
}
227
244
}
228
245
229
- private async shouldVeto ( label : string | undefined , reason : ShutdownReason ) : Promise < boolean > {
246
+ private async _saveAll ( resources : readonly URI [ ] ) {
247
+ const set = new ResourceSet ( resources ) ;
248
+ const saves = this . _workingCopyService . dirtyWorkingCopies . map ( async ( copy ) => {
249
+ if ( set . has ( copy . resource ) ) {
250
+ await copy . save ( ) ;
251
+ }
252
+ } ) ;
253
+
254
+ const result = await Promise . allSettled ( saves ) ;
255
+ for ( const item of result ) {
256
+ if ( item . status === 'rejected' ) {
257
+ this . _logService . warn ( item . reason ) ;
258
+ }
259
+ }
260
+ }
261
+
262
+ private async _shouldVeto ( label : string | undefined , reason : ShutdownReason ) : Promise < boolean > {
230
263
label = label || localize ( 'fileOperation' , "File operation" ) ;
231
264
const reasonLabel = reason === ShutdownReason . CLOSE ? localize ( 'closeTheWindow' , "Close Window" ) : reason === ShutdownReason . LOAD ? localize ( 'changeWorkspace' , "Change Workspace" ) :
232
265
reason === ShutdownReason . RELOAD ? localize ( 'reloadTheWindow' , "Reload Window" ) : localize ( 'quit' , "Quit" ) ;
@@ -240,3 +273,16 @@ export class BulkEditService implements IBulkEditService {
240
273
}
241
274
242
275
registerSingleton ( IBulkEditService , BulkEditService , true ) ;
276
+
277
+ const autoSaveSetting = 'files.refactoring.autoSave' ;
278
+
279
+ Registry . as < IConfigurationRegistry > ( Extensions . Configuration ) . registerConfiguration ( {
280
+ id : 'files' ,
281
+ properties : {
282
+ [ autoSaveSetting ] : {
283
+ description : localize ( 'refactoring.autoSave' , "Controls if files that were part of a refactoring are saved automatically" ) ,
284
+ default : true ,
285
+ type : 'boolean'
286
+ }
287
+ }
288
+ } ) ;
0 commit comments