Skip to content

Commit b23229f

Browse files
committed
Have TextFileEditorModel handle restores
This change does the following: - filesToRestore are no longer checked at all, instead the the already existing editorStacks.model value from local storage restores the files just like normal. - Loading of the resource is now solely the responsibility of TextFileEditorModel, removing a lot of the stuff being passed down through the layers. Fixes microsoft#14100 Fixes microsoft#14067
1 parent d40ffa4 commit b23229f

9 files changed

Lines changed: 81 additions & 50 deletions

File tree

src/vs/platform/backup/common/backup.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ export interface IBackupService {
5959
*/
6060
getWorkspaceUntitledFileBackupsSync(workspace: Uri): string[];
6161

62+
/**
63+
* Gets whether a text file has a backup to restore.
64+
*
65+
* @param resource The resource to check.
66+
* @returns Whether the file has a backup.
67+
*/
68+
doesTextFileHaveBackup(resource: Uri): TPromise<boolean>;
69+
6270
/**
6371
* Registers a resource for backup, flagging it for restoration.
6472
*

src/vs/platform/backup/node/backupService.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ export class BackupService implements IBackupService {
115115
}
116116
}
117117

118+
public doesTextFileHaveBackup(resource: Uri): TPromise<boolean> {
119+
return this.load().then(() => {
120+
return arrays.contains(this.fileContent.folderWorkspaces[this.workspaceResource.fsPath] || [], resource.fsPath);
121+
});
122+
}
123+
118124
public getBackupResource(resource: Uri): Uri {
119125
// Hot exit is disabled for empty workspaces
120126
if (!this.workspaceResource) {

src/vs/platform/backup/test/backupService.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,22 @@ suite('BackupService', () => {
172172
});
173173
});
174174
});
175+
176+
test('doesTextFileHaveBackup should return whether a backup resource exists', done => {
177+
backupService.setCurrentWorkspace(fooFile);
178+
backupService.doesTextFileHaveBackup(barFile).then(exists => {
179+
assert.equal(exists, false);
180+
backupService.registerResourceForBackup(barFile).then(() => {
181+
backupService.doesTextFileHaveBackup(barFile).then(exists2 => {
182+
assert.equal(exists2, true);
183+
backupService.deregisterResourceForBackup(barFile).then(() => {
184+
backupService.doesTextFileHaveBackup(barFile).then(exists3 => {
185+
assert.equal(exists3, false);
186+
done();
187+
});
188+
});
189+
});
190+
});
191+
});
192+
});
175193
});

src/vs/test/utils/servicesTestUtils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,10 @@ export class TestBackupService implements IBackupService {
622622
return [];
623623
}
624624

625+
public doesTextFileHaveBackup(resource: URI): TPromise<boolean> {
626+
return TPromise.as(false);
627+
}
628+
625629
public registerResourceForBackup(resource: URI): TPromise<void> {
626630
this.registeredResources.push(resource);
627631
return TPromise.as(void 0);

src/vs/workbench/browser/parts/editor/editorPart.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -909,7 +909,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
909909
return this.doOpenEditors(editors, activePosition, ratio);
910910
}
911911

912-
public restoreEditors(): TPromise<BaseEditor[]> {
912+
public restoreEditors(untitledToRestoreInputs?: EditorInput[]): TPromise<BaseEditor[]> {
913913
const editors = this.stacks.groups.map((group, index) => {
914914
return {
915915
input: group.activeEditor,
@@ -918,6 +918,17 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
918918
};
919919
});
920920

921+
// Add any untitled files to be restored from backup
922+
if (untitledToRestoreInputs && untitledToRestoreInputs.length) {
923+
editors.push(...untitledToRestoreInputs.map(input => {
924+
return {
925+
input: input,
926+
position: Position.ONE,
927+
options: null
928+
};
929+
}));
930+
}
931+
921932
if (!editors.length) {
922933
return TPromise.as<BaseEditor[]>([]);
923934
}

src/vs/workbench/electron-browser/workbench.ts

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,6 @@ export class Workbench implements IPartService {
175175

176176
// Restore any backups if they exist for this workspace (empty workspaces are not supported yet)
177177
if (workspace) {
178-
options.filesToRestore = this.backupService.getWorkspaceTextFilesWithBackupsSync(workspace.resource).map(filePath => {
179-
return { resource: Uri.file(filePath), options: { pinned: true } };
180-
});
181178
options.untitledFilesToRestore = this.backupService.getWorkspaceUntitledFileBackupsSync(workspace.resource).map(untitledFilePath => {
182179
return { resource: Uri.file(untitledFilePath), options: { pinned: true } };
183180
});
@@ -186,9 +183,7 @@ export class Workbench implements IPartService {
186183
this.hasFilesToCreateOpenOrDiff =
187184
(options.filesToCreate && options.filesToCreate.length > 0) ||
188185
(options.filesToOpen && options.filesToOpen.length > 0) ||
189-
(options.filesToDiff && options.filesToDiff.length > 0) ||
190-
(options.filesToRestore && options.filesToRestore.length > 0) ||
191-
(options.untitledFilesToRestore && options.untitledFilesToRestore.length > 0);
186+
(options.filesToDiff && options.filesToDiff.length > 0);
192187

193188
this.toDispose = [];
194189
this.toShutdown = [];
@@ -273,7 +268,14 @@ export class Workbench implements IPartService {
273268

274269
editorOpenPromise = this.editorPart.openEditors(editors);
275270
} else {
276-
editorOpenPromise = this.editorPart.restoreEditors();
271+
if (this.workbenchParams.options.untitledFilesToRestore && this.workbenchParams.options.untitledFilesToRestore.length) {
272+
const untitledToRestoreInputs = this.workbenchParams.options.untitledFilesToRestore.map(resourceInput => {
273+
return this.untitledEditorService.createOrGet(null, null, resourceInput.resource);
274+
});
275+
editorOpenPromise = this.editorPart.restoreEditors(untitledToRestoreInputs);
276+
} else {
277+
editorOpenPromise = this.editorPart.restoreEditors();
278+
}
277279
}
278280

279281
return editorOpenPromise.then(() => {
@@ -315,8 +317,6 @@ export class Workbench implements IPartService {
315317
const wbopt = this.workbenchParams.options;
316318
const filesToCreate = wbopt.filesToCreate || [];
317319
const filesToOpen = wbopt.filesToOpen || [];
318-
const filesToRestore = wbopt.filesToRestore || [];
319-
const untitledFilesToRestore = wbopt.untitledFilesToRestore || [];
320320
const filesToDiff = wbopt.filesToDiff;
321321

322322
// Files to diff is exclusive
@@ -335,17 +335,12 @@ export class Workbench implements IPartService {
335335
inputs.push(...filesToCreate.map(resourceInput => this.untitledEditorService.createOrGet(resourceInput.resource)));
336336
options.push(...filesToCreate.map(r => null)); // fill empty options for files to create because we dont have options there
337337

338-
// Files to restore
339-
inputs.push(...untitledFilesToRestore.map(resourceInput => this.untitledEditorService.createOrGet(null, null, resourceInput.resource)));
340-
options.push(...untitledFilesToRestore.map(r => null)); // fill empty options for files to create because we dont have options there
341-
342338
// Files to open
343339
let filesToOpenInputPromise = filesToOpen.map(resourceInput => this.editorService.createInput(resourceInput));
344-
let filesToRestoreInputPromise = filesToRestore.map(resourceInput => this.editorService.createInput(resourceInput, true));
345340

346-
return TPromise.join<EditorInput>(filesToOpenInputPromise.concat(filesToRestoreInputPromise)).then((inputsToOpen) => {
341+
return TPromise.join<EditorInput>(filesToOpenInputPromise).then((inputsToOpen) => {
347342
inputs.push(...inputsToOpen);
348-
options.push(...filesToOpen.concat(filesToRestore).map(resourceInput => TextEditorOptions.from(resourceInput)));
343+
options.push(...filesToOpen.map(resourceInput => TextEditorOptions.from(resourceInput)));
349344

350345
return inputs.map((input, index) => { return { input, options: options[index] }; });
351346
});

src/vs/workbench/services/editor/browser/editorService.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,8 @@ export class WorkbenchEditorService implements IWorkbenchEditorService {
208208
}
209209

210210
public createInput(input: EditorInput): TPromise<EditorInput>;
211-
public createInput(input: IResourceInput, restoreFromBackup?: boolean): TPromise<EditorInput>;
212-
public createInput(input: any, restoreFromBackup?: boolean): TPromise<IEditorInput> {
211+
public createInput(input: IResourceInput): TPromise<EditorInput>;
212+
public createInput(input: any): TPromise<IEditorInput> {
213213

214214
// Workbench Input Support
215215
if (input instanceof EditorInput) {
@@ -263,7 +263,7 @@ export class WorkbenchEditorService implements IWorkbenchEditorService {
263263

264264
// Base Text Editor Support for file resources
265265
else if (this.fileInputDescriptor && resourceInput.resource instanceof URI && resourceInput.resource.scheme === network.Schemas.file) {
266-
return this.createFileInput(resourceInput.resource, resourceInput.encoding, restoreFromBackup);
266+
return this.createFileInput(resourceInput.resource, resourceInput.encoding);
267267
}
268268

269269
// Treat an URI as ResourceEditorInput
@@ -277,11 +277,10 @@ export class WorkbenchEditorService implements IWorkbenchEditorService {
277277
return TPromise.as<EditorInput>(null);
278278
}
279279

280-
private createFileInput(resource: URI, encoding?: string, restoreFromBackup?: boolean): TPromise<IFileEditorInput> {
280+
private createFileInput(resource: URI, encoding?: string): TPromise<IFileEditorInput> {
281281
return this.instantiationService.createInstance(this.fileInputDescriptor).then((typedFileInput) => {
282282
typedFileInput.setResource(resource);
283283
typedFileInput.setPreferredEncoding(encoding);
284-
typedFileInput.setRestoreFromBackup(restoreFromBackup);
285284

286285
return typedFileInput;
287286
});

src/vs/workbench/services/textfile/common/textFileEditorModel.ts

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
1616
import paths = require('vs/base/common/paths');
1717
import diagnostics = require('vs/base/common/diagnostics');
1818
import types = require('vs/base/common/types');
19-
import { IModelContentChangedEvent } from 'vs/editor/common/editorCommon';
19+
import { IModelContentChangedEvent, IRawText } from 'vs/editor/common/editorCommon';
2020
import { IMode } from 'vs/editor/common/modes';
2121
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
2222
import { ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, IModelSaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
2323
import { EncodingMode, EditorModel } from 'vs/workbench/common/editor';
2424
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
25+
import { IBackupService } from 'vs/platform/backup/common/backup';
2526
import { IFileService, IFileStat, IFileOperationResult, FileOperationResult } from 'vs/platform/files/common/files';
2627
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
2728
import { IMessageService, Severity } from 'vs/platform/message/common/message';
@@ -40,7 +41,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
4041
private static saveParticipant: ISaveParticipant;
4142

4243
private resource: URI;
43-
private restoreResource: URI;
4444
private contentEncoding: string; // encoding as reported from disk
4545
private preferredEncoding: string; // encoding as chosen by the user
4646
private dirty: boolean;
@@ -71,7 +71,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
7171
@ILifecycleService private lifecycleService: ILifecycleService,
7272
@IInstantiationService private instantiationService: IInstantiationService,
7373
@ITelemetryService private telemetryService: ITelemetryService,
74-
@ITextFileService private textFileService: ITextFileService
74+
@ITextFileService private textFileService: ITextFileService,
75+
@IBackupService private backupService: IBackupService
7576
) {
7677
super(modelService, modeService);
7778

@@ -183,10 +184,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
183184
});
184185
}
185186

186-
public setRestoreResource(resource: URI): void {
187-
this.restoreResource = resource;
188-
}
189-
190187
public load(force?: boolean /* bypass any caches and really go to disk */): TPromise<EditorModel> {
191188
diag('load() - enter', this.resource, new Date());
192189

@@ -264,12 +261,20 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
264261
else {
265262
diag('load() - created text editor model', this.resource, new Date());
266263

267-
if (this.restoreResource) {
268-
this.createTextEditorModelPromise = this.textFileService.resolveTextContent(this.restoreResource, { acceptTextOnly: true, etag: etag, encoding: this.preferredEncoding }).then((restoreContent) => {
269-
return this.createTextEditorModel(restoreContent.value, content.resource).then(() => {
264+
return this.backupService.doesTextFileHaveBackup(this.resource).then(backupExists => {
265+
let getContentPromise: TPromise<IRawText>;
266+
if (backupExists) {
267+
const restoreResource = this.backupService.getBackupResource(this.resource);
268+
getContentPromise = this.textFileService.resolveTextContent(restoreResource, { acceptTextOnly: true, etag: etag, encoding: this.preferredEncoding }).then(content => content.value);
269+
} else {
270+
getContentPromise = TPromise.as(content.value);
271+
}
272+
273+
this.createTextEditorModelPromise = getContentPromise.then(fileContent => {
274+
return this.createTextEditorModel(fileContent, content.resource).then(() => {
270275
this.createTextEditorModelPromise = null;
271276

272-
this.setDirty(true);
277+
this.setDirty(backupExists); // Ensure we are not tracking a stale state
273278
this.toDispose.push(this.textEditorModel.onDidChangeRawContent((e: IModelContentChangedEvent) => this.onModelContentChanged(e)));
274279

275280
return this;
@@ -279,22 +284,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
279284
return TPromise.wrapError(error);
280285
});
281286
});
282-
} else {
283-
this.createTextEditorModelPromise = this.createTextEditorModel(content.value, content.resource).then(() => {
284-
this.createTextEditorModelPromise = null;
285-
286-
this.setDirty(false); // Ensure we are not tracking a stale state
287-
this.toDispose.push(this.textEditorModel.onDidChangeRawContent((e: IModelContentChangedEvent) => this.onModelContentChanged(e)));
288-
289-
return this;
290-
}, (error) => {
291-
this.createTextEditorModelPromise = null;
292287

293-
return TPromise.wrapError(error);
294-
});
295-
}
296-
297-
return this.createTextEditorModelPromise;
288+
return this.createTextEditorModelPromise;
289+
});
298290
}
299291
}, (error) => {
300292

src/vs/workbench/services/textfile/common/textfiles.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,6 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport
219219

220220
backup(): TPromise<void>;
221221

222-
setRestoreResource(resource: URI): void;
223-
224222
revert(): TPromise<void>;
225223

226224
setConflictResolutionMode();

0 commit comments

Comments
 (0)