提交 4928801c 编写于 作者: D Daniel Imms

Get untitled files restoring from backup

上级 86e1c202
......@@ -5,7 +5,7 @@
'use strict';
import {createDecorator} from 'vs/platform/instantiation/common/instantiation';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import Uri from 'vs/base/common/uri';
export const IBackupService = createDecorator<IBackupService>('backupService');
......@@ -20,5 +20,6 @@ export interface IBackupService {
registerBackupFile(resource: Uri): void;
deregisterBackupFile(resource: Uri): void;
getBackupFiles(workspace: string): string[];
getBackupUntitledFiles(workspace: string): string[];
getBackupResource(resource: Uri): Uri;
}
......@@ -62,9 +62,22 @@ export class BackupService implements IBackupService {
return this.fileContent.folderWorkspaces[workspace] || [];
}
public getBackupUntitledFiles(workspace: string): string[] {
const workspaceHash = crypto.createHash('md5').update(this.workspaceResource.fsPath).digest('hex');
const untitledDir = path.join(this.environmentService.userDataPath, 'Backups', workspaceHash, 'untitled');
try {
const untitledFiles = fs.readdirSync(untitledDir).map(file => path.join(untitledDir, file));
console.log('untitledFiles', untitledFiles);
return untitledFiles;
} catch (ex) {
console.log('untitled backups do not exist');
return [];
}
}
public getBackupResource(resource: Uri): Uri {
let workspaceHash = crypto.createHash('md5').update(this.workspaceResource.fsPath).digest('hex');
const workspaceHash = crypto.createHash('md5').update(this.workspaceResource.fsPath).digest('hex');
const backupName = crypto.createHash('md5').update(resource.fsPath).digest('hex');
const backupPath = path.join(this.environmentService.userDataPath, 'Backups', workspaceHash, resource.scheme, backupName);
console.log('getBackupResource ' + Uri.file(backupPath));
......
......@@ -19,6 +19,9 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import Event, { Emitter } from 'vs/base/common/event';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
// TODO: This file cannot depend on native node modules
import fs = require('fs');
/**
* An editor input to be used for untitled text buffers.
*/
......@@ -28,6 +31,7 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput {
public static SCHEMA: string = 'untitled';
private resource: URI;
private restoreResource: URI;
private hasAssociatedFilePath: boolean;
private modeId: string;
private cachedModel: UntitledEditorModel;
......@@ -46,7 +50,7 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput {
@ITextFileService private textFileService: ITextFileService
) {
super();
console.log('UntitledEditorInput constructor', resource, hasAssociatedFilePath, modeId);
this.resource = resource;
this.hasAssociatedFilePath = hasAssociatedFilePath;
this.modeId = modeId;
......@@ -66,6 +70,10 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput {
return this.resource;
}
public setRestoreResource(resource: URI): void {
this.restoreResource = resource;
}
public getName(): string {
return this.hasAssociatedFilePath ? paths.basename(this.resource.fsPath) : this.resource.fsPath;
}
......@@ -140,7 +148,11 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput {
}
private createModel(): UntitledEditorModel {
const content = '';
let content = '';
if (this.restoreResource) {
// TODO: This loading should probably go through fileService, fs cannot be a dependency in common/
content = fs.readFileSync(this.restoreResource.fsPath, 'utf8');
}
const model = this.instantiationService.createInstance(UntitledEditorModel, content, this.modeId, this.resource, this.hasAssociatedFilePath);
// re-emit some events from the model
......
......@@ -46,7 +46,7 @@ export class UntitledEditorModel extends StringEditorModel implements IEncodingS
super(value, modeId, resource, modeService, modelService);
this.hasAssociatedFilePath = hasAssociatedFilePath;
this.dirty = hasAssociatedFilePath; // untitled associated to file path are dirty right away
this.dirty = hasAssociatedFilePath || value !== ''; // untitled associated to file path are dirty right away
this._onDidChangeDirty = new Emitter<void>();
this._onDidChangeEncoding = new Emitter<void>();
......
......@@ -24,4 +24,5 @@ export interface IOptions {
filesToDiff?: IResourceInput[];
filesToRestore?: IResourceInput[];
untitledFilesToRestore?: IResourceInput[];
}
\ No newline at end of file
......@@ -176,8 +176,16 @@ export class Workbench implements IPartService {
options.filesToRestore = this.backupService.getBackupFiles(workspace.resource.fsPath).map(filePath => {
return { resource: Uri.file(filePath), options: { pinned: true } };
});
options.untitledFilesToRestore = this.backupService.getBackupUntitledFiles(workspace.resource.fsPath).map(untitledFilePath => {
return { resource: Uri.from({ path: untitledFilePath, scheme: 'untitled' }), options: { pinned: true } };
});
this.hasFilesToCreateOpenOrDiff = (options.filesToCreate && options.filesToCreate.length > 0) || (options.filesToOpen && options.filesToOpen.length > 0) || (options.filesToDiff && options.filesToDiff.length > 0) || (options.filesToRestore.length > 0);
this.hasFilesToCreateOpenOrDiff =
(options.filesToCreate && options.filesToCreate.length > 0) ||
(options.filesToOpen && options.filesToOpen.length > 0) ||
(options.filesToDiff && options.filesToDiff.length > 0) ||
(options.filesToRestore.length > 0) ||
(options.untitledFilesToRestore.length > 0);
this.toDispose = [];
this.toShutdown = [];
......@@ -305,6 +313,7 @@ export class Workbench implements IPartService {
const filesToCreate = wbopt.filesToCreate || [];
const filesToOpen = wbopt.filesToOpen || [];
const filesToRestore = wbopt.filesToRestore || [];
const untitledFilesToRestore = wbopt.untitledFilesToRestore || [];
const filesToDiff = wbopt.filesToDiff;
// Files to diff is exclusive
......@@ -323,9 +332,14 @@ export class Workbench implements IPartService {
inputs.push(...filesToCreate.map(resourceInput => this.untitledEditorService.createOrGet(resourceInput.resource)));
options.push(...filesToCreate.map(r => null)); // fill empty options for files to create because we dont have options there
// Files to restore
inputs.push(...untitledFilesToRestore.map(resourceInput => this.untitledEditorService.createOrGet(null, null, resourceInput.resource)));
options.push(...untitledFilesToRestore.map(r => null)); // fill empty options for files to create because we dont have options there
// Files to open
let filesToOpenInputPromise = filesToOpen.map(resourceInput => this.editorService.createInput(resourceInput));
let filesToRestoreInputPromise = filesToRestore.map(resourceInput => this.editorService.createInput(resourceInput, true));
return TPromise.join<EditorInput>(filesToOpenInputPromise.concat(filesToRestoreInputPromise)).then((inputsToOpen) => {
inputs.push(...inputsToOpen);
options.push(...filesToOpen.concat(filesToRestore).map(resourceInput => TextEditorOptions.from(resourceInput)));
......
......@@ -459,10 +459,8 @@ export class FileService implements IFileService {
public backupFile(resource: uri, content: string): TPromise<IFileStat> {
if (resource.scheme === 'file') {
// TODO: Persist hash -> file map on disk (json file?)
this.backupService.registerBackupFile(resource);
}
this.backupService.registerBackupFile(resource);
const backupResource = this.getBackupPath(resource);
console.log(`Backing up to ${backupResource.fsPath}`);
return this.updateContent(backupResource, content);
......
......@@ -6,6 +6,7 @@
import URI from 'vs/base/common/uri';
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IBackupService } from 'vs/platform/backup/common/backup';
import arrays = require('vs/base/common/arrays');
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
import Event, { Emitter, once } from 'vs/base/common/event';
......@@ -58,7 +59,7 @@ export interface IUntitledEditorService {
* It is valid to pass in a file resource. In that case the path will be used as identifier.
* The use case is to be able to create a new file with a specific path with VSCode.
*/
createOrGet(resource?: URI, modeId?: string): UntitledEditorInput;
createOrGet(resource?: URI, modeId?: string, restoreResource?: URI): UntitledEditorInput;
/**
* A check to find out if a untitled resource has a file path associated or not.
......@@ -76,7 +77,10 @@ export class UntitledEditorService implements IUntitledEditorService {
private _onDidChangeDirty: Emitter<URI>;
private _onDidChangeEncoding: Emitter<URI>;
constructor( @IInstantiationService private instantiationService: IInstantiationService) {
constructor(
@IBackupService private backupService: IBackupService,
@IInstantiationService private instantiationService: IInstantiationService
) {
this._onDidChangeDirty = new Emitter<URI>();
this._onDidChangeEncoding = new Emitter<URI>();
}
......@@ -130,7 +134,7 @@ export class UntitledEditorService implements IUntitledEditorService {
.map((i) => i.getResource());
}
public createOrGet(resource?: URI, modeId?: string): UntitledEditorInput {
public createOrGet(resource?: URI, modeId?: string, restoreResource?: URI): UntitledEditorInput {
let hasAssociatedFilePath = false;
if (resource) {
hasAssociatedFilePath = (resource.scheme === 'file');
......@@ -147,10 +151,10 @@ export class UntitledEditorService implements IUntitledEditorService {
}
// Create new otherwise
return this.doCreate(resource, hasAssociatedFilePath, modeId);
return this.doCreate(resource, hasAssociatedFilePath, modeId, restoreResource);
}
private doCreate(resource?: URI, hasAssociatedFilePath?: boolean, modeId?: string): UntitledEditorInput {
private doCreate(resource?: URI, hasAssociatedFilePath?: boolean, modeId?: string, restoreResource?: URI): UntitledEditorInput {
if (!resource) {
// Create new taking a resource URI that is not already taken
......@@ -162,6 +166,9 @@ export class UntitledEditorService implements IUntitledEditorService {
}
const input = this.instantiationService.createInstance(UntitledEditorInput, resource, hasAssociatedFilePath, modeId);
if (restoreResource) {
input.setRestoreResource(restoreResource);
}
const dirtyListener = input.onDidChangeDirty(() => {
this._onDidChangeDirty.fire(resource);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册