From 35d2f1cee76c176af0627a12f5be4606327a8758 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 27 Jan 2016 12:38:23 +0100 Subject: [PATCH] The unsaved file marker (the dot thing) should appear when content in buffer != content on disk (fixes #2357) --- src/vs/platform/files/common/files.ts | 2 +- .../files/browser/editors/fileEditorInput.ts | 6 ++--- .../parts/files/browser/fileTracker.ts | 6 ++--- .../parts/files/browser/files.contribution.ts | 10 +++---- .../parts/files/browser/textFileServices.ts | 26 ++++++++++++------- .../files/browser/views/workingFilesView.ts | 6 ++--- .../files/browser/views/workingFilesViewer.ts | 4 +-- src/vs/workbench/parts/files/common/files.ts | 13 +++++++--- .../parts/files/common/workingFilesModel.ts | 6 ++--- .../electron-browser/electronFileTracker.ts | 6 ++--- .../electron-browser/textFileServices.ts | 4 +-- 11 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index e62c07154f4..06be9949a43 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -412,7 +412,7 @@ export enum FileOperationResult { FILE_TOO_LARGE } -export const AutoSaveModes = { +export const AutoSaveConfiguration = { OFF: 'off', AFTER_DELAY: 'afterDelay', ON_FOCUS_CHANGE: 'onFocusChange' diff --git a/src/vs/workbench/parts/files/browser/editors/fileEditorInput.ts b/src/vs/workbench/parts/files/browser/editors/fileEditorInput.ts index a3410f79668..8fa3bec8db1 100644 --- a/src/vs/workbench/parts/files/browser/editors/fileEditorInput.ts +++ b/src/vs/workbench/parts/files/browser/editors/fileEditorInput.ts @@ -19,7 +19,7 @@ import {IEditorRegistry, Extensions, EditorDescriptor} from 'vs/workbench/browse import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; import {IFileOperationResult, FileOperationResult} from 'vs/platform/files/common/files'; import {FileEditorDescriptor} from 'vs/workbench/parts/files/browser/files'; -import {ITextFileService, BINARY_FILE_EDITOR_ID, FILE_EDITOR_INPUT_ID, FileEditorInput as CommonFileEditorInput} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService, BINARY_FILE_EDITOR_ID, FILE_EDITOR_INPUT_ID, FileEditorInput as CommonFileEditorInput, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import {CACHE, TextFileEditorModel, State} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; @@ -158,11 +158,11 @@ export class FileEditorInput extends CommonFileEditorInput { } case State.DIRTY: { - return { state: 'dirty', decoration: !this.textFileService.isAutoSaveEnabled() ? '\u25cf' : '', displayText: FileEditorInput.nlsDirtyDisplay, description: FileEditorInput.nlsDirtyMeta }; + return { state: 'dirty', decoration: (this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) ? '\u25cf' : '', displayText: FileEditorInput.nlsDirtyDisplay, description: FileEditorInput.nlsDirtyMeta }; } case State.PENDING_SAVE: - return { state: 'saving', decoration: !this.textFileService.isAutoSaveEnabled() ? '\u25cf' : '', displayText: FileEditorInput.nlsPendingSaveDisplay, description: FileEditorInput.nlsPendingSaveMeta }; + return { state: 'saving', decoration: (this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) ? '\u25cf' : '', displayText: FileEditorInput.nlsPendingSaveDisplay, description: FileEditorInput.nlsPendingSaveMeta }; case State.ERROR: return { state: 'error', decoration: '\u25cf', displayText: FileEditorInput.nlsErrorDisplay, description: FileEditorInput.nlsErrorMeta }; diff --git a/src/vs/workbench/parts/files/browser/fileTracker.ts b/src/vs/workbench/parts/files/browser/fileTracker.ts index fe37e8b5a43..bfc96695d1b 100644 --- a/src/vs/workbench/parts/files/browser/fileTracker.ts +++ b/src/vs/workbench/parts/files/browser/fileTracker.ts @@ -14,7 +14,7 @@ import {DiffEditorInput} from 'vs/workbench/common/editor/diffEditorInput'; import {EditorInput, EditorOptions} from 'vs/workbench/common/editor'; import {BaseEditor} from 'vs/workbench/browser/parts/editor/baseEditor'; import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor'; -import {LocalFileChangeEvent, VIEWLET_ID, EventType as FileEventType, IWorkingFilesModel, ITextFileService} from 'vs/workbench/parts/files/common/files'; +import {LocalFileChangeEvent, VIEWLET_ID, EventType as FileEventType, IWorkingFilesModel, ITextFileService, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import {FileChangeType, FileChangesEvent, EventType as CommonFileEventType} from 'vs/platform/files/common/files'; import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEditorInput'; import {IFrameEditorInput} from 'vs/workbench/common/editor/iframeEditorInput'; @@ -84,8 +84,8 @@ export class FileTracker implements IWorkbenchContribution { private onTextFileDirty(e: LocalFileChangeEvent): void { this.emitInputStateChangeEvent(e.getAfter().resource); - if (!this.textFileService.isAutoSaveEnabled()) { - this.updateActivityBadge(); // no indication needed when auto save is turned off and we didn't show dirty + if (this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) { + this.updateActivityBadge(); // no indication needed when auto save is enabled for short delay } } diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index 9e18b2f8680..5fd5aa68feb 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -19,7 +19,7 @@ import {IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions} from import {IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory} from 'vs/workbench/browser/parts/editor/baseEditor'; import {EditorInput, IFileEditorInput} from 'vs/workbench/common/editor'; import {FileEditorDescriptor} from 'vs/workbench/parts/files/browser/files'; -import {AutoSaveModes} from 'vs/platform/files/common/files'; +import {AutoSaveConfiguration} from 'vs/platform/files/common/files'; import {FILE_EDITOR_INPUT_ID, VIEWLET_ID} from 'vs/workbench/parts/files/common/files'; import {FileTracker} from 'vs/workbench/parts/files/browser/fileTracker'; import {SaveParticipant} from 'vs/workbench/parts/files/common/editors/saveParticipant'; @@ -203,14 +203,14 @@ configurationRegistry.registerConfiguration({ }, 'files.autoSave': { 'type': 'string', - 'enum': [AutoSaveModes.OFF, AutoSaveModes.AFTER_DELAY, AutoSaveModes.ON_FOCUS_CHANGE], - 'default': AutoSaveModes.OFF, - 'description': nls.localize('autoSave', "Controls auto save of dirty files. Accepted values: \"{0}\", \"{1}\", \"{2}\". If set to \"{3}\" you can configure the delay in \"files.autoSaveDelay\".", AutoSaveModes.OFF, AutoSaveModes.AFTER_DELAY, AutoSaveModes.ON_FOCUS_CHANGE, AutoSaveModes.AFTER_DELAY) + 'enum': [AutoSaveConfiguration.OFF, AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE], + 'default': AutoSaveConfiguration.OFF, + 'description': nls.localize('autoSave', "Controls auto save of dirty files. Accepted values: \"{0}\", \"{1}\", \"{2}\". If set to \"{3}\" you can configure the delay in \"files.autoSaveDelay\".", AutoSaveConfiguration.OFF, AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.AFTER_DELAY) }, 'files.autoSaveDelay': { 'type': 'number', 'default': 1000, - 'description': nls.localize('autoSaveDelay', "Controls the delay in ms after which a dirty file is saved automatically. Only applies when \"files.autoSave\" is set to \"{0}\"", AutoSaveModes.AFTER_DELAY) + 'description': nls.localize('autoSaveDelay', "Controls the delay in ms after which a dirty file is saved automatically. Only applies when \"files.autoSave\" is set to \"{0}\"", AutoSaveConfiguration.AFTER_DELAY) } } }); diff --git a/src/vs/workbench/parts/files/browser/textFileServices.ts b/src/vs/workbench/parts/files/browser/textFileServices.ts index ddf1da1ab37..abd01393db6 100644 --- a/src/vs/workbench/parts/files/browser/textFileServices.ts +++ b/src/vs/workbench/parts/files/browser/textFileServices.ts @@ -11,11 +11,11 @@ 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} from 'vs/workbench/parts/files/common/files'; +import {IResult, ITextFileOperationResult, ConfirmResult, ITextFileService, IAutoSaveConfiguration, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import {EventType} from 'vs/workbench/common/events'; import {WorkingFilesModel} from 'vs/workbench/parts/files/common/workingFilesModel'; import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService'; -import {IFilesConfiguration, IFileOperationResult, FileOperationResult, AutoSaveModes} from 'vs/platform/files/common/files'; +import {IFilesConfiguration, IFileOperationResult, FileOperationResult, AutoSaveConfiguration} from 'vs/platform/files/common/files'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; import {IEventService} from 'vs/platform/event/common/event'; @@ -98,16 +98,16 @@ export abstract class TextFileService implements ITextFileService { } private onConfigurationChange(configuration: IFilesConfiguration): void { - const wasAutoSaveEnabled = this.isAutoSaveEnabled(); + const wasAutoSaveEnabled = (this.getAutoSaveMode() !== AutoSaveMode.OFF); - const autoSaveMode = (configuration && configuration.files && configuration.files.autoSave) || AutoSaveModes.OFF; + const autoSaveMode = (configuration && configuration.files && configuration.files.autoSave) || AutoSaveConfiguration.OFF; switch (autoSaveMode) { - case AutoSaveModes.AFTER_DELAY: + case AutoSaveConfiguration.AFTER_DELAY: this.configuredAutoSaveDelay = configuration && configuration.files && configuration.files.autoSaveDelay; this.configuredAutoSaveOnFocusChange = false; break; - case AutoSaveModes.ON_FOCUS_CHANGE: + case AutoSaveConfiguration.ON_FOCUS_CHANGE: this.configuredAutoSaveDelay = void 0; this.configuredAutoSaveOnFocusChange = true; break; @@ -122,7 +122,7 @@ export abstract class TextFileService implements ITextFileService { this._onAutoSaveConfigurationChange.fire(this.getAutoSaveConfiguration()); // save all dirty when enabling auto save - if (!wasAutoSaveEnabled && this.isAutoSaveEnabled()) { + if (!wasAutoSaveEnabled && this.getAutoSaveMode() !== AutoSaveMode.OFF) { this.saveAll().done(null, errors.onUnexpectedError); } } @@ -248,8 +248,16 @@ export abstract class TextFileService implements ITextFileService { return this.workingFilesModel; } - public isAutoSaveEnabled(): boolean { - return this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0 || this.configuredAutoSaveOnFocusChange; + public getAutoSaveMode(): AutoSaveMode { + if (this.configuredAutoSaveOnFocusChange) { + return AutoSaveMode.ON_FOCUS_CHANGE; + } + + if (this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0) { + return this.configuredAutoSaveDelay <= 1000 ? AutoSaveMode.AFTER_SHORT_DELAY : AutoSaveMode.AFTER_LONG_DELAY; + } + + return AutoSaveMode.OFF; } public getAutoSaveConfiguration(): IAutoSaveConfiguration { diff --git a/src/vs/workbench/parts/files/browser/views/workingFilesView.ts b/src/vs/workbench/parts/files/browser/views/workingFilesView.ts index 29b8b413ac2..578dae76433 100644 --- a/src/vs/workbench/parts/files/browser/views/workingFilesView.ts +++ b/src/vs/workbench/parts/files/browser/views/workingFilesView.ts @@ -12,7 +12,7 @@ import {Tree} from 'vs/base/parts/tree/browser/treeImpl'; import {IAction, IActionRunner} from 'vs/base/common/actions'; import workbenchEditorCommon = require('vs/workbench/common/editor'); import {CollapsibleState} from 'vs/base/browser/ui/splitview/splitview'; -import {IWorkingFileEntry, IWorkingFilesModel, IWorkingFileModelChangeEvent, LocalFileChangeEvent, EventType as FileEventType, IFilesConfiguration, ITextFileService} from 'vs/workbench/parts/files/common/files'; +import {IWorkingFileEntry, IWorkingFilesModel, IWorkingFileModelChangeEvent, LocalFileChangeEvent, EventType as FileEventType, IFilesConfiguration, ITextFileService, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import dom = require('vs/base/browser/dom'); import {IDisposable} from 'vs/base/common/lifecycle'; import errors = require('vs/base/common/errors'); @@ -148,8 +148,8 @@ export class WorkingFilesView extends AdaptiveCollapsibleViewletView { } private onTextFileDirty(e: LocalFileChangeEvent): void { - if (!this.textFileService.isAutoSaveEnabled()) { - this.updateDirtyIndicator(); // no indication needed when auto save is turned off and we didn't show dirty + if (this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) { + this.updateDirtyIndicator(); // no indication needed when auto save is enabled for short delay } } diff --git a/src/vs/workbench/parts/files/browser/views/workingFilesViewer.ts b/src/vs/workbench/parts/files/browser/views/workingFilesViewer.ts index 8f5c602b743..8d09ad31936 100644 --- a/src/vs/workbench/parts/files/browser/views/workingFilesViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/workingFilesViewer.ts @@ -22,7 +22,7 @@ import actions = require('vs/base/common/actions'); import {ActionsRenderer} from 'vs/base/parts/tree/browser/actionsRenderer'; import {ContributableActionProvider} from 'vs/workbench/browser/actionBarRegistry'; import {keybindingForAction, CloseWorkingFileAction, SelectResourceForCompareAction, CompareResourcesAction, SaveFileAsAction, SaveFileAction, RevertFileAction, OpenToSideAction} from 'vs/workbench/parts/files/browser/fileActions'; -import {asFileResource, ITextFileService} from 'vs/workbench/parts/files/common/files'; +import {asFileResource, ITextFileService, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import {WorkingFileEntry, WorkingFilesModel} from 'vs/workbench/parts/files/common/workingFilesModel'; import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; @@ -164,7 +164,7 @@ export class WorkingFilesActionProvider extends ContributableActionProvider { actions.unshift(openToSideAction); // be on top // Files: Save / Revert - let autoSaveEnabled = this.textFileService.isAutoSaveEnabled(); + let autoSaveEnabled = (this.textFileService.getAutoSaveMode() !== AutoSaveMode.OFF); if ((!autoSaveEnabled || element.dirty) && element.isFile) { actions.push(new Separator()); diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index 7dab721c811..097839ddd0e 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -293,6 +293,13 @@ export interface IAutoSaveConfiguration { autoSaveFocusChange: boolean; } +export enum AutoSaveMode { + OFF, + AFTER_SHORT_DELAY, + AFTER_LONG_DELAY, + ON_FOCUS_CHANGE +} + export var ITextFileService = createDecorator(TEXT_FILE_SERVICE_ID); export interface ITextFileService extends IDisposable { @@ -367,12 +374,12 @@ export interface ITextFileService extends IDisposable { getWorkingFilesModel(): IWorkingFilesModel; /** - * Checks if the user configured auto save to be enabled or not + * Convinient fast access to the current auto save mode. */ - isAutoSaveEnabled(): boolean; + getAutoSaveMode(): AutoSaveMode; /** - * Convinient fast access to the configured auto save settings. + * Convinient fast access to the raw configured auto save settings. */ getAutoSaveConfiguration(): IAutoSaveConfiguration; diff --git a/src/vs/workbench/parts/files/common/workingFilesModel.ts b/src/vs/workbench/parts/files/common/workingFilesModel.ts index 5868ca3d007..3f0320da664 100644 --- a/src/vs/workbench/parts/files/common/workingFilesModel.ts +++ b/src/vs/workbench/parts/files/common/workingFilesModel.ts @@ -11,7 +11,7 @@ import paths = require('vs/base/common/paths'); import errors = require('vs/base/common/errors'); import labels = require('vs/base/common/labels'); import {disposeAll, IDisposable} from 'vs/base/common/lifecycle'; -import {ITextFileService, IWorkingFilesModel, IWorkingFileModelChangeEvent, IWorkingFileEntry, EventType, LocalFileChangeEvent, WORKING_FILES_MODEL_ENTRY_CLASS_ID} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService, IWorkingFilesModel, IWorkingFileModelChangeEvent, IWorkingFileEntry, EventType, LocalFileChangeEvent, WORKING_FILES_MODEL_ENTRY_CLASS_ID, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import {IFileStat, FileChangeType, FileChangesEvent, EventType as FileEventType} from 'vs/platform/files/common/files'; import {UntitledEditorEvent, EventType as WorkbenchEventType, EditorEvent} from 'vs/workbench/common/events'; import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService'; @@ -85,8 +85,8 @@ export class WorkingFilesModel implements IWorkingFilesModel { } private onTextFileDirty(e: LocalFileChangeEvent): void { - if (!this.textFileService.isAutoSaveEnabled()) { - this.updateDirtyState(e.getAfter().resource, true); // no indication needed when auto save is turned off and we didn't show dirty + if (this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) { + this.updateDirtyState(e.getAfter().resource, true); // no indication needed when auto save is enabled for short delay } else { this.addEntry(e.getAfter().resource); } diff --git a/src/vs/workbench/parts/files/electron-browser/electronFileTracker.ts b/src/vs/workbench/parts/files/electron-browser/electronFileTracker.ts index a681c9dc1f3..3c11c78ba19 100644 --- a/src/vs/workbench/parts/files/electron-browser/electronFileTracker.ts +++ b/src/vs/workbench/parts/files/electron-browser/electronFileTracker.ts @@ -6,7 +6,7 @@ 'use strict'; import {IWorkbenchContribution} from 'vs/workbench/common/contributions'; -import {LocalFileChangeEvent, IWorkingFileModelChangeEvent, EventType as FileEventType, ITextFileService} from 'vs/workbench/parts/files/common/files'; +import {LocalFileChangeEvent, IWorkingFileModelChangeEvent, EventType as FileEventType, ITextFileService, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import {IFileService} from 'vs/platform/files/common/files'; import {OpenResourcesAction} from 'vs/workbench/parts/files/browser/fileActions'; import plat = require('vs/base/common/platform'); @@ -159,8 +159,8 @@ export class FileTracker implements IWorkbenchContribution { } private onTextFileDirty(e: LocalFileChangeEvent): void { - if (!this.textFileService.isAutoSaveEnabled() && !this.isDocumentedEdited) { - this.updateDocumentEdited(); // no indication needed when auto save is turned off and we didn't show dirty + if ((this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) && !this.isDocumentedEdited) { + this.updateDocumentEdited(); // no indication needed when auto save is enabled for short delay } } diff --git a/src/vs/workbench/parts/files/electron-browser/textFileServices.ts b/src/vs/workbench/parts/files/electron-browser/textFileServices.ts index b37d8e6c732..29ee63e3ecf 100644 --- a/src/vs/workbench/parts/files/electron-browser/textFileServices.ts +++ b/src/vs/workbench/parts/files/electron-browser/textFileServices.ts @@ -18,7 +18,7 @@ import {UntitledEditorModel} from 'vs/workbench/common/editor/untitledEditorMode 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} from 'vs/workbench/parts/files/common/files'; +import {ITextFileOperationResult, ConfirmResult, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; import {IWorkbenchActionRegistry, Extensions as ActionExtensions} from 'vs/workbench/common/actionRegistry'; import {SyncActionDescriptor} from 'vs/platform/actions/common/actions'; import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService'; @@ -55,7 +55,7 @@ export class TextFileService extends AbstractTextFileService { if (this.getDirty().length) { // If auto save is enabled, save all files and then check again for dirty files - if (this.isAutoSaveEnabled()) { + if (this.getAutoSaveMode() !== AutoSaveMode.OFF) { return this.saveAll(false /* files only */).then(() => { if (this.getDirty().length) { return this.confirmBeforeShutdown(); // we still have dirty files around, so confirm normally -- GitLab