From 937736148ef61e3b51cdc6c1cf2134a90d19b8c7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 17 May 2016 16:27:53 +0200 Subject: [PATCH] first cut of handling dirty editors on close --- .../browser/parts/editor/editorPart.ts | 186 +++++++++++++----- src/vs/workbench/common/editor.ts | 61 ++++++ .../common/editor/editorStacksModel.ts | 3 + .../common/editor/untitledEditorInput.ts | 19 +- .../files/browser/editors/fileEditorInput.ts | 18 +- .../parts/files/browser/fileActions.ts | 54 +++-- .../parts/files/browser/textFileServices.ts | 3 +- .../files/browser/views/explorerViewer.ts | 4 +- src/vs/workbench/parts/files/common/files.ts | 8 +- .../electron-browser/textFileServices.ts | 3 +- 10 files changed, 264 insertions(+), 95 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 3b9733c4bcf..78945629d7a 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -23,7 +23,7 @@ import {Scope} from 'vs/workbench/browser/actionBarRegistry'; import {Part} from 'vs/workbench/browser/part'; import {EventType as WorkbenchEventType, EditorInputEvent, EditorEvent} from 'vs/workbench/common/events'; import {IEditorRegistry, Extensions as EditorExtensions, BaseEditor, EditorDescriptor} from 'vs/workbench/browser/parts/editor/baseEditor'; -import {EditorInput, EditorOptions, TextEditorOptions} from 'vs/workbench/common/editor'; +import {EditorInput, EditorOptions, TextEditorOptions, ConfirmResult} from 'vs/workbench/common/editor'; import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor'; import {SideBySideEditorControl, Rochade, ISideBySideEditorControl, ProgressState, ITitleAreaState} from 'vs/workbench/browser/parts/editor/sideBySideEditorControl'; import {WorkbenchProgressService} from 'vs/workbench/services/progress/browser/progressService'; @@ -467,6 +467,7 @@ export class EditorPart extends Part implements IEditorPart { this.sideBySideControl.updateProgress(position, ProgressState.DONE); + // Event this.emit(WorkbenchEventType.EDITOR_SET_INPUT_ERROR, new EditorEvent(editor, editor.getId(), input, options, position)); // Recover from this error by closing the editor if the attempt of setInput failed and we are not having any previous input @@ -503,37 +504,59 @@ export class EditorPart extends Part implements IEditorPart { } // Closing inactive editor is just a model update - group.closeEditor(input); + this.doCloseInactiveEditor(input, position); } private doCloseActiveEditor(position: Position): TPromise { - // Update visible inputs for position - this.visibleInputs[position] = null; + // Check for dirty and veto + const input = this.visibleInputs[position]; + return this.handleDirty([input]).then(veto => { + if (veto) { + return; + } - // Dispose previous input listener if any - if (this.visibleInputListeners[position]) { - this.visibleInputListeners[position](); - this.visibleInputListeners[position] = null; - } + // Update visible inputs for position + this.visibleInputs[position] = null; - // Reset counter - this.editorSetInputErrorCounter[position] = 0; + // Dispose previous input listener if any + if (this.visibleInputListeners[position]) { + this.visibleInputListeners[position](); + this.visibleInputListeners[position] = null; + } - // Update stacks model - const group = this.groupAt(position); - group.closeEditor(group.activeEditor); + // Reset counter + this.editorSetInputErrorCounter[position] = 0; - // Close group is this is the last editor in group - if (group.count === 0) { - return this.doCloseGroup(position); - } + // Update stacks model + const group = this.groupAt(position); + group.closeEditor(group.activeEditor); - // Otherwise open next active - return this.openEditor(group.activeEditor, null, position).then(null, (error) => { + // Close group is this is the last editor in group + if (group.count === 0) { + return this.doCloseGroup(position); + } - // in case of an error, continue closing - return this.doCloseActiveEditor(position); + // Otherwise open next active + return this.openEditor(group.activeEditor, null, position).then(null, (error) => { + + // in case of an error, continue closing + return this.doCloseActiveEditor(position); + }); + }); + } + + private doCloseInactiveEditor(input: EditorInput, position: Position): TPromise { + + // Check for dirty and veto + return this.handleDirty([input]).then(veto => { + if (veto) { + return; + } + + // Closing inactive editor is just a model update + const group = this.groupAt(position); + group.closeEditor(input); }); } @@ -610,30 +633,44 @@ export class EditorPart extends Part implements IEditorPart { const group = this.groupAt(position); - // Close all editors in group - if (!except) { + // Check for dirty and veto + let editorsToClose: EditorInput[]; + if (!direction) { + editorsToClose = group.getEditors().filter(e => !except || !e.matches(except)); + } else { + editorsToClose = (direction === Direction.LEFT) ? group.getEditors().slice(0, group.indexOf(except)) : group.getEditors().slice(group.indexOf(except) + 1); + } - // Update stacks model: remove all non active editors first to prevent opening the next editor in group - group.closeEditors(group.activeEditor); + return this.handleDirty(editorsToClose).then(veto => { + if (veto) { + return; + } - // Now close active editor in group which will close the group - return this.doCloseActiveEditor(position); - } + // Close all editors in group + if (!except) { + + // Update stacks model: remove all non active editors first to prevent opening the next editor in group + group.closeEditors(group.activeEditor); - // Close all editors in group except active one - if (except.matches(group.activeEditor)) { + // Now close active editor in group which will close the group + return this.doCloseActiveEditor(position); + } - // Update stacks model: close non active editors supporting the direction - group.closeEditors(group.activeEditor, direction); + // Close all editors in group except active one + if (except.matches(group.activeEditor)) { - // No UI update needed - return TPromise.as(null); - } + // Update stacks model: close non active editors supporting the direction + group.closeEditors(group.activeEditor, direction); + + // No UI update needed + return TPromise.as(null); + } - // Finally: we are asked to close editors around a non-active editor - // Thus we make the non-active one active and then close the others - return this.openEditor(except, null, position).then(() => { - return this.closeEditors(position, except, direction); + // Finally: we are asked to close editors around a non-active editor + // Thus we make the non-active one active and then close the others + return this.openEditor(except, null, position).then(() => { + return this.closeEditors(position, except, direction); + }); }); } @@ -648,6 +685,38 @@ export class EditorPart extends Part implements IEditorPart { return TPromise.join(editors.map(e => this.closeEditors(e.position))).then(() => void 0); } + private handleDirty(inputs: EditorInput[]): TPromise { + if (!inputs.length) { + return TPromise.as(false); // no veto + } + + return this.doHandleDirty(inputs.shift()).then(veto => { + if (veto) { + return veto; + } + + return this.handleDirty(inputs); + }); + } + + private doHandleDirty(input: EditorInput): TPromise { + if (!input || !input.isDirty()) { + return TPromise.as(false); // no veto + } + + const res = input.confirmSave(); + switch (res) { + case ConfirmResult.SAVE: + return input.save().then(ok => !ok); + + case ConfirmResult.DONT_SAVE: + return input.revert().then(ok => !ok); + + case ConfirmResult.CANCEL: + return TPromise.as(true); // veto + } + } + public getStacksModel(): EditorStacksModel { return this.stacksModel; } @@ -902,24 +971,35 @@ export class EditorPart extends Part implements IEditorPart { return; } - let closeActivePromise: TPromise = TPromise.as(null); - - // The active editor is the preview editor and we are asked to make - // another editor the preview editor. So we need to take care of closing - // the active editor first - if (group.isPreview(group.activeEditor) && !group.activeEditor.matches(input)) { - closeActivePromise = this.doCloseActiveEditor(position); + // Unpinning an editor closes the preview editor if we have any + let handlePreviewEditor: TPromise = TPromise.as(false); + if (group.previewEditor) { + handlePreviewEditor = this.handleDirty([group.previewEditor]); } - closeActivePromise.done(() => { + handlePreviewEditor.done(veto => { + if (veto) { + return; + } - // Update stacks model - group.unpin(input); + // The active editor is the preview editor and we are asked to make + // another editor the preview editor. So we need to take care of closing + // the active editor first + let closeActivePromise: TPromise = TPromise.as(null); + if (group.isPreview(group.activeEditor) && !group.activeEditor.matches(input)) { + closeActivePromise = this.doCloseActiveEditor(position); + } - // Update UI - this.sideBySideControl.updateTitleArea({ position, preview: group.previewEditor }); + closeActivePromise.done(() => { - }, errors.onUnexpectedError); + // Update stacks model + group.unpin(input); + + // Update UI + this.sideBySideControl.updateTitleArea({ position, preview: group.previewEditor }); + + }, errors.onUnexpectedError); + }); } } diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 934c224a61c..334b49f4a91 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -38,6 +38,12 @@ export interface IInputStatus { decoration?: string; } +export enum ConfirmResult { + SAVE, + DONT_SAVE, + CANCEL +} + /** * Editor inputs are lightweight objects that can be passed to the workbench API to open inside the editor part. * Each editor input is mapped to an editor that is capable of opening it through the Platform facade. @@ -103,6 +109,40 @@ export abstract class EditorInput extends EventEmitter implements IEditorInput { */ public abstract resolve(refresh?: boolean): TPromise; + /** + * An editor that is dirty will be asked to be saved once it closes. + */ + public isDirty(): boolean { + return false; + } + + /** + * Subclasses should bring up a proper dialog for the user if the editor is dirty and return the result. + */ + public confirmSave(): ConfirmResult { + return ConfirmResult.DONT_SAVE; + } + + /** + * Saves the editor if it is dirty. Subclasses return a promise with a boolean indicating the success of the operation. + */ + public save(): TPromise { + return TPromise.as(true); + } + + /** + * Reverts the editor if it is dirty. Subclasses return a promise with a boolean indicating the success of the operation. + */ + public revert(): TPromise { + return TPromise.as(true); + } + + /** + * Called when the editor is closed. Subclasses can free resources as needed. + */ + public close(): void { + } + /** * Called when an editor input is no longer needed. Allows to free up any resources taken by * resolving the editor input. @@ -222,6 +262,27 @@ export abstract class BaseDiffEditorInput extends EditorInput { public getModifiedInput(): EditorInput { return this.modifiedInput; } + + public isDirty(): boolean { + return this._modifiedInput.isDirty(); + } + + public confirmSave(): ConfirmResult { + return this._modifiedInput.confirmSave(); + } + + public save(): TPromise { + return this._modifiedInput.save(); + } + + public revert(): TPromise { + return this._modifiedInput.revert(); + } + + public close(): void { + this._originalInput.close(); + this._modifiedInput.close(); + } } /** diff --git a/src/vs/workbench/common/editor/editorStacksModel.ts b/src/vs/workbench/common/editor/editorStacksModel.ts index ee0d3f79009..f696d7caebc 100644 --- a/src/vs/workbench/common/editor/editorStacksModel.ts +++ b/src/vs/workbench/common/editor/editorStacksModel.ts @@ -317,6 +317,9 @@ export class EditorGroup implements IEditorGroup { this.preview = null; } + // Close it + editor.close(); + // Remove from arrays this.splice(index, true); diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index 2332f4fa196..2eb97d88b85 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -9,13 +9,15 @@ 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, IInputStatus} from 'vs/workbench/common/editor'; +import {UntitledEditorInput as AbstractUntitledEditorInput, EditorModel, EncodingMode, IInputStatus, 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'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IModeService} from 'vs/editor/common/services/modeService'; +import {ITextFileService} from 'vs/workbench/parts/files/common/files'; // TODO@Ben layer breaker + /** * An editor input to be used for untitled text buffers. */ @@ -36,7 +38,8 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { @IInstantiationService private instantiationService: IInstantiationService, @ILifecycleService private lifecycleService: ILifecycleService, @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IModeService private modeService: IModeService + @IModeService private modeService: IModeService, + @ITextFileService private textFileService: ITextFileService ) { super(); @@ -74,6 +77,18 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { return null; } + public confirmSave(): ConfirmResult { + return this.textFileService.confirmSave([this.resource]); + } + + public save(): TPromise { + return this.textFileService.save(this.resource); + } + + public revert(): TPromise { + return this.textFileService.revert(this.resource); + } + public suggestFileName(): string { if (!this.hasAssociatedFilePath) { let mime = this.getMime(); diff --git a/src/vs/workbench/parts/files/browser/editors/fileEditorInput.ts b/src/vs/workbench/parts/files/browser/editors/fileEditorInput.ts index 98513117dbc..1560921c318 100644 --- a/src/vs/workbench/parts/files/browser/editors/fileEditorInput.ts +++ b/src/vs/workbench/parts/files/browser/editors/fileEditorInput.ts @@ -14,7 +14,7 @@ import labels = require('vs/base/common/labels'); import URI from 'vs/base/common/uri'; import strings = require('vs/base/common/strings'); import assert = require('vs/base/common/assert'); -import {EditorModel, IInputStatus, EncodingMode} from 'vs/workbench/common/editor'; +import {EditorModel, IInputStatus, EncodingMode, ConfirmResult} from 'vs/workbench/common/editor'; import {IEditorRegistry, Extensions, EditorDescriptor} from 'vs/workbench/browser/parts/editor/baseEditor'; import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; import {IFileOperationResult, FileOperationResult} from 'vs/platform/files/common/files'; @@ -175,6 +175,22 @@ export class FileEditorInput extends CommonFileEditorInput { return null; } + public isDirty(): boolean { + return this.textFileService.isDirty(this.resource); + } + + public confirmSave(): ConfirmResult { + return this.textFileService.confirmSave([this.resource]); + } + + public save(): TPromise { + return this.textFileService.save(this.resource); + } + + public revert(): TPromise { + return this.textFileService.revert(this.resource); + } + public getPreferredEditorId(candidates: string[]): string { let editorRegistry = (Registry.as(Extensions.Editors)); diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index ca8af4c3d18..3a833f69604 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -25,10 +25,10 @@ import {MessageType, IInputValidator} from 'vs/base/browser/ui/inputbox/inputBox import {ITree, IHighlightEvent} from 'vs/base/parts/tree/browser/tree'; import {dispose, IDisposable} from 'vs/base/common/lifecycle'; import {EventType as WorkbenchEventType, EditorEvent} from 'vs/workbench/common/events'; -import Files = require('vs/workbench/parts/files/common/files'); +import {LocalFileChangeEvent, VIEWLET_ID, ITextFileService, TextFileChangeEvent, ITextFileOperationResult, IWorkingFileModelChangeEvent, IWorkingFileEntry, IWorkingFilesModel, EventType as FileEventType} from 'vs/workbench/parts/files/common/files'; import {IFileService, IFileStat, IImportResult} from 'vs/platform/files/common/files'; import {DiffEditorInput, toDiffLabel} from 'vs/workbench/common/editor/diffEditorInput'; -import {asFileEditorInput, getUntitledOrFileResource, TextEditorOptions, EditorOptions, UntitledEditorInput} from 'vs/workbench/common/editor'; +import {asFileEditorInput, getUntitledOrFileResource, TextEditorOptions, EditorOptions, UntitledEditorInput, ConfirmResult} from 'vs/workbench/common/editor'; import {IEditorSelection} from 'vs/editor/common/editorCommon'; import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput'; import {FileStat, NewStatPlaceholder} from 'vs/workbench/parts/files/common/explorerViewModel'; @@ -50,8 +50,6 @@ import {IMessageService, IMessageWithAction, IConfirmation, Severity, CancelActi import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {KeyMod, KeyCode, Keybinding} from 'vs/base/common/keyCodes'; -import ITextFileService = Files.ITextFileService; - export interface IEditableData { action: IAction; validator: IInputValidator; @@ -155,11 +153,11 @@ export class BaseFileAction extends Action { protected handleDirty(): TPromise { if (this.textFileService.isDirty(this._element.resource)) { let res = this.textFileService.confirmSave([this._element.resource]); - if (res === Files.ConfirmResult.SAVE) { + if (res === ConfirmResult.SAVE) { return this.textFileService.save(this._element.resource).then(() => false); } - if (res === Files.ConfirmResult.DONT_SAVE) { + if (res === ConfirmResult.DONT_SAVE) { return this.textFileService.revert(this._element.resource).then(() => false); } @@ -325,7 +323,7 @@ export abstract class BaseRenameAction extends BaseFileAction { before = this.element.clone(); // Clone element to not expose viewers element to listeners } - this.eventService.emit('files.internal:fileChanged', new Files.LocalFileChangeEvent(before, stat)); + this.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(before, stat)); } } @@ -524,7 +522,7 @@ export abstract class BaseGlobalNewAction extends Action { } public run(): TPromise { - return this.viewletService.openViewlet(Files.VIEWLET_ID, true).then((viewlet) => { + return this.viewletService.openViewlet(VIEWLET_ID, true).then((viewlet) => { return TPromise.timeout(100).then(() => { // use a timeout to prevent the explorer from revealing the active file viewlet.focus(); @@ -730,7 +728,7 @@ export class BaseDeleteFileAction extends BaseFileAction { // Since a delete operation can take a while we want to emit the event proactively to avoid issues // with stale entries in the explorer tree. - this.eventService.emit('files.internal:fileChanged', new Files.LocalFileChangeEvent(this.element.clone(), null)); + this.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(this.element.clone(), null)); // Call function let servicePromise = this.fileService.del(this.element.resource, this.useTrash).then(() => { @@ -748,7 +746,7 @@ export class BaseDeleteFileAction extends BaseFileAction { this.onErrorWithRetry(error, () => this.run(), extraAction); // Since the delete failed, best we can do is to refresh the explorer from the root to show the current state of files. - let event = new Files.LocalFileChangeEvent(new FileStat(this.contextService.getWorkspace().resource, true, true), new FileStat(this.contextService.getWorkspace().resource, true, true)); + let event = new LocalFileChangeEvent(new FileStat(this.contextService.getWorkspace().resource, true, true), new FileStat(this.contextService.getWorkspace().resource, true, true)); this.eventService.emit('files.internal:fileChanged', event); // Focus back to tree @@ -890,7 +888,7 @@ export class ImportFileAction extends BaseFileAction { // Emit Deleted Event if file gets replaced unless it is the same file let oldFile = targetNames[isLinux ? file.name : file.name.toLowerCase()]; if (oldFile && oldFile.resource.fsPath !== result.stat.resource.fsPath) { - this.eventService.emit('files.internal:fileChanged', new Files.LocalFileChangeEvent(oldFile, null)); + this.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(oldFile, null)); } // Emit Import Event @@ -917,7 +915,7 @@ export class ImportFileAction extends BaseFileAction { } /** File import event is emitted when a file is import into the workbench. */ -export class FileImportedEvent extends Files.LocalFileChangeEvent { +export class FileImportedEvent extends LocalFileChangeEvent { private isNew: boolean; constructor(stat?: IFileStat, isNew?: boolean, originalEvent?: Event) { @@ -1083,7 +1081,7 @@ export class DuplicateFileAction extends BaseFileAction { // Copy File and emit event let result = this.fileService.copyFile(this.element.resource, this.findTarget()).then((stat: IFileStat) => { - this.eventService.emit('files.internal:fileChanged', new Files.LocalFileChangeEvent(null, stat)); + this.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(null, stat)); }, (error: any) => { this.onError(error); }); @@ -1544,10 +1542,10 @@ export abstract class BaseSaveAllAction extends BaseActionWithErrorReporting { private registerListeners(): void { // listen to files being changed locally - this.toDispose.push(this.eventService.addListener2(Files.EventType.FILE_DIRTY, (e: Files.TextFileChangeEvent) => this.updateEnablement(true))); - this.toDispose.push(this.eventService.addListener2(Files.EventType.FILE_SAVED, (e: Files.TextFileChangeEvent) => this.updateEnablement(false))); - this.toDispose.push(this.eventService.addListener2(Files.EventType.FILE_REVERTED, (e: Files.TextFileChangeEvent) => this.updateEnablement(false))); - this.toDispose.push(this.eventService.addListener2(Files.EventType.FILE_SAVE_ERROR, (e: Files.TextFileChangeEvent) => this.updateEnablement(true))); + this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_DIRTY, (e: TextFileChangeEvent) => this.updateEnablement(true))); + this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_SAVED, (e: TextFileChangeEvent) => this.updateEnablement(false))); + this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_REVERTED, (e: TextFileChangeEvent) => this.updateEnablement(false))); + this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_SAVE_ERROR, (e: TextFileChangeEvent) => this.updateEnablement(true))); if (this.includeUntitled()) { this.toDispose.push(this.eventService.addListener2(WorkbenchEventType.UNTITLED_FILE_DIRTY, () => this.updateEnablement(true))); @@ -1765,8 +1763,8 @@ export class ReopenClosedFileAction extends Action { } public run(): TPromise { - let workingFilesModel: Files.IWorkingFilesModel = this.textFileService.getWorkingFilesModel(); - let entry: Files.IWorkingFileEntry = workingFilesModel.popLastClosedEntry(); + let workingFilesModel: IWorkingFilesModel = this.textFileService.getWorkingFilesModel(); + let entry: IWorkingFileEntry = workingFilesModel.popLastClosedEntry(); if (entry === null) { return TPromise.as(true); @@ -1825,12 +1823,12 @@ export abstract class BaseCloseWorkingFileAction extends Action { isDirty = this.textFileService.isDirty(); } - let saveOrRevertPromise: TPromise = TPromise.as(null); + let saveOrRevertPromise: TPromise = TPromise.as(null); if (isDirty) { let confirmResult = this.textFileService.confirmSave(this.elements); switch (confirmResult) { - case Files.ConfirmResult.SAVE: + case ConfirmResult.SAVE: if (this.elements) { saveOrRevertPromise = this.textFileService.saveAll(this.elements); } else { @@ -1838,7 +1836,7 @@ export abstract class BaseCloseWorkingFileAction extends Action { } break; - case Files.ConfirmResult.DONT_SAVE: + case ConfirmResult.DONT_SAVE: if (this.elements) { saveOrRevertPromise = this.textFileService.revertAll(this.elements); } else { @@ -1846,12 +1844,12 @@ export abstract class BaseCloseWorkingFileAction extends Action { } break; - case Files.ConfirmResult.CANCEL: + case ConfirmResult.CANCEL: return TPromise.as(null); } } - return saveOrRevertPromise.then((result?: Files.ITextFileOperationResult) => { + return saveOrRevertPromise.then((result?: ITextFileOperationResult) => { // Collect resources to dispose let resourcesToDispose: URI[] = []; @@ -1922,7 +1920,7 @@ export class CloseAllWorkingFilesAction extends BaseCloseWorkingFileAction { return super.run().then(() => closeNonFileEditors(this.editorService)); // close non file editors too } - private onModelChange(event: Files.IWorkingFileModelChangeEvent): void { + private onModelChange(event: IWorkingFileModelChangeEvent): void { this.enabled = (this.model.count() > 0); } @@ -2246,7 +2244,7 @@ export class FocusOpenEditorsView extends Action { } public run(): TPromise { - return this.viewletService.openViewlet(Files.VIEWLET_ID, true).then((viewlet: ExplorerViewlet) => { + return this.viewletService.openViewlet(VIEWLET_ID, true).then((viewlet: ExplorerViewlet) => { viewlet.getOpenEditorsView().expand(); viewlet.getOpenEditorsView().getViewer().DOMFocus(); }); @@ -2267,7 +2265,7 @@ export class FocusFilesExplorer extends Action { } public run(): TPromise { - return this.viewletService.openViewlet(Files.VIEWLET_ID, true).then((viewlet: ExplorerViewlet) => { + return this.viewletService.openViewlet(VIEWLET_ID, true).then((viewlet: ExplorerViewlet) => { const view = viewlet.getExplorerView(); if (view) { view.expand(); @@ -2296,7 +2294,7 @@ export class ShowActiveFileInExplorer extends Action { public run(): TPromise { let fileInput = asFileEditorInput(this.editorService.getActiveEditorInput(), true); if (fileInput) { - return this.viewletService.openViewlet(Files.VIEWLET_ID, false).then((viewlet: ExplorerViewlet) => { + return this.viewletService.openViewlet(VIEWLET_ID, false).then((viewlet: ExplorerViewlet) => { const isInsideWorkspace = this.contextService.isInsideWorkspace(fileInput.getResource()); if (isInsideWorkspace) { const explorerView = viewlet.getExplorerView(); diff --git a/src/vs/workbench/parts/files/browser/textFileServices.ts b/src/vs/workbench/parts/files/browser/textFileServices.ts index 479167cd06b..2b41cffab32 100644 --- a/src/vs/workbench/parts/files/browser/textFileServices.ts +++ b/src/vs/workbench/parts/files/browser/textFileServices.ts @@ -11,8 +11,9 @@ import {ListenerUnbind} from 'vs/base/common/eventEmitter'; import Event, {Emitter} from 'vs/base/common/event'; import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput'; import {CACHE, TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; -import {IResult, ITextFileOperationResult, ConfirmResult, ITextFileService, IAutoSaveConfiguration, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; +import {IResult, ITextFileOperationResult, ITextFileService, IAutoSaveConfiguration, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import {EventType} from 'vs/workbench/common/events'; +import {ConfirmResult} from 'vs/workbench/common/editor'; import {WorkingFilesModel} from 'vs/workbench/parts/files/common/workingFilesModel'; import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService'; import {IFilesConfiguration, IFileOperationResult, FileOperationResult, AutoSaveConfiguration} from 'vs/platform/files/common/files'; diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 73882814dfe..271bf285083 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -22,11 +22,11 @@ import {$} from 'vs/base/browser/builder'; import platform = require('vs/base/common/platform'); import glob = require('vs/base/common/glob'); import {ContributableActionProvider} from 'vs/workbench/browser/actionBarRegistry'; -import {LocalFileChangeEvent, ConfirmResult, IFilesConfiguration, ITextFileService} from 'vs/workbench/parts/files/common/files'; +import {LocalFileChangeEvent, IFilesConfiguration, ITextFileService} from 'vs/workbench/parts/files/common/files'; import {IFileOperationResult, FileOperationResult, IFileStat, IFileService} from 'vs/platform/files/common/files'; import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput'; import {DuplicateFileAction, ImportFileAction, PasteFileAction, keybindingForAction, IEditableData, IFileViewletState} from 'vs/workbench/parts/files/browser/fileActions'; -import {EditorOptions} from 'vs/workbench/common/editor'; +import {EditorOptions, ConfirmResult} from 'vs/workbench/common/editor'; import {IDataSource, ITree, IElementCallback, IAccessibilityProvider, IRenderer, ContextMenuEvent, ISorter, IFilter, IDragAndDrop, IDragAndDropData, IDragOverReaction, DRAG_OVER_ACCEPT_BUBBLE_DOWN, DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY, DRAG_OVER_ACCEPT_BUBBLE_UP, DRAG_OVER_ACCEPT_BUBBLE_UP_COPY, DRAG_OVER_REJECT} from 'vs/base/parts/tree/browser/tree'; import labels = require('vs/base/common/labels'); import {DesktopDragAndDropData, ExternalElementsDragAndDropData} from 'vs/base/parts/tree/browser/treeDnd'; diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index 98ae3641325..757cdc444f1 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -11,7 +11,7 @@ import Event from 'vs/base/common/event'; import {guessMimeTypes} from 'vs/base/common/mime'; import {IModel, IEditorOptions} from 'vs/editor/common/editorCommon'; import {IDisposable} from 'vs/base/common/lifecycle'; -import {EncodingMode, EditorInput, IFileEditorInput} from 'vs/workbench/common/editor'; +import {EncodingMode, EditorInput, IFileEditorInput, ConfirmResult} from 'vs/workbench/common/editor'; import {IFileStat, IFilesConfiguration} from 'vs/platform/files/common/files'; import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation'; import {FileStat} from 'vs/workbench/parts/files/common/explorerViewModel'; @@ -281,12 +281,6 @@ export class TextFileChangeEvent extends LocalFileChangeEvent { export const TEXT_FILE_SERVICE_ID = 'textFileService'; -export enum ConfirmResult { - SAVE, - DONT_SAVE, - CANCEL -} - export interface ITextFileOperationResult { results: IResult[]; } diff --git a/src/vs/workbench/parts/files/electron-browser/textFileServices.ts b/src/vs/workbench/parts/files/electron-browser/textFileServices.ts index 7c62da4417b..33adbf2534b 100644 --- a/src/vs/workbench/parts/files/electron-browser/textFileServices.ts +++ b/src/vs/workbench/parts/files/electron-browser/textFileServices.ts @@ -12,10 +12,11 @@ import strings = require('vs/base/common/strings'); import {isWindows, isLinux} from 'vs/base/common/platform'; import URI from 'vs/base/common/uri'; import {UntitledEditorModel} from 'vs/workbench/common/editor/untitledEditorModel'; +import {ConfirmResult} from 'vs/workbench/common/editor'; import {IEventService} from 'vs/platform/event/common/event'; import {TextFileService as AbstractTextFileService} from 'vs/workbench/parts/files/browser/textFileServices'; import {CACHE, TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; -import {ITextFileOperationResult, ConfirmResult, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; +import {ITextFileOperationResult, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService'; import {IFileService} from 'vs/platform/files/common/files'; import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; -- GitLab