diff --git a/src/vs/editor/browser/standalone/simpleServices.ts b/src/vs/editor/browser/standalone/simpleServices.ts index 5c68fb3292e064a5674a13caa91483276a3bbcfc..567e3b097d29d1a2e0ed41f814462c7d47c91221 100644 --- a/src/vs/editor/browser/standalone/simpleServices.ts +++ b/src/vs/editor/browser/standalone/simpleServices.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {EventEmitter} from 'vs/base/common/eventEmitter'; import {Schemas} from 'vs/base/common/network'; import Severity from 'vs/base/common/severity'; import {TPromise} from 'vs/base/common/winjs.base'; @@ -56,13 +55,18 @@ export class SimpleEditor implements IEditor { } } -export class SimpleModel extends EventEmitter implements ITextEditorModel { +export class SimpleModel implements ITextEditorModel { private model:editorCommon.IModel; + private _onDispose: Emitter; constructor(model:editorCommon.IModel) { - super(); this.model = model; + this._onDispose = new Emitter(); + } + + public get onDispose(): Event { + return this._onDispose.event; } public load(): TPromise { @@ -72,6 +76,10 @@ export class SimpleModel extends EventEmitter implements ITextEditorModel { public get textEditorModel():editorCommon.IModel { return this.model; } + + public dispose(): void { + this._onDispose.fire(); + } } export interface IOpenEditorDelegate { diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index 70d2028e556c88fb06abfc1b4a232684c01dce3e..897923795c77f5f1bbd193ddda3b0cbccf7f30bc 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -28,6 +28,8 @@ export interface IEditorService { export interface IEditorModel { + onDispose: Event; + /** * Loads the model. */ diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index b61d85b01cf5d4b7b7ffed2c364d92c236079e5e..17bf0df175b2920b92d93a217f523e5b4e24bc50 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -9,7 +9,7 @@ import URI from 'vs/base/common/uri'; import {isUnspecific, guessMimeTypes, MIME_TEXT, suggestFilename} from 'vs/base/common/mime'; import labels = require('vs/base/common/labels'); import paths = require('vs/base/common/paths'); -import {UntitledEditorInput as AbstractUntitledEditorInput, EditorModel, EncodingMode, ConfirmResult} from 'vs/workbench/common/editor'; +import {UntitledEditorInput as AbstractUntitledEditorInput, EncodingMode, ConfirmResult} from 'vs/workbench/common/editor'; import {UntitledEditorModel} from 'vs/workbench/common/editor/untitledEditorModel'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; @@ -131,7 +131,7 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { } } - public resolve(refresh?: boolean): TPromise { + public resolve(refresh?: boolean): TPromise { // Use Cached Model if (this.cachedModel) { diff --git a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts index 95da252871c34043503bc603ebea903979aee489..1a3f919e7366b7cd84a6c4eea55001f6bc6c09a6 100644 --- a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts @@ -15,10 +15,9 @@ import {IEditorViewState} from 'vs/editor/common/editorCommon'; import {Action} from 'vs/base/common/actions'; import {Scope} from 'vs/workbench/common/memento'; import {IEditorOptions} from 'vs/editor/common/editorCommon'; -import {VIEWLET_ID, TEXT_FILE_EDITOR_ID} from 'vs/workbench/parts/files/common/files'; +import {VIEWLET_ID, TEXT_FILE_EDITOR_ID, ITextFileEditorModel} from 'vs/workbench/parts/files/common/files'; import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor'; -import {EditorOptions, TextEditorOptions, EditorModel} from 'vs/workbench/common/editor'; -import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; +import {EditorOptions, TextEditorOptions} from 'vs/workbench/common/editor'; import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import {ExplorerViewlet} from 'vs/workbench/parts/files/browser/explorerViewlet'; @@ -117,7 +116,7 @@ export class TextFileEditor extends BaseTextEditor { } // Different Input (Reload) - return this.editorService.resolveEditorModel(input, true /* Reload */).then((resolvedModel: EditorModel) => { + return this.editorService.resolveEditorModel(input, true /* Reload */).then(resolvedModel => { // There is a special case where the text editor has to handle binary file editor input: if a file with application/unknown // mime has been resolved and cached before, it maybe an actual instance of BinaryEditorModel. In this case our text @@ -126,13 +125,8 @@ export class TextFileEditor extends BaseTextEditor { return this.openAsBinary(input, options); } - // Assert Model interface - if (!(resolvedModel instanceof TextFileEditorModel)) { - return TPromise.wrapError('Invalid editor input. Text file editor requires a model instance of TextFileEditorModel.'); - } - // Check Model state - const textFileModel = resolvedModel; + const textFileModel = resolvedModel; const hasInput = !!this.getInput(); const modelDisposed = textFileModel.isDisposed(); diff --git a/src/vs/workbench/parts/files/common/editors/textFileEditorModelManager.ts b/src/vs/workbench/parts/files/common/editors/textFileEditorModelManager.ts index 5efd8ee90e0c6fb5f1744da9f5cd77008003b0c8..6a91400c223cfcee58358810b483c9401145eb2e 100644 --- a/src/vs/workbench/parts/files/common/editors/textFileEditorModelManager.ts +++ b/src/vs/workbench/parts/files/common/editors/textFileEditorModelManager.ts @@ -32,8 +32,8 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager { private mapResourceToDisposeListener: { [resource: string]: IDisposable; }; private mapResourceToStateChangeListener: { [resource: string]: IDisposable; }; - private mapResourceToModel: { [resource: string]: TextFileEditorModel; }; - private mapResourceToPendingModelLoaders: { [resource: string]: TPromise }; + private mapResourceToModel: { [resource: string]: ITextFileEditorModel; }; + private mapResourceToPendingModelLoaders: { [resource: string]: TPromise }; constructor( @ILifecycleService private lifecycleService: ILifecycleService, @@ -162,11 +162,11 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager { return this._onModelEncodingChanged.event; } - public get(resource: URI): TextFileEditorModel { + public get(resource: URI): ITextFileEditorModel { return this.mapResourceToModel[resource.toString()]; } - public loadOrCreate(resource: URI, encoding: string, refresh?: boolean): TPromise { + public loadOrCreate(resource: URI, encoding: string, refresh?: boolean): TPromise { // Return early if model is currently being loaded const pendingLoad = this.mapResourceToPendingModelLoaders[resource.toString()]; @@ -174,7 +174,7 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager { return pendingLoad; } - let modelPromise: TPromise; + let modelPromise: TPromise; // Model exists let model = this.get(resource); @@ -238,13 +238,13 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager { }); } - public getAll(resource?: URI): TextFileEditorModel[] { + public getAll(resource?: URI): ITextFileEditorModel[] { return Object.keys(this.mapResourceToModel) .filter(r => !resource || resource.toString() === r) .map(r => this.mapResourceToModel[r]); } - public add(resource: URI, model: TextFileEditorModel): void { + public add(resource: URI, model: ITextFileEditorModel): void { const knownModel = this.mapResourceToModel[resource.toString()]; if (knownModel === model) { return; // already cached diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index 32989913884a7a34d80a68b5fa5e7a34003becaa..44ac8de74e54867e962617accd2534f5112f4809 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -274,6 +274,8 @@ export interface ITextFileEditorModelManager { export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport { + onDidStateChange: Event; + getResource(): URI; getLastSaveAttemptTime(): number; @@ -282,6 +284,8 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport getState(): ModelState; + updatePreferredEncoding(encoding: string): void; + save(overwriteReadonly?: boolean, overwriteEncoding?: boolean): TPromise; revert(): TPromise; diff --git a/src/vs/workbench/parts/files/common/textFileService.ts b/src/vs/workbench/parts/files/common/textFileService.ts index ac12eb92f39609db68155d7d02bd6c87181aa32b..3ada394c2205ea186d1f8656be0ac0827900f7a7 100644 --- a/src/vs/workbench/parts/files/common/textFileService.ts +++ b/src/vs/workbench/parts/files/common/textFileService.ts @@ -9,8 +9,7 @@ import URI from 'vs/base/common/uri'; import paths = require('vs/base/common/paths'); import errors = require('vs/base/common/errors'); import Event, {Emitter} from 'vs/base/common/event'; -import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; -import {IResult, ITextFileOperationResult, ITextFileService, IRawTextContent, IAutoSaveConfiguration, AutoSaveMode, ITextFileEditorModelManager} from 'vs/workbench/parts/files/common/files'; +import {IResult, ITextFileOperationResult, ITextFileService, IRawTextContent, IAutoSaveConfiguration, AutoSaveMode, ITextFileEditorModelManager, ITextFileEditorModel} from 'vs/workbench/parts/files/common/files'; import {ConfirmResult} from 'vs/workbench/common/editor'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; @@ -329,11 +328,11 @@ export abstract class TextFileService implements ITextFileService { }); } - private getFileModels(resources?: URI[]): TextFileEditorModel[]; - private getFileModels(resource?: URI): TextFileEditorModel[]; - private getFileModels(arg1?: any): TextFileEditorModel[] { + private getFileModels(resources?: URI[]): ITextFileEditorModel[]; + private getFileModels(resource?: URI): ITextFileEditorModel[]; + private getFileModels(arg1?: any): ITextFileEditorModel[] { if (Array.isArray(arg1)) { - const models: TextFileEditorModel[] = []; + const models: ITextFileEditorModel[] = []; (arg1).forEach(resource => { models.push(...this.getFileModels(resource)); }); @@ -344,9 +343,9 @@ export abstract class TextFileService implements ITextFileService { return this._models.getAll(arg1); } - private getDirtyFileModels(resources?: URI[]): TextFileEditorModel[]; - private getDirtyFileModels(resource?: URI): TextFileEditorModel[]; - private getDirtyFileModels(arg1?: any): TextFileEditorModel[] { + private getDirtyFileModels(resources?: URI[]): ITextFileEditorModel[]; + private getDirtyFileModels(resource?: URI): ITextFileEditorModel[]; + private getDirtyFileModels(arg1?: any): ITextFileEditorModel[] { return this.getFileModels(arg1).filter(model => model.isDirty()); } @@ -381,7 +380,7 @@ export abstract class TextFileService implements ITextFileService { private doSaveAs(resource: URI, target?: URI): TPromise { // Retrieve text model from provided resource if any - let modelPromise: TPromise = TPromise.as(null); + let modelPromise: TPromise = TPromise.as(null); if (resource.scheme === 'file') { modelPromise = TPromise.as(this._models.get(resource)); } else if (resource.scheme === 'untitled') { @@ -411,11 +410,11 @@ export abstract class TextFileService implements ITextFileService { }); } - private doSaveTextFileAs(sourceModel: TextFileEditorModel | UntitledEditorModel, resource: URI, target: URI): TPromise { + private doSaveTextFileAs(sourceModel: ITextFileEditorModel | UntitledEditorModel, resource: URI, target: URI): TPromise { // create the target file empty if it does not exist already return this.fileService.resolveFile(target).then(stat => stat, () => null).then(stat => stat || this.fileService.createFile(target)).then(stat => { // resolve a model for the file (which can be binary if the file is not a text file) - return this.editorService.resolveEditorModel({ resource: target }).then((targetModel: TextFileEditorModel) => { + return this.editorService.resolveEditorModel({ resource: target }).then((targetModel: ITextFileEditorModel) => { // binary model: delete the file and run the operation again if (targetModel instanceof BinaryEditorModel) { return this.fileService.del(target).then(() => this.doSaveTextFileAs(sourceModel, resource, target));