diff --git a/extensions/vscode-api-tests/src/workspace.test.ts b/extensions/vscode-api-tests/src/workspace.test.ts
index d4c4ae7013c18..4fccf98385b1d 100644
--- a/extensions/vscode-api-tests/src/workspace.test.ts
+++ b/extensions/vscode-api-tests/src/workspace.test.ts
@@ -505,4 +505,18 @@ suite('workspace-namespace', () => {
 			return vscode.workspace.applyEdit(edit);
 		});
 	});
+
+
+	test('applyEdit should fail when editing deleted resource', async () => {
+		const resource = await createRandomFile();
+
+		let edit = new vscode.WorkspaceEdit();
+		edit.deleteResource(resource);
+		try {
+			edit.insert(resource, new vscode.Position(0, 0), '');
+			assert.fail(false, 'Should disallow edit of deleted resource');
+		} catch {
+			// noop
+		}
+	});
 });
diff --git a/src/vs/editor/browser/services/bulkEdit.ts b/src/vs/editor/browser/services/bulkEdit.ts
index bfe4d9c4df32d..d5052d8c70624 100644
--- a/src/vs/editor/browser/services/bulkEdit.ts
+++ b/src/vs/editor/browser/services/bulkEdit.ts
@@ -18,6 +18,13 @@ import { Selection, ISelection } from 'vs/editor/common/core/selection';
 import { IIdentifiedSingleEditOperation, ITextModel, EndOfLineSequence } from 'vs/editor/common/model';
 import { IProgressRunner } from 'vs/platform/progress/common/progress';
 import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
