Skip to content

Commit 2aa63c8

Browse files
committed
prompt users when scratchpads will be lost on close
1 parent e0d2557 commit 2aa63c8

File tree

3 files changed

+56
-39
lines changed

3 files changed

+56
-39
lines changed

src/vs/workbench/services/workingCopy/browser/workingCopyBackupTracker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export class BrowserWorkingCopyBackupTracker extends WorkingCopyBackupTracker im
4141
return false; // nothing modified: no veto
4242
}
4343

44-
if (this.workingCopyService.hasDirty && !this.filesConfigurationService.isHotExitEnabled) {
45-
return true; // dirty without backup: veto
44+
if (!this.filesConfigurationService.isHotExitEnabled) {
45+
return true; // modified without backup: veto
4646
}
4747

4848
for (const modifiedWorkingCopy of modifiedWorkingCopies) {

src/vs/workbench/services/workingCopy/common/workingCopyService.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ export interface IWorkingCopyService {
6868
*/
6969
readonly dirtyWorkingCopies: readonly IWorkingCopy[];
7070

71+
/**
72+
* The number of dirty working copies that are registered.
73+
*/
74+
readonly modifiedCount: number;
75+
7176
/**
7277
* All working copies with unsaved changes,
7378
* including scratchpads, which are never dirty
@@ -271,6 +276,18 @@ export class WorkingCopyService extends Disposable implements IWorkingCopyServic
271276
return this.workingCopies.filter(workingCopy => workingCopy.isDirty());
272277
}
273278

279+
get modifiedCount(): number {
280+
let totalModifiedCount = 0;
281+
282+
for (const workingCopy of this._workingCopies) {
283+
if (workingCopy.isModified()) {
284+
totalModifiedCount++;
285+
}
286+
}
287+
288+
return totalModifiedCount;
289+
}
290+
274291
get modifiedWorkingCopies(): IWorkingCopy[] {
275292
return this.workingCopies.filter(workingCopy => workingCopy.isModified());
276293
}

src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupTracker.ts

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp
4949

5050
protected async onFinalBeforeShutdown(reason: ShutdownReason): Promise<boolean> {
5151

52-
// Important: we are about to shutdown and handle dirty working copies
52+
// Important: we are about to shutdown and handle modified working copies
5353
// and backups. We do not want any pending backup ops to interfer with
5454
// this because there is a risk of a backup being scheduled after we have
5555
// acknowledged to shutdown and then might end up with partial backups
@@ -67,13 +67,13 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp
6767

6868
try {
6969

70-
// Dirty working copies need treatment on shutdown
70+
// Modified working copies need treatment on shutdown
7171
const modifiedWorkingCopies = this.workingCopyService.modifiedWorkingCopies;
7272
if (modifiedWorkingCopies.length) {
7373
return await this.onBeforeShutdownWithModified(reason, modifiedWorkingCopies);
7474
}
7575

76-
// No dirty working copies
76+
// No modified working copies
7777
else {
7878
return await this.onBeforeShutdownWithoutModified();
7979
}
@@ -85,18 +85,18 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp
8585
protected async onBeforeShutdownWithModified(reason: ShutdownReason, modifiedWorkingCopies: readonly IWorkingCopy[]): Promise<boolean> {
8686

8787
// If auto save is enabled, save all non-untitled working copies
88-
// and then check again for dirty copies
88+
// and then check again for modified copies
8989

9090
if (this.filesConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF) {
9191

92-
// Save all dirty working copies
92+
// Save all modified working copies
9393
try {
9494
await this.doSaveAllBeforeShutdown(false /* not untitled */, SaveReason.AUTO);
9595
} catch (error) {
96-
this.logService.error(`[backup tracker] error saving dirty working copies: ${error}`); // guard against misbehaving saves, we handle remaining dirty below
96+
this.logService.error(`[backup tracker] error saving modified working copies: ${error}`); // guard against misbehaving saves, we handle remaining modified below
9797
}
9898

99-
// If we still have dirty working copies, we either have untitled ones or working copies that cannot be saved
99+
// If we still have modified working copies, we either have untitled ones or working copies that cannot be saved
100100
const remainingModifiedWorkingCopies = this.workingCopyService.modifiedWorkingCopies;
101101
if (remainingModifiedWorkingCopies.length) {
102102
return this.handleModifiedBeforeShutdown(remainingModifiedWorkingCopies, reason);
@@ -129,6 +129,8 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp
129129
}
130130
}
131131