+import { IResourceRename, IResourceCreate } from 'vs/editor/common/modes';
+
+export interface IResourceFileEdit {
+	readonly renamedResources: { from: URI, to }[];
+	readonly createdResources: { uri: URI, contents: string }[];
+	readonly deletedResources: URI[];
+}
 
 export interface IResourceEdit {
 	resource: URI;
@@ -196,12 +203,24 @@ class BulkEditModel implements IDisposable {
 	private _sourceSelections: Selection[];
 	private _sourceModelTask: SourceModelEditTask;
 
-	constructor(textModelResolverService: ITextModelService, sourceModel: URI, sourceSelections: Selection[], edits: IResourceEdit[], private progress: IProgressRunner = null) {
+	constructor(
+		textModelResolverService: ITextModelService,
+		sourceModel: URI,
+		sourceSelections: Selection[],
+		edits: IResourceEdit[],
+		private progress: IProgressRunner,
+		private renames: IResourceRename[],
+		private creates: IResourceCreate[],
+		private deletes: URI[],
+		private fileService: IFileService
+	) {
 		this._textModelResolverService = textModelResolverService;
 		this._sourceModel = sourceModel;
 		this._sourceSelections = sourceSelections;
 		this._sourceModelTask = null;
 
+		this._numberOfResourcesToModify += this.renames.length + this.deletes.length + this.creates.length;
+
 		for (let edit of edits) {
 			this._addEdit(edit);
 		}
@@ -216,7 +235,7 @@ class BulkEditModel implements IDisposable {
 		array.push(edit);
 	}
 
-	public prepare(): TPromise<BulkEditModel> {
+	public async prepare(): TPromise<BulkEditModel> {
 
 		if (this._tasks) {
 			throw new Error('illegal state - already prepared');
@@ -229,6 +248,15 @@ class BulkEditModel implements IDisposable {
 			this.progress.total(this._numberOfResourcesToModify * 2);
 		}
 
+		await TPromise.join(this.renames.map(rename =>
+			this.fileService.moveFile(rename.from, rename.to)));
+
+		await TPromise.join(this.creates.map(create =>
+			this.fileService.createFile(create.uri, create.contents)));
+
+		await TPromise.join(this.deletes.map(uri =>
+			this.fileService.del(uri)));
+
 		forEach(this._edits, entry => {
 			const promise = this._textModelResolverService.createModelReference(URI.parse(entry.key)).then(ref => {
 				const model = ref.object;
@@ -256,8 +284,9 @@ class BulkEditModel implements IDisposable {
 			promises.push(promise);
 		});
 
+		await TPromise.join(promises);
 
-		return TPromise.join(promises).then(_ => this);
+		return this;
 	}
 
 	public apply(): Selection {
@@ -284,20 +313,29 @@ class BulkEditModel implements IDisposable {
 export interface BulkEdit {
 	progress(progress: IProgressRunner): void;
 	add(edit: IResourceEdit[]): void;
+	addRename(edit: IResourceRename[]): void;
+	addCreate(edit: IResourceCreate[]): void;
+	addDelete(edit: URI[]): void;
 	finish(): TPromise<ISelection>;
 	ariaMessage(): string;
 }
 
-export function bulkEdit(textModelResolverService: ITextModelService, editor: ICodeEditor, edits: IResourceEdit[], fileService?: IFileService, progress: IProgressRunner = null): TPromise<any> {
+export function bulkEdit(textModelResolverService: ITextModelService, editor: ICodeEditor, edits: IResourceEdit[], fileService: IFileService, resourceFileEdits?: IResourceFileEdit): TPromise<any> {
 	let bulk = createBulkEdit(textModelResolverService, editor, fileService);
 	bulk.add(edits);
-	bulk.progress(progress);
+	bulk.addRename(resourceFileEdits.renamedResources);
+	bulk.addCreate(resourceFileEdits.createdResources);
+	bulk.addDelete(resourceFileEdits.deletedResources);
+	bulk.progress(null);
 	return bulk.finish();
 }
 
 export function createBulkEdit(textModelResolverService: ITextModelService, editor?: ICodeEditor, fileService?: IFileService): BulkEdit {
 
 	let all: IResourceEdit[] = [];
+	const renames: IResourceRename[] = [];
+	const creates: IResourceCreate[] = [];
+	const deletes: URI[] = [];
 	let recording = new ChangeRecorder(fileService).start();
 	let progressRunner: IProgressRunner;
 
@@ -309,6 +347,18 @@ export function createBulkEdit(textModelResolverService: ITextModelService, edit
 		all.push(...edits);
 	}
 
+	function addRename(edits: IResourceRename[]): void {
+		renames.push(...edits);
+	}
+
+	function addCreate(edits: IResourceCreate[]): void {
+		creates.push(...edits);
+	}
+
+	function addDelete(edits: URI[]): void {
+		deletes.push(...edits);
+	}
+
 	function getConcurrentEdits() {
 		let names: string[];
 		for (let edit of all) {
@@ -327,7 +377,7 @@ export function createBulkEdit(textModelResolverService: ITextModelService, edit
 
 	function finish(): TPromise<ISelection> {
 
-		if (all.length === 0) {
+		if (all.length === 0 && renames.length === 0 && creates.length === 0 && deletes.length === 0) {
 			return TPromise.as(undefined);
 		}
 
@@ -344,9 +394,9 @@ export function createBulkEdit(textModelResolverService: ITextModelService, edit
 			selections = editor.getSelections();
 		}
 
-		const model = new BulkEditModel(textModelResolverService, uri, selections, all, progressRunner);
+		const model = new BulkEditModel(textModelResolverService, uri, selections, all, progressRunner, renames, creates, deletes, fileService);
 
-		return model.prepare().then(_ => {
+		return model.prepare().then(async _ => {
 
 			let concurrentEdits = getConcurrentEdits();
 			if (concurrentEdits) {
@@ -355,7 +405,7 @@ export function createBulkEdit(textModelResolverService: ITextModelService, edit
 
 			recording.stop();
 
-			const result = model.apply();
+			const result = await model.apply();
 			model.dispose();
 			return result;
 		});
@@ -376,6 +426,9 @@ export function createBulkEdit(textModelResolverService: ITextModelService, edit
 	return {
 		progress,
 		add,
+		addRename,
+		addCreate,
+		addDelete,
 		finish,
 		ariaMessage
 	};
diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts
index 1693993e6db77..9aa2e6ae1ba9f 100644
--- a/src/vs/editor/common/modes.ts
+++ b/src/vs/editor/common/modes.ts
@@ -821,8 +821,22 @@ export interface IResourceEdit {
 	range: IRange;
 	newText: string;
 }
+
+export interface IResourceRename {
+	readonly from: URI;
+	readonly to: URI;
+}
+
+export interface IResourceCreate {
+	readonly uri: URI;
+	readonly contents: string;
+}
+
 export interface WorkspaceEdit {
 	edits: IResourceEdit[];
+	renamedResources?: IResourceRename[];
+	createdResources?: IResourceCreate[];
+	deletedResources?: URI[];
 	rejectReason?: string;
 }
 export interface RenameProvider {
diff --git a/src/vs/editor/contrib/quickFix/quickFixCommands.ts b/src/vs/editor/contrib/quickFix/quickFixCommands.ts
index 2d067db0bf0ec..f012b11a4ca8e 100644
--- a/src/vs/editor/contrib/quickFix/quickFixCommands.ts
+++ b/src/vs/editor/contrib/quickFix/quickFixCommands.ts
@@ -22,9 +22,10 @@ import { LightBulbWidget } from './lightBulbWidget';
 import { QuickFixModel, QuickFixComputeEvent } from './quickFixModel';
 import { TPromise } from 'vs/base/common/winjs.base';
 import { CodeAction } from 'vs/editor/common/modes';
-import { createBulkEdit } from 'vs/editor/browser/services/bulkEdit';
+import { bulkEdit } from 'vs/editor/browser/services/bulkEdit';
 import { IFileService } from 'vs/platform/files/common/files';
 import { ITextModelService } from 'vs/editor/common/services/resolverService';
+import URI from 'vs/base/common/uri';
 
 export class QuickFixController implements IEditorContribution {
 
@@ -112,9 +113,11 @@ export class QuickFixController implements IEditorContribution {
 
 	private async _onApplyCodeAction(action: CodeAction): TPromise<void> {
 		if (action.edit) {
-			const edit = createBulkEdit(this._textModelService, this._editor, this._fileService);
-			edit.add(action.edit.edits);
-			await edit.finish();
+			await bulkEdit(this._textModelService, this._editor, action.edit.edits, this._fileService, {
+				createdResources: action.edit.createdResources.map(create => ({ uri: URI.revive(create.uri), contents: create.contents })),
+				renamedResources: action.edit.renamedResources.map(rename => ({ from: URI.revive(rename.from), to: URI.revive(rename.to) })),
+				deletedResources: action.edit.deletedResources.map(URI.revive)
+			});
 		}
 
 		if (action.command) {
diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts
index 81d3e99523b52..58eb60dd2250f 100644
--- a/src/vs/monaco.d.ts
+++ b/src/vs/monaco.d.ts
@@ -4913,8 +4913,21 @@ declare module monaco.languages {
 		newText: string;
 	}
 
+	export interface IResourceRename {
+		readonly from: Uri;
+		readonly to: Uri;
+	}
+
+	export interface IResourceCreate {
+		readonly uri: Uri;
+		readonly contents: string;
+	}
+
 	export interface WorkspaceEdit {
 		edits: IResourceEdit[];
+		renamedResources?: IResourceRename[];
+		createdResources?: IResourceCreate[];
+		deletedResources?: Uri[];
 		rejectReason?: string;
 	}
 
diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts
index 0920acba7475f..ad5cb36dc8c18 100644
--- a/src/vs/vscode.d.ts
+++ b/src/vs/vscode.d.ts
@@ -2430,6 +2430,29 @@ declare module 'vscode' {
 		 */
 		readonly size: number;
 
+		/**
+		 * Renames a given resource in the workspace.
+		 *
+		 * @param from Uri of current resource.
+		 * @param to Uri of renamed resource.
+		 */
+		renameResource(from: Uri, to: Uri): void;
+
+		/**
+		 * Create a new resource in the workspace.
+		 *
+		 * @param uri Uri of resource to create.
+		 * @param contents New file contents.
+		 */
+		createResource(uri: Uri, contents: String): void;
+
+		/**
+		 * Delete a given resource in the workspace.
+		 *
+		 * @param uri Uri of resource to delete.
+		 */
+		deleteResource(uri: Uri): void;
+
 		/**
 		 * Replace the given range with given text for the given resource.
 		 *
@@ -2485,6 +2508,21 @@ declare module 'vscode' {
 		 * @return An array of `[Uri, TextEdit[]]`-tuples.
 		 */
 		entries(): [Uri, TextEdit[]][];
+
+		/**
+		 * Get all resource rename edits.
+		 */
+		readonly renamedResources: { from: Uri, to: Uri }[];
+
+		/**
+		 * Get all resource create edits.
+		 */
+		readonly createdResources: { uri: Uri, contents: string }[];
+
+		/**
+		 * Get all resource delete edits.
+		 */
+		readonly deletedResources: Uri[];
 	}
 
 	/**
diff --git a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts
index 0952ff3985fc1..1af196d24914c 100644
--- a/src/vs/workbench/api/electron-browser/mainThreadEditors.ts
+++ b/src/vs/workbench/api/electron-browser/mainThreadEditors.ts
@@ -15,7 +15,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
 import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
 import { Position as EditorPosition, ITextEditorOptions } from 'vs/platform/editor/common/editor';
 import { MainThreadTextEditor } from './mainThreadEditor';
-import { ITextEditorConfigurationUpdate, TextEditorRevealType, IApplyEditsOptions, IUndoStopOptions } from 'vs/workbench/api/node/extHost.protocol';
+import { ITextEditorConfigurationUpdate, TextEditorRevealType, IApplyEditsOptions, IUndoStopOptions, IResourceFileEdit } from 'vs/workbench/api/node/extHost.protocol';
 import { MainThreadDocumentsAndEditors } from './mainThreadDocumentsAndEditors';
 import { equals as objectEquals } from 'vs/base/common/objects';
 import { ExtHostContext, MainThreadEditorsShape, ExtHostEditorsShape, ITextDocumentShowOptions, ITextEditorPositionData, IExtHostContext, IWorkspaceResourceEdit } from '../node/extHost.protocol';
@@ -210,7 +210,7 @@ export class MainThreadEditors implements MainThreadEditorsShape {
 		return TPromise.as(this._documentsAndEditors.getEditor(id).applyEdits(modelVersionId, edits, opts));
 	}
 
-	$tryApplyWorkspaceEdit(workspaceResourceEdits: IWorkspaceResourceEdit[]): TPromise<boolean> {
+	$tryApplyWorkspaceEdit(workspaceResourceEdits: IWorkspaceResourceEdit[], resourceFileEdits?: IResourceFileEdit): TPromise<boolean> {
 
 		// First check if loaded models were not changed in the meantime
 		for (let i = 0, len = workspaceResourceEdits.length; i < len; i++) {
@@ -253,8 +253,17 @@ export class MainThreadEditors implements MainThreadEditorsShape {
 			}
 		}
 
-		return bulkEdit(this._textModelResolverService, codeEditor, resourceEdits, this._fileService)
-			.then(() => true);
+		return bulkEdit(
+			this._textModelResolverService,
+			codeEditor,
+			resourceEdits,
+			this._fileService,
+			resourceFileEdits ? {
+				renamedResources: resourceFileEdits.renamedResources.map(entry => ({ from: URI.revive(entry.from), to: URI.revive(entry.to) })),
+				createdResources: resourceFileEdits.createdResources.map(entry => ({ uri: URI.revive(entry.uri), contents: entry.contents })),
+				deletedResources: resourceFileEdits.deletedResources.map(URI.revive)
+			} : undefined
+		).then(() => true);
 	}
 
 	$tryInsertSnippet(id: string, template: string, ranges: IRange[], opts: IUndoStopOptions): TPromise<boolean> {
diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts
index d189f463f6bdb..0d3ad1d8df194 100644
--- a/src/vs/workbench/api/node/extHost.protocol.ts
+++ b/src/vs/workbench/api/node/extHost.protocol.ts
@@ -210,6 +210,12 @@ export interface IWorkspaceResourceEdit {
 	}[];
 }
 
+export interface IResourceFileEdit {
+	renamedResources: { from: UriComponents, to: UriComponents }[];
+	createdResources: { uri: UriComponents, contents: string }[];
+	deletedResources: UriComponents[];
+}
+
 export interface MainThreadEditorsShape extends IDisposable {
 	$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): TPromise<string>;
 	$registerTextEditorDecorationType(key: string, options: editorCommon.IDecorationRenderOptions): void;
@@ -222,7 +228,7 @@ export interface MainThreadEditorsShape extends IDisposable {
 	$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): TPromise<void>;
 	$trySetSelections(id: string, selections: ISelection[]): TPromise<void>;
 	$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): TPromise<boolean>;
-	$tryApplyWorkspaceEdit(workspaceResourceEdits: IWorkspaceResourceEdit[]): TPromise<boolean>;
+	$tryApplyWorkspaceEdit(workspaceResourceEdits: IWorkspaceResourceEdit[], resourceFileEdits?: IResourceFileEdit): TPromise<boolean>;
 	$tryInsertSnippet(id: string, template: string, selections: IRange[], opts: IUndoStopOptions): TPromise<boolean>;
 	$getDiffInformation(id: string): TPromise<editorCommon.ILineChange[]>;
 }
diff --git a/src/vs/workbench/api/node/extHostTextEditors.ts b/src/vs/workbench/api/node/extHostTextEditors.ts
index 35ad03c3a4941..79e50c129a2b7 100644
--- a/src/vs/workbench/api/node/extHostTextEditors.ts
+++ b/src/vs/workbench/api/node/extHostTextEditors.ts
@@ -121,7 +121,7 @@ export class ExtHostEditors implements ExtHostEditorsShape {
 			workspaceResourceEdits.push(workspaceResourceEdit);
 		}
 
-		return this._proxy.$tryApplyWorkspaceEdit(workspaceResourceEdits);
+		return this._proxy.$tryApplyWorkspaceEdit(workspaceResourceEdits, edit);
 	}
 
 	// --- called from main thread
diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts
index 46b7171459620..f137970845988 100644
--- a/src/vs/workbench/api/node/extHostTypeConverters.ts
+++ b/src/vs/workbench/api/node/extHostTypeConverters.ts
@@ -228,7 +228,12 @@ export const TextEdit = {
 
 export namespace WorkspaceEdit {
 	export function from(value: vscode.WorkspaceEdit): modes.WorkspaceEdit {
-		const result: modes.WorkspaceEdit = { edits: [] };
+		const result: modes.WorkspaceEdit = {
+			edits: [],
+			renamedResources: value.renamedResources,
+			createdResources: value.createdResources,
+			deletedResources: value.deletedResources
+		};
 		for (let entry of value.entries()) {
 			let [uri, textEdits] = entry;
 			for (let textEdit of textEdits) {
diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts
index 154012715bf31..a7b250b6d6971 100644
--- a/src/vs/workbench/api/node/extHostTypes.ts
+++ b/src/vs/workbench/api/node/extHostTypes.ts
@@ -494,8 +494,43 @@ export class TextEdit {
 export class WorkspaceEdit {
 
 	private _values: [URI, TextEdit[]][] = [];
+	private readonly _resourcesCreated: { uri: URI, contents: string }[] = [];
+	private readonly _resourcesDeleted: URI[] = [];
+	private readonly _resourcesRenamed: { from: URI, to: URI }[] = [];
 	private _index = new Map<string, number>();
 
+	private _validResources = new Set<URI>();
+	private _invalidResources = new Set<URI>();
+
+
+	createResource(uri: URI, contents: string): void {
+		if (this._invalidResources.has(uri)) {
+			throw illegalArgument('Cannot create already deleted resource');
+		}
+		this._resourcesCreated.push({ uri: uri, contents: contents });
+		this._validResources.add(uri);
+	}
+
+	deleteResource(uri: URI): void {
+		if (this._validResources.has(uri)) {
+			throw illegalArgument('Cannot delete newly created resource');
+		}
+		this._resourcesDeleted.push(uri);
+		this._invalidResources.add(uri);
+	}
+
+	renameResource(uri: URI, newUri: URI): void {
+		if (this._validResources.has(uri)) {
+			throw illegalArgument('Cannot delete newly created resource');
+		}
+		if (this._invalidResources.has(newUri)) {
+			throw illegalArgument('Cannot create already deleted resource');
+		}
+		this._resourcesRenamed.push({ from: uri, to: newUri });
+		this._invalidResources.add(uri);
+		this._validResources.add(newUri);
+	}
+
 	replace(uri: URI, range: Range, newText: string): void {
 		let edit = new TextEdit(range, newText);
 		let array = this.get(uri);
@@ -519,6 +554,10 @@ export class WorkspaceEdit {
 	}
 
 	set(uri: URI, edits: TextEdit[]): void {
+		if (this._invalidResources.has(uri)) {
+			throw illegalArgument('Cannot modify already deleted resource');
+		}
+		this._validResources.add(uri);
 		const idx = this._index.get(uri.toString());
 		if (typeof idx === 'undefined') {
 			let newLen = this._values.push([uri, edits]);
@@ -537,8 +576,20 @@ export class WorkspaceEdit {
 		return this._values;
 	}
 
+	get createdResources(): { uri: URI, contents: string }[] {
+		return this._resourcesCreated;
+	}
+
+	get deletedResources(): URI[] {
+		return this._resourcesDeleted;
+	}
+
+	get renamedResources(): { from: URI, to: URI }[] {
+		return this._resourcesRenamed;
+	}
+
 	get size(): number {
-		return this._values.length;
+		return this._values.length + this._resourcesCreated.length + this._resourcesRenamed.length + this._resourcesDeleted.length;
 	}
 
 	toJSON(): any {
diff --git a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts
index 3cd1208f264ef..3e99b175fc79b 100644
--- a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts
+++ b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts
@@ -362,6 +362,19 @@ suite('ExtHostTypes', function () {
 
 	});
 
+	test('WorkspaceEdit should fail when editing deleted resource', () => {
+		const resource = URI.parse('file:///a.ts');
+
+		const edit = new types.WorkspaceEdit();
+		edit.deleteResource(resource);
+		try {
+			edit.insert(resource, new types.Position(0, 0), '');
+			assert.fail(false, 'Should disallow edit of deleted resource');
+		} catch {
+			// expected
+		}
+	});
+
 	test('DocumentLink', function () {
 		assert.throws(() => new types.DocumentLink(null, null));
 		assert.throws(() => new types.DocumentLink(new types.Range(1, 1, 1, 1), null));
diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts
index 73887be8ea365..b725c6163bd13 100644
--- a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts
+++ b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts
@@ -23,6 +23,9 @@ import { Range } from 'vs/editor/common/core/range';
 import { Position } from 'vs/editor/common/core/position';
 import { IModelService } from 'vs/editor/common/services/modelService';
 import { EditOperation } from 'vs/editor/common/core/editOperation';
+import { TestFileService } from 'vs/workbench/test/workbenchTestServices';
+import { TPromise } from 'vs/base/common/winjs.base';
+import { IFileStat } from 'vs/platform/files/common/files';
 
 suite('MainThreadEditors', () => {
 
@@ -31,10 +34,35 @@ suite('MainThreadEditors', () => {
 	let modelService: IModelService;
 	let editors: MainThreadEditors;
 
+	const movedResources = new Map<URI, URI>();
+	const createdResources = new Map<URI, string>();
+	const deletedResources = new Set<URI>();
+
 	setup(() => {
 		const configService = new TestConfigurationService();
 		modelService = new ModelServiceImpl(null, configService);
 		const codeEditorService = new TestCodeEditorService();
+
+		movedResources.clear();
+		createdResources.clear();
+		deletedResources.clear();
+		const fileService = new TestFileService();
+
+		fileService.moveFile = async (from, target): TPromise<IFileStat> => {
+			assert(!movedResources.has(from));
+			movedResources.set(from, target);
+			return createMockFileStat(target);
+		};
+		fileService.createFile = async (uri, contents): TPromise<IFileStat> => {
+			assert(!createdResources.has(uri));
+			createdResources.set(uri, contents);
+			return createMockFileStat(uri);
+		};
+		fileService.del = async (uri): TPromise<void> => {
+			assert(!deletedResources.has(uri));
+			deletedResources.add(uri);
+		};
+
 		const textFileService = new class extends mock<ITextFileService>() {
 			isDirty() { return false; }
 			models = <any>{
@@ -69,7 +97,7 @@ suite('MainThreadEditors', () => {
 			workbenchEditorService,
 			codeEditorService,
 			null,
-			null,
+			fileService,
 			null,
 			null,
 			editorGroupService,
@@ -82,7 +110,7 @@ suite('MainThreadEditors', () => {
 			workbenchEditorService,
 			editorGroupService,
 			null,
-			null,
+			fileService,
 			modelService
 		);
 	});
@@ -107,4 +135,38 @@ suite('MainThreadEditors', () => {
 			assert.equal(result, false);
 		});
 	});
+
+	test(`applyWorkspaceEdit with only resource edit`, () => {
+		let model = modelService.createModel('something', null, resource);
+
+		let workspaceResourceEdit: IWorkspaceResourceEdit = {
+			resource: resource,
+			modelVersionId: model.getVersionId(),
+			edits: []
+		};
+
+		return editors.$tryApplyWorkspaceEdit([workspaceResourceEdit], {
+			renamedResources: [{ from: resource, to: resource }],
+			createdResources: [{ uri: resource, contents: 'foo' }],
+			deletedResources: [resource]
+		}).then((result) => {
+			assert.equal(result, true);
+			assert.equal(movedResources.get(resource), resource);
+			assert.equal(createdResources.get(resource), 'foo');
+			assert.equal(deletedResources.has(resource), true);
+		});
+	});
 });
+
+
+function createMockFileStat(target: URI): IFileStat {
+	return {
+		etag: '',
+		hasChildren: false,
+		isDirectory: false,
+		name: target.path,
+		mtime: 0,
+		resource: target
+	};
+}
+