132+
const remainingModifiedWorkingCopies = modifiedWorkingCopies.filter(workingCopy => !backups.includes(workingCopy));
133+
132134
// We ran a backup but received an error that we show to the user
133135
if (backupError) {
134136
if (this.environmentService.isExtensionDevelopment) {
@@ -137,7 +139,6 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp
137139
return false; // do not block shutdown during extension development (https://github.com/microsoft/vscode/issues/115028)
138140
}
139141

140-
const remainingModifiedWorkingCopies = modifiedWorkingCopies.filter(workingCopy => !backups.includes(workingCopy));
141142
this.showErrorDialog(localize('backupTrackerBackupFailed', "The following editors with unsaved changes could not be saved to the back up location."), remainingModifiedWorkingCopies, backupError);
142143

143144
return true; // veto (the backup failed)
@@ -146,17 +147,16 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp
146147
// Since a backup did not happen, we have to confirm for
147148
// the working copies that did not successfully backup
148149

149-
const remainingDirtyWorkingCopies = modifiedWorkingCopies.filter(workingCopy => !backups.includes(workingCopy) && workingCopy.isDirty());
150150
try {
151-
return await this.confirmBeforeShutdown(remainingDirtyWorkingCopies);
151+
return await this.confirmBeforeShutdown(remainingModifiedWorkingCopies);
152152
} catch (error) {
153153
if (this.environmentService.isExtensionDevelopment) {
154-
this.logService.error(`[backup tracker] error saving or reverting dirty working copies: ${error}`);
154+
this.logService.error(`[backup tracker] error saving or reverting modified working copies: ${error}`);
155155

156156
return false; // do not block shutdown during extension development (https://github.com/microsoft/vscode/issues/115028)
157157
}
158158

159-
this.showErrorDialog(localize('backupTrackerConfirmFailed', "The following editors with unsaved changes could not be saved or reverted."), remainingDirtyWorkingCopies, error);
159+
this.showErrorDialog(localize('backupTrackerConfirmFailed', "The following editors with unsaved changes could not be saved or reverted."), remainingModifiedWorkingCopies, error);
160160

161161
return true; // veto (save or revert failed)
162162
}
@@ -224,7 +224,7 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp
224224

225225
await this.withProgressAndCancellation(async token => {
226226

227-
// Perform a backup of all dirty working copies unless a backup already exists
227+
// Perform a backup of all modified working copies unless a backup already exists
228228
try {
229229
await Promises.settled(modifiedWorkingCopies.map(async workingCopy => {
230230

@@ -260,46 +260,46 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp
260260
return { backups, error };
261261
}
262262

263-
private async confirmBeforeShutdown(dirtyWorkingCopies: IWorkingCopy[]): Promise<boolean> {
263+
private async confirmBeforeShutdown(modifiedWorkingCopies: IWorkingCopy[]): Promise<boolean> {
264264

265265
// Save
266-
const confirm = await this.fileDialogService.showSaveConfirm(dirtyWorkingCopies.map(workingCopy => workingCopy.name));
266+
const confirm = await this.fileDialogService.showSaveConfirm(modifiedWorkingCopies.map(workingCopy => workingCopy.name));
267267
if (confirm === ConfirmResult.SAVE) {
268-
const dirtyCountBeforeSave = this.workingCopyService.dirtyCount;
268+
const modifiedCountBeforeSave = this.workingCopyService.modifiedCount;
269269

270270
try {
271-
await this.doSaveAllBeforeShutdown(dirtyWorkingCopies, SaveReason.EXPLICIT);
271+
await this.doSaveAllBeforeShutdown(modifiedWorkingCopies, SaveReason.EXPLICIT);
272272
} catch (error) {
273-
this.logService.error(`[backup tracker] error saving dirty working copies: ${error}`); // guard against misbehaving saves, we handle remaining dirty below
273+
this.logService.error(`[backup tracker] error saving modified working copies: ${error}`); // guard against misbehaving saves, we handle remaining modified below
274274
}
275275

276-
const savedWorkingCopies = dirtyCountBeforeSave - this.workingCopyService.dirtyCount;
277-
if (savedWorkingCopies < dirtyWorkingCopies.length) {
276+
const savedWorkingCopies = modifiedCountBeforeSave - this.workingCopyService.modifiedCount;
277+
if (savedWorkingCopies < modifiedWorkingCopies.length) {
278278
return true; // veto (save failed or was canceled)
279279
}
280280

281-
return this.noVeto(dirtyWorkingCopies); // no veto (dirty saved)
281+
return this.noVeto(modifiedWorkingCopies); // no veto (modified saved)
282282
}
283283

284284
// Don't Save
285285
else if (confirm === ConfirmResult.DONT_SAVE) {
286286
try {
287-
await this.doRevertAllBeforeShutdown(dirtyWorkingCopies);
287+
await this.doRevertAllBeforeShutdown(modifiedWorkingCopies);
288288
} catch (error) {
289-
this.logService.error(`[backup tracker] error reverting dirty working copies: ${error}`); // do not block the shutdown on errors from revert
289+
this.logService.error(`[backup tracker] error reverting modified working copies: ${error}`); // do not block the shutdown on errors from revert
290290
}
291291

292-
return this.noVeto(dirtyWorkingCopies); // no veto (dirty reverted)
292+
return this.noVeto(modifiedWorkingCopies); // no veto (modified reverted)
293293
}
294294

295295
// Cancel
296296
return true; // veto (user canceled)
297297
}
298298

299-
private doSaveAllBeforeShutdown(dirtyWorkingCopies: IWorkingCopy[], reason: SaveReason): Promise<void>;
299+
private doSaveAllBeforeShutdown(modifiedWorkingCopies: IWorkingCopy[], reason: SaveReason): Promise<void>;
300300
private doSaveAllBeforeShutdown(includeUntitled: boolean, reason: SaveReason): Promise<void>;
301301
private doSaveAllBeforeShutdown(arg1: IWorkingCopy[] | boolean, reason: SaveReason): Promise<void> {
302-
const dirtyWorkingCopies = Array.isArray(arg1) ? arg1 : this.workingCopyService.dirtyWorkingCopies.filter(workingCopy => {
302+
const modifiedWorkingCopies = Array.isArray(arg1) ? arg1 : this.workingCopyService.modifiedWorkingCopies.filter(workingCopy => {
303303
if (arg1 === false && (workingCopy.capabilities & WorkingCopyCapabilities.Untitled)) {
304304
return false; // skip untitled unless explicitly included
305305
}
@@ -313,40 +313,40 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp
313313
const saveOptions = { skipSaveParticipants: true, reason };
314314

315315
// First save through the editor service if we save all to benefit
316-
// from some extras like switching to untitled dirty editors before saving.
316+
// from some extras like switching to untitled modified editors before saving.
317317

318318
let result: boolean | undefined = undefined;
319-
if (typeof arg1 === 'boolean' || dirtyWorkingCopies.length === this.workingCopyService.dirtyCount) {
319+
if (typeof arg1 === 'boolean' || modifiedWorkingCopies.length === this.workingCopyService.modifiedCount) {
320320
result = (await this.editorService.saveAll({ includeUntitled: typeof arg1 === 'boolean' ? arg1 : true, ...saveOptions })).success;
321321
}
322322

323-
// If we still have dirty working copies, save those directly
323+
// If we still have modified working copies, save those directly
324324
// unless the save was not successful (e.g. cancelled)
325325
if (result !== false) {
326-
await Promises.settled(dirtyWorkingCopies.map(workingCopy => workingCopy.isDirty() ? workingCopy.save(saveOptions) : Promise.resolve(true)));
326+
await Promises.settled(modifiedWorkingCopies.map(workingCopy => workingCopy.isModified() ? workingCopy.save(saveOptions) : Promise.resolve(true)));
327327
}
328328
}, localize('saveBeforeShutdown', "Saving editors with unsaved changes is taking a bit longer..."));
329329
}
330330

331-
private doRevertAllBeforeShutdown(dirtyWorkingCopies: IWorkingCopy[]): Promise<void> {
331+
private doRevertAllBeforeShutdown(modifiedWorkingCopies: IWorkingCopy[]): Promise<void> {
332332
return this.withProgressAndCancellation(async () => {
333333

334334
// Soft revert is good enough on shutdown
335335
const revertOptions = { soft: true };
336336

337337
// First revert through the editor service if we revert all
338-
if (dirtyWorkingCopies.length === this.workingCopyService.dirtyCount) {
338+
if (modifiedWorkingCopies.length === this.workingCopyService.modifiedCount) {
339339
await this.editorService.revertAll(revertOptions);
340340
}
341341

342-
// If we still have dirty working copies, revert those directly
343-
await Promises.settled(dirtyWorkingCopies.map(workingCopy => workingCopy.isDirty() ? workingCopy.revert(revertOptions) : Promise.resolve()));
342+
// If we still have modified working copies, revert those directly
343+
await Promises.settled(modifiedWorkingCopies.map(workingCopy => workingCopy.isModified() ? workingCopy.revert(revertOptions) : Promise.resolve()));
344344
}, localize('revertBeforeShutdown', "Reverting editors with unsaved changes is taking a bit longer..."));
345345
}
346346

347347
private onBeforeShutdownWithoutModified(): Promise<boolean> {
348348

349-
// We are about to shutdown without dirty editors
349+
// We are about to shutdown without modified editors
350350
// and will discard any backups that are still
351351
// around that have not been handled depending
352352
// on the window state.
@@ -375,7 +375,7 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp
375375

376376
await this.discardBackupsBeforeShutdown(arg1);
377377

378-
return false; // no veto (no dirty)
378+
return false; // no veto (no modified)
379379
}
380380

381381
private discardBackupsBeforeShutdown(backupsToDiscard: IWorkingCopyIdentifier[]): Promise<void>;
@@ -394,7 +394,7 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp
394394

395395
await this.withProgressAndCancellation(async () => {
396396

397-
// When we shutdown either with no dirty working copies left
397+
// When we shutdown either with no modified working copies left
398398
// or with some handled, we start to discard these backups
399399
// to free them up. This helps to get rid of stale backups
400400
// as reported in https://github.com/microsoft/vscode/issues/92962

0 commit comments

Comments
 (0)