diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index 44be0d24797..f4b681204c8 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -157,7 +157,7 @@ export class InstantiationService implements IInstantiationService { graph.lookupOrInsertNode(item); // a weak but working heuristic for cycle checks - if (cycleCount++ > 100) { + if (cycleCount++ > 150) { throw new CyclicDependencyError(graph); } diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index e4d132cc598..8d4f411c71c 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -33,6 +33,7 @@ import { EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * The text editor that leverages the diff text editor for the editing experience. @@ -55,8 +56,9 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { @ITextFileService textFileService: ITextFileService, @IHostService hostService: IHostService, @IClipboardService private _clipboardService: IClipboardService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); } protected getEditorMemento(editorGroupService: IEditorGroupsService, key: string, limit: number = 10): IEditorMemento { diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index ab5403342c3..d7042a43310 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -16,7 +16,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ITextFileService, SaveReason, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { isDiffEditor, isCodeEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -24,6 +24,7 @@ import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'textEditorViewState'; @@ -53,7 +54,8 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { @ITextFileService private readonly _textFileService: ITextFileService, @IEditorService protected editorService: IEditorService, @IEditorGroupsService protected editorGroupService: IEditorGroupsService, - @IHostService private readonly hostService: IHostService + @IHostService private readonly hostService: IHostService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(id, telemetryService, themeService, storageService); @@ -165,7 +167,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { } private maybeTriggerSaveAll(reason: SaveReason): void { - const mode = this.textFileService.getAutoSaveMode(); + const mode = this.autoSaveConfigurationService.getAutoSaveMode(); // Determine if we need to save all. In case of a window focus change we also save if auto save mode // is configured to be ON_FOCUS_CHANGE (editor focus change) diff --git a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts index 640af28854b..b4e50ce6a8f 100644 --- a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -24,6 +24,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * An editor implementation that is capable of showing the contents of resource inputs. Uses @@ -41,9 +42,10 @@ export class AbstractTextResourceEditor extends BaseTextEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); } getTitle(): string | undefined { @@ -205,8 +207,9 @@ export class TextResourceEditor extends AbstractTextResourceEditor { @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, @IEditorGroupsService editorGroupService: IEditorGroupsService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, textFileService, editorService, hostService); + super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); } } diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 945da6272a8..80aab18b259 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -16,7 +16,7 @@ import { Mode, IEntryRunContext, IAutoFocus, IQuickNavigateConfiguration, IModel import { QuickOpenEntry, QuickOpenModel, QuickOpenEntryGroup, QuickOpenItemAccessorClass } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { QuickOpenWidget, HideReason } from 'vs/base/parts/quickopen/browser/quickOpenWidget'; import { ContributableActionProvider } from 'vs/workbench/browser/actions'; -import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { Registry } from 'vs/platform/registry/common/platform'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -51,6 +51,7 @@ import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/commo import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const HELP_PREFIX = '?'; @@ -735,7 +736,8 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { @ITextFileService private readonly textFileService: ITextFileService, @IConfigurationService private readonly configurationService: IConfigurationService, @ILabelService labelService: ILabelService, - @IFileService fileService: IFileService + @IFileService fileService: IFileService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(editorService); @@ -753,7 +755,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { this.description = labelService.getUriLabel(resources.dirname(this.resource), { relative: true }); this.dirty = this.resource && this.textFileService.isDirty(this.resource); - if (this.dirty && this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + if (this.dirty && this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { this.dirty = false; // no dirty decoration if auto save is on with a short timeout } } diff --git a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts index 484a7ddce40..21d022ec1b7 100644 --- a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts +++ b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts @@ -6,10 +6,11 @@ import { URI as Uri } from 'vs/base/common/uri'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Disposable } from 'vs/base/common/lifecycle'; -import { ITextFileService, TextFileModelChangeEvent, StateChange, IAutoSaveConfiguration } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, TextFileModelChangeEvent, StateChange } from 'vs/workbench/services/textfile/common/textfiles'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files'; +import { IAutoSaveConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const AUTO_SAVE_AFTER_DELAY_DISABLED_TIME = CONTENT_CHANGE_EVENT_BUFFER_DELAY + 500; @@ -21,6 +22,7 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu @IBackupFileService private readonly backupFileService: IBackupFileService, @ITextFileService private readonly textFileService: ITextFileService, @IUntitledTextEditorService private readonly untitledTextEditorService: IUntitledTextEditorService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(); @@ -38,8 +40,8 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu this._register(this.untitledTextEditorService.onDidChangeContent(e => this.onUntitledModelChanged(e))); this._register(this.untitledTextEditorService.onDidDisposeModel(e => this.discardBackup(e))); - // Listen to config changes - this._register(this.textFileService.onAutoSaveConfigurationChange(c => this.onAutoSaveConfigurationChange(c))); + // Listen to auto save config changes + this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(c => this.onAutoSaveConfigurationChange(c))); } private onAutoSaveConfigurationChange(configuration: IAutoSaveConfiguration): void { diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts index 92253252003..b683a64070a 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts @@ -32,6 +32,7 @@ import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; import { MutableDisposable } from 'vs/base/common/lifecycle'; import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * An implementation of editor for file system resources. @@ -56,9 +57,10 @@ export class TextFileEditor extends BaseTextEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IHostService hostService: IHostService, - @IExplorerService private readonly explorerService: IExplorerService + @IExplorerService private readonly explorerService: IExplorerService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); this.updateRestoreViewStateConfiguration(); diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index cec21f34551..1fb26f4e763 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -18,7 +18,7 @@ import { isMacintosh } from 'vs/base/common/platform'; import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, IExplorerService, ExplorerResourceMoveableToTrash, ExplorerViewletVisibleContext } from 'vs/workbench/contrib/files/common/files'; import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL } from 'vs/workbench/browser/actions/workspaceCommands'; import { CLOSE_SAVED_EDITORS_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; -import { AutoSaveContext } from 'vs/workbench/services/textfile/common/textfiles'; +import { AutoSaveContext } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; import { ResourceContextKey } from 'vs/workbench/common/resources'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { URI } from 'vs/base/common/uri'; diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index ec20bae93dd..38d7fbac179 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -5,7 +5,6 @@ import 'vs/css!./media/fileactions'; import * as nls from 'vs/nls'; -import * as types from 'vs/base/common/types'; import { isWindows, isWeb } from 'vs/base/common/platform'; import * as extpath from 'vs/base/common/extpath'; import { extname, basename } from 'vs/base/common/path'; @@ -17,7 +16,7 @@ import { Action } from 'vs/base/common/actions'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { VIEWLET_ID, IExplorerService, IFilesConfiguration } from 'vs/workbench/contrib/files/common/files'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IFileService, AutoSaveConfiguration } from 'vs/platform/files/common/files'; +import { IFileService } from 'vs/platform/files/common/files'; import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; @@ -47,6 +46,7 @@ import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common import { onUnexpectedError, getErrorMessage } from 'vs/base/common/errors'; import { asDomUri, triggerDownload } from 'vs/base/browser/dom'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export const NEW_FILE_COMMAND_ID = 'explorer.newFile'; export const NEW_FILE_LABEL = nls.localize('newFile', "New File"); @@ -496,26 +496,13 @@ export class ToggleAutoSaveAction extends Action { constructor( id: string, label: string, - @IConfigurationService private readonly configurationService: IConfigurationService + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(id, label); } run(): Promise { - const setting = this.configurationService.inspect('files.autoSave'); - let userAutoSaveConfig = setting.user; - if (types.isUndefinedOrNull(userAutoSaveConfig)) { - userAutoSaveConfig = setting.default; // use default if setting not defined - } - - let newAutoSaveValue: string; - if ([AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE].some(s => s === userAutoSaveConfig)) { - newAutoSaveValue = AutoSaveConfiguration.OFF; - } else { - newAutoSaveValue = AutoSaveConfiguration.AFTER_DELAY; - } - - return this.configurationService.updateValue('files.autoSave', newAutoSaveValue, ConfigurationTarget.USER); + return this.autoSaveConfigurationService.toggleAutoSave(); } } diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index abbc65cacae..a182f6f962c 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -15,7 +15,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IEditorInput, Verbosity } from 'vs/workbench/common/editor'; import { SaveAllAction, SaveAllInGroupAction, CloseGroupAction } from 'vs/workbench/contrib/files/browser/fileActions'; import { OpenEditorsFocusedContext, ExplorerFocusedContext, IFilesConfiguration, OpenEditor } from 'vs/workbench/contrib/files/common/files'; -import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { CloseAllEditorsAction, CloseEditorAction } from 'vs/workbench/browser/parts/editor/editorActions'; import { ToggleEditorLayoutAction } from 'vs/workbench/browser/actions/layoutActions'; @@ -43,6 +43,7 @@ import { ElementsDragAndDropData, DesktopDragAndDropData } from 'vs/base/browser import { URI } from 'vs/base/common/uri'; import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { isWeb } from 'vs/base/common/platform'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const $ = dom.$; @@ -76,7 +77,8 @@ export class OpenEditorsView extends ViewletPanel { @IContextKeyService private readonly contextKeyService: IContextKeyService, @IThemeService private readonly themeService: IThemeService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IMenuService private readonly menuService: IMenuService + @IMenuService private readonly menuService: IMenuService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super({ ...(options as IViewletPanelOptions), @@ -413,7 +415,7 @@ export class OpenEditorsView extends ViewletPanel { } private updateDirtyIndicator(): void { - let dirty = this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY ? this.textFileService.getDirty().length + let dirty = this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY ? this.textFileService.getDirty().length : this.untitledTextEditorService.getDirty().length; if (dirty === 0) { dom.addClass(this.dirtyCountElement, 'hidden'); diff --git a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts index 515a11480ba..0513fcc3cf2 100644 --- a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts +++ b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts @@ -6,11 +6,11 @@ import * as nls from 'vs/nls'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { VIEWLET_ID } from 'vs/workbench/contrib/files/common/files'; -import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IWorkingCopyService, IWorkingCopy, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class DirtyFilesIndicator extends Disposable implements IWorkbenchContribution { private readonly badgeHandle = this._register(new MutableDisposable()); @@ -22,10 +22,10 @@ export class DirtyFilesIndicator extends Disposable implements IWorkbenchContrib } constructor( - @ITextFileService private readonly textFileService: ITextFileService, @ILifecycleService private readonly lifecycleService: ILifecycleService, @IActivityService private readonly activityService: IActivityService, - @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(); @@ -42,7 +42,7 @@ export class DirtyFilesIndicator extends Disposable implements IWorkbenchContrib } private onWorkingCopyDidChangeDirty(copy: IWorkingCopy): void { - if (!!(copy.capabilities & WorkingCopyCapabilities.AutoSave) && this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + if (!!(copy.capabilities & WorkingCopyCapabilities.AutoSave) && this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { return; // do not indicate changes to working copies that are auto saved after short delay } diff --git a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts index 399c49196c9..d4efe1d0084 100644 --- a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts @@ -11,12 +11,13 @@ import { EncodingMode, ConfirmResult, EditorInput, IFileEditorInput, ITextEditor import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; -import { ITextFileService, AutoSaveMode, ModelState, TextFileModelChangeEvent, LoadReason, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ModelState, TextFileModelChangeEvent, LoadReason, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IReference } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { FILE_EDITOR_INPUT_ID, TEXT_FILE_EDITOR_ID, BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; import { ILabelService } from 'vs/platform/label/common/label'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const enum ForceOpenAs { None, @@ -49,7 +50,8 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { @ITextFileService private readonly textFileService: ITextFileService, @ITextModelService private readonly textModelResolverService: ITextModelService, @ILabelService private readonly labelService: ILabelService, - @IFileService private readonly fileService: IFileService + @IFileService private readonly fileService: IFileService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(); @@ -234,7 +236,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { return true; // always indicate dirty state if we are in conflict or error state } - if (this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + if (this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { return false; // fast auto save enabled so we do not declare dirty } diff --git a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts index 18624e12e9a..d2b5d4aa360 100644 --- a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts @@ -25,6 +25,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { IExplorerService } from 'vs/workbench/contrib/files/common/files'; import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * An implementation of editor for file system resources. @@ -46,9 +47,10 @@ export class NativeTextFileEditor extends TextFileEditor { @IElectronService private readonly electronService: IElectronService, @IPreferencesService private readonly preferencesService: IPreferencesService, @IHostService hostService: IHostService, - @IExplorerService explorerService: IExplorerService + @IExplorerService explorerService: IExplorerService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, configurationService, editorService, themeService, editorGroupService, textFileService, hostService, explorerService); + super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, configurationService, editorService, themeService, editorGroupService, textFileService, hostService, explorerService, autoSaveConfigurationService); } protected handleSetInputError(error: Error, input: FileEditorInput, options: EditorOptions | undefined): void { diff --git a/src/vs/workbench/contrib/output/browser/logViewer.ts b/src/vs/workbench/contrib/output/browser/logViewer.ts index ce500dfe4a3..31ee5aac462 100644 --- a/src/vs/workbench/contrib/output/browser/logViewer.ts +++ b/src/vs/workbench/contrib/output/browser/logViewer.ts @@ -20,6 +20,7 @@ import { LOG_SCHEME, IFileOutputChannelDescriptor } from 'vs/workbench/contrib/o import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class LogViewerInput extends ResourceEditorInput { @@ -54,9 +55,10 @@ export class LogViewer extends AbstractTextResourceEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(LogViewer.LOG_VIEWER_EDITOR_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService); + super(LogViewer.LOG_VIEWER_EDITOR_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); } protected getConfigurationOverrides(): IEditorOptions { diff --git a/src/vs/workbench/contrib/output/browser/outputPanel.ts b/src/vs/workbench/contrib/output/browser/outputPanel.ts index d9eeefed511..c2e14e0763a 100644 --- a/src/vs/workbench/contrib/output/browser/outputPanel.ts +++ b/src/vs/workbench/contrib/output/browser/outputPanel.ts @@ -26,6 +26,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class OutputPanel extends AbstractTextResourceEditor { private actions: IAction[] | undefined; @@ -44,9 +45,10 @@ export class OutputPanel extends AbstractTextResourceEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(OUTPUT_PANEL_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService); + super(OUTPUT_PANEL_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); this.scopedInstantiationService = instantiationService; } diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index abec70f1f28..8c5d0468c3e 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -55,6 +55,7 @@ import { DefaultSettingsEditorModel, SettingsEditorModel } from 'vs/workbench/se import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { withNullAsUndefined, withUndefinedAsNull, assertIsDefined } from 'vs/base/common/types'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class PreferencesEditor extends BaseEditor { @@ -981,9 +982,10 @@ export class DefaultPreferencesEditor extends BaseTextEditor { @ITextFileService textFileService: ITextFileService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); } private static _getContributions(): IEditorContributionDescription[] { diff --git a/src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts b/src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts new file mode 100644 index 00000000000..9e7ac720a44 --- /dev/null +++ b/src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts @@ -0,0 +1,158 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { Event, Emitter } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IFilesConfiguration, AutoSaveConfiguration } from 'vs/platform/files/common/files'; +import { isUndefinedOrNull } from 'vs/base/common/types'; + +export const AutoSaveContext = new RawContextKey('config.files.autoSave', undefined); + +export interface IAutoSaveConfiguration { + autoSaveDelay?: number; + autoSaveFocusChange: boolean; + autoSaveApplicationChange: boolean; +} + +export const enum AutoSaveMode { + OFF, + AFTER_SHORT_DELAY, + AFTER_LONG_DELAY, + ON_FOCUS_CHANGE, + ON_WINDOW_CHANGE +} + +export const IAutoSaveConfigurationService = createDecorator('autoSaveConfigurationService'); + +export interface IAutoSaveConfigurationService { + + _serviceBrand: undefined; + + readonly onAutoSaveConfigurationChange: Event; + + getAutoSaveMode(): AutoSaveMode; + + getAutoSaveConfiguration(): IAutoSaveConfiguration; + + toggleAutoSave(): Promise; +} + +export class AutoSaveConfigurationService extends Disposable implements IAutoSaveConfigurationService { + + _serviceBrand: undefined; + + private readonly _onAutoSaveConfigurationChange = this._register(new Emitter()); + readonly onAutoSaveConfigurationChange = this._onAutoSaveConfigurationChange.event; + + private configuredAutoSaveDelay?: number; + private configuredAutoSaveOnFocusChange: boolean | undefined; + private configuredAutoSaveOnWindowChange: boolean | undefined; + + private autoSaveContext: IContextKey; + + constructor( + @IContextKeyService contextKeyService: IContextKeyService, + @IConfigurationService private readonly configurationService: IConfigurationService + ) { + super(); + + this.autoSaveContext = AutoSaveContext.bindTo(contextKeyService); + + const configuration = configurationService.getValue(); + this.onFilesConfigurationChange(configuration); + + this.registerListeners(); + } + + private registerListeners(): void { + + // Files configuration changes + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('files')) { + this.onFilesConfigurationChange(this.configurationService.getValue()); + } + })); + } + + private onFilesConfigurationChange(configuration: IFilesConfiguration): void { + const autoSaveMode = configuration?.files?.autoSave || AutoSaveConfiguration.OFF; + this.autoSaveContext.set(autoSaveMode); + switch (autoSaveMode) { + case AutoSaveConfiguration.AFTER_DELAY: + this.configuredAutoSaveDelay = configuration?.files?.autoSaveDelay; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = false; + break; + + case AutoSaveConfiguration.ON_FOCUS_CHANGE: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = true; + this.configuredAutoSaveOnWindowChange = false; + break; + + case AutoSaveConfiguration.ON_WINDOW_CHANGE: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = true; + break; + + default: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = false; + break; + } + + // Emit as event + this._onAutoSaveConfigurationChange.fire(this.getAutoSaveConfiguration()); + } + + getAutoSaveMode(): AutoSaveMode { + if (this.configuredAutoSaveOnFocusChange) { + return AutoSaveMode.ON_FOCUS_CHANGE; + } + + if (this.configuredAutoSaveOnWindowChange) { + return AutoSaveMode.ON_WINDOW_CHANGE; + } + + if (this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0) { + return this.configuredAutoSaveDelay <= 1000 ? AutoSaveMode.AFTER_SHORT_DELAY : AutoSaveMode.AFTER_LONG_DELAY; + } + + return AutoSaveMode.OFF; + } + + getAutoSaveConfiguration(): IAutoSaveConfiguration { + return { + autoSaveDelay: this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0 ? this.configuredAutoSaveDelay : undefined, + autoSaveFocusChange: !!this.configuredAutoSaveOnFocusChange, + autoSaveApplicationChange: !!this.configuredAutoSaveOnWindowChange + }; + } + + async toggleAutoSave(): Promise { + const setting = this.configurationService.inspect('files.autoSave'); + let userAutoSaveConfig = setting.user; + if (isUndefinedOrNull(userAutoSaveConfig)) { + userAutoSaveConfig = setting.default; // use default if setting not defined + } + + let newAutoSaveValue: string; + if ([AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE].some(s => s === userAutoSaveConfig)) { + newAutoSaveValue = AutoSaveConfiguration.OFF; + } else { + newAutoSaveValue = AutoSaveConfiguration.AFTER_DELAY; + } + + return this.configurationService.updateValue('files.autoSave', newAutoSaveValue, ConfigurationTarget.USER); + } +} + +registerSingleton(IAutoSaveConfigurationService, AutoSaveConfigurationService); diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index 7a68d53bd7a..ea66d626d2e 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -9,11 +9,11 @@ import * as objects from 'vs/base/common/objects'; import { Emitter, AsyncEmitter } from 'vs/base/common/event'; import * as platform from 'vs/base/common/platform'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, AutoSaveContext, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, FileOperationWillRunEvent, FileOperationDidRunEvent } from 'vs/workbench/services/textfile/common/textfiles'; +import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, FileOperationWillRunEvent, FileOperationDidRunEvent } from 'vs/workbench/services/textfile/common/textfiles'; import { ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor'; import { ILifecycleService, ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, AutoSaveConfiguration, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions, FileOperation } from 'vs/platform/files/common/files'; +import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions, FileOperation } from 'vs/platform/files/common/files'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Disposable } from 'vs/base/common/lifecycle'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -24,7 +24,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ResourceMap } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { createTextBufferFactoryFromSnapshot, createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; import { IModelService } from 'vs/editor/common/services/modelService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; @@ -38,6 +37,7 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { ITextSnapshot } from 'vs/editor/common/model'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * The workbench file service implementation implements the raw file service spec and adds additional methods on top. @@ -48,9 +48,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex //#region events - private readonly _onAutoSaveConfigurationChange = this._register(new Emitter()); - readonly onAutoSaveConfigurationChange = this._onAutoSaveConfigurationChange.event; - private readonly _onFilesAssociationChange = this._register(new Emitter()); readonly onFilesAssociationChange = this._onFilesAssociationChange.event; @@ -68,11 +65,8 @@ export abstract class AbstractTextFileService extends Disposable implements ITex abstract get encoding(): IResourceEncodings; private currentFilesAssociationConfig: { [key: string]: string; }; - private configuredAutoSaveDelay?: number; - private configuredAutoSaveOnFocusChange: boolean | undefined; - private configuredAutoSaveOnWindowChange: boolean | undefined; + private configuredHotExit: string | undefined; - private autoSaveContext: IContextKey; constructor( @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @@ -87,22 +81,19 @@ export abstract class AbstractTextFileService extends Disposable implements ITex @INotificationService private readonly notificationService: INotificationService, @IBackupFileService private readonly backupFileService: IBackupFileService, @IHistoryService private readonly historyService: IHistoryService, - @IContextKeyService contextKeyService: IContextKeyService, @IDialogService private readonly dialogService: IDialogService, @IFileDialogService private readonly fileDialogService: IFileDialogService, @IEditorService private readonly editorService: IEditorService, - @ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService + @ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(); this._models = this._register(instantiationService.createInstance(TextFileEditorModelManager)); - this.autoSaveContext = AutoSaveContext.bindTo(contextKeyService); const configuration = configurationService.getValue(); this.currentFilesAssociationConfig = configuration?.files?.associations; - this.onFilesConfigurationChange(configuration); - this.registerListeners(); } @@ -120,6 +111,17 @@ export abstract class AbstractTextFileService extends Disposable implements ITex this.onFilesConfigurationChange(this.configurationService.getValue()); } })); + + // Auto save changes + this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(() => this.onAutoSaveConfigurationChange())); + } + + private onAutoSaveConfigurationChange(): void { + + // save all dirty when enabling auto save + if (this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF) { + this.saveAll(); + } } protected onBeforeShutdown(reason: ShutdownReason): boolean | Promise { @@ -130,7 +132,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // If auto save is enabled, save all files and then check again for dirty files // We DO NOT run any save participant if we are in the shutdown phase for performance reasons - if (this.getAutoSaveMode() !== AutoSaveMode.OFF) { + if (this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF) { return this.saveAll(false /* files only */, { skipSaveParticipants: true }).then(() => { // If we still have dirty files, we either have untitled ones or files that cannot be saved @@ -302,43 +304,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex } protected onFilesConfigurationChange(configuration: IFilesConfiguration): void { - const wasAutoSaveEnabled = (this.getAutoSaveMode() !== AutoSaveMode.OFF); - - const autoSaveMode = configuration?.files?.autoSave || AutoSaveConfiguration.OFF; - this.autoSaveContext.set(autoSaveMode); - switch (autoSaveMode) { - case AutoSaveConfiguration.AFTER_DELAY: - this.configuredAutoSaveDelay = configuration?.files?.autoSaveDelay; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = false; - break; - - case AutoSaveConfiguration.ON_FOCUS_CHANGE: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = true; - this.configuredAutoSaveOnWindowChange = false; - break; - - case AutoSaveConfiguration.ON_WINDOW_CHANGE: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = true; - break; - - default: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = false; - break; - } - - // Emit as event - this._onAutoSaveConfigurationChange.fire(this.getAutoSaveConfiguration()); - - // save all dirty when enabling auto save - if (!wasAutoSaveEnabled && this.getAutoSaveMode() !== AutoSaveMode.OFF) { - this.saveAll(); - } // Check for change in files associations const filesAssociation = configuration?.files?.associations; @@ -1006,30 +971,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex //#region config - getAutoSaveMode(): AutoSaveMode { - if (this.configuredAutoSaveOnFocusChange) { - return AutoSaveMode.ON_FOCUS_CHANGE; - } - - if (this.configuredAutoSaveOnWindowChange) { - return AutoSaveMode.ON_WINDOW_CHANGE; - } - - if (this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0) { - return this.configuredAutoSaveDelay <= 1000 ? AutoSaveMode.AFTER_SHORT_DELAY : AutoSaveMode.AFTER_LONG_DELAY; - } - - return AutoSaveMode.OFF; - } - - getAutoSaveConfiguration(): IAutoSaveConfiguration { - return { - autoSaveDelay: this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0 ? this.configuredAutoSaveDelay : undefined, - autoSaveFocusChange: !!this.configuredAutoSaveOnFocusChange, - autoSaveApplicationChange: !!this.configuredAutoSaveOnWindowChange - }; - } - get isHotExitEnabled(): boolean { return !this.environmentService.isExtensionDevelopment && this.configuredHotExit !== HotExitConfiguration.OFF; } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index b86d2ed4508..c50d7ea0404 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri'; import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, ITextFileStreamContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, ITextFileStreamContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; import { EncodingMode } from 'vs/workbench/common/editor'; import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; @@ -30,6 +30,7 @@ import { isEqual, isEqualOrParent, extname, basename, joinPath } from 'vs/base/c import { onUnexpectedError } from 'vs/base/common/errors'; import { Schemas } from 'vs/base/common/network'; import { IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IAutoSaveConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export interface IBackupMetaData { mtime: number; @@ -121,11 +122,12 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil @IEnvironmentService private readonly environmentService: IEnvironmentService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @ILogService private readonly logService: ILogService, - @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(modelService, modeService); - this.updateAutoSaveConfiguration(textFileService.getAutoSaveConfiguration()); + this.updateAutoSaveConfiguration(autoSaveConfigurationService.getAutoSaveConfiguration()); // Make known to working copy service this._register(this.workingCopyService.registerWorkingCopy(this)); @@ -135,7 +137,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private registerListeners(): void { this._register(this.fileService.onFileChanges(e => this.onFileChanges(e))); - this._register(this.textFileService.onAutoSaveConfigurationChange(config => this.updateAutoSaveConfiguration(config))); + this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(config => this.updateAutoSaveConfiguration(config))); this._register(this.textFileService.onFilesAssociationChange(e => this.onFilesAssociationChange())); this._register(this.onDidStateChange(e => this.onStateChange(e))); } diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 4ab9efb61c7..93414127020 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -11,7 +11,6 @@ import { IBaseStatWithMetadata, IFileStatWithMetadata, IReadFileOptions, IWriteF import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; import { ITextBufferFactory, ITextModel, ITextSnapshot } from 'vs/editor/common/model'; -import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { isNative } from 'vs/base/common/platform'; @@ -23,8 +22,6 @@ export interface ITextFileService extends IDisposable { _serviceBrand: undefined; - readonly onAutoSaveConfigurationChange: Event; - readonly onFilesAssociationChange: Event; readonly isHotExitEnabled: boolean; @@ -144,16 +141,6 @@ export interface ITextFileService extends IDisposable { * confirming for all dirty resources. */ confirmSave(resources?: URI[]): Promise; - - /** - * Convenient fast access to the current auto save mode. - */ - getAutoSaveMode(): AutoSaveMode; - - /** - * Convenient fast access to the raw configured auto save settings. - */ - getAutoSaveConfiguration(): IAutoSaveConfiguration; } @@ -341,8 +328,6 @@ export class TextFileModelChangeEvent { } } -export const AutoSaveContext = new RawContextKey('config.files.autoSave', undefined); - export interface ITextFileOperationResult { results: IResult[]; } @@ -353,20 +338,6 @@ export interface IResult { success?: boolean; } -export interface IAutoSaveConfiguration { - autoSaveDelay?: number; - autoSaveFocusChange: boolean; - autoSaveApplicationChange: boolean; -} - -export const enum AutoSaveMode { - OFF, - AFTER_SHORT_DELAY, - AFTER_LONG_DELAY, - ON_FOCUS_CHANGE, - ON_WINDOW_CHANGE -} - export const enum SaveReason { EXPLICIT = 1, AUTO = 2, diff --git a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index 23cf1f058dc..3a1487ec779 100644 --- a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -38,11 +38,11 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { INotificationService } from 'vs/platform/notification/common/notification'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ConfirmResult } from 'vs/workbench/common/editor'; import { assign } from 'vs/base/common/objects'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class NativeTextFileService extends AbstractTextFileService { @@ -59,15 +59,15 @@ export class NativeTextFileService extends AbstractTextFileService { @INotificationService notificationService: INotificationService, @IBackupFileService backupFileService: IBackupFileService, @IHistoryService historyService: IHistoryService, - @IContextKeyService contextKeyService: IContextKeyService, @IDialogService dialogService: IDialogService, @IFileDialogService fileDialogService: IFileDialogService, @IEditorService editorService: IEditorService, @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, @IElectronService private readonly electronService: IElectronService, - @IProductService private readonly productService: IProductService + @IProductService private readonly productService: IProductService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(contextService, fileService, untitledTextEditorService, lifecycleService, instantiationService, configurationService, modeService, modelService, environmentService, notificationService, backupFileService, historyService, contextKeyService, dialogService, fileDialogService, editorService, textResourceConfigurationService); + super(contextService, fileService, untitledTextEditorService, lifecycleService, instantiationService, configurationService, modeService, modelService, environmentService, notificationService, backupFileService, historyService, dialogService, fileDialogService, editorService, textResourceConfigurationService, autoSaveConfigurationService); } private _encoding: EncodingOracle | undefined; diff --git a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts index 7bff97ff408..a7797845a17 100644 --- a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts +++ b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts @@ -4,10 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { WorkingCopyService, IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { URI } from 'vs/base/common/uri'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; +import { TestWorkingCopyService } from 'vs/workbench/test/workbenchTestServices'; suite('WorkingCopyService', () => { @@ -48,7 +49,7 @@ suite('WorkingCopyService', () => { } test('registry - basics', () => { - const service = new WorkingCopyService(); + const service = new TestWorkingCopyService(); const onDidChangeDirty: IWorkingCopy[] = []; service.onDidChangeDirty(copy => onDidChangeDirty.push(copy)); @@ -104,7 +105,7 @@ suite('WorkingCopyService', () => { }); test('registry - multiple copies on same resource', () => { - const service = new WorkingCopyService(); + const service = new TestWorkingCopyService(); const onDidChangeDirty: IWorkingCopy[] = []; service.onDidChangeDirty(copy => onDidChangeDirty.push(copy)); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 5d9d717d2bc..b1e238cb5d5 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -93,6 +93,7 @@ import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; import { find } from 'vs/base/common/arrays'; import { WorkingCopyService, IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IAutoSaveConfigurationService, AutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); @@ -207,13 +208,13 @@ export class TestTextFileService extends NativeTextFileService { @INotificationService notificationService: INotificationService, @IBackupFileService backupFileService: IBackupFileService, @IHistoryService historyService: IHistoryService, - @IContextKeyService contextKeyService: IContextKeyService, @IDialogService dialogService: IDialogService, @IFileDialogService fileDialogService: IFileDialogService, @IEditorService editorService: IEditorService, @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, @IElectronService electronService: IElectronService, - @IProductService productService: IProductService + @IProductService productService: IProductService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { super( contextService, @@ -228,13 +229,13 @@ export class TestTextFileService extends NativeTextFileService { notificationService, backupFileService, historyService, - contextKeyService, dialogService, fileDialogService, editorService, textResourceConfigurationService, electronService, - productService + productService, + autoSaveConfigurationService ); } @@ -297,11 +298,13 @@ export class TestTextFileService extends NativeTextFileService { export function workbenchInstantiationService(): IInstantiationService { let instantiationService = new TestInstantiationService(new ServiceCollection([ILifecycleService, new TestLifecycleService()])); instantiationService.stub(IEnvironmentService, TestEnvironmentService); - instantiationService.stub(IContextKeyService, instantiationService.createInstance(MockContextKeyService)); + const contextKeyService = instantiationService.createInstance(MockContextKeyService); + instantiationService.stub(IContextKeyService, contextKeyService); const workspaceContextService = new TestContextService(TestWorkspace); instantiationService.stub(IWorkspaceContextService, workspaceContextService); const configService = new TestConfigurationService(); instantiationService.stub(IConfigurationService, configService); + instantiationService.stub(IAutoSaveConfigurationService, new AutoSaveConfigurationService(contextKeyService, configService)); instantiationService.stub(ITextResourceConfigurationService, new TestTextResourceConfigurationService(configService)); instantiationService.stub(IUntitledTextEditorService, instantiationService.createInstance(UntitledTextEditorService)); instantiationService.stub(IStorageService, new TestStorageService()); @@ -1467,6 +1470,4 @@ export class TestDialogMainService implements IDialogMainService { } } -export class TestWorkingCopyService extends WorkingCopyService { - -} +export class TestWorkingCopyService extends WorkingCopyService { } diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 8c9f50ad424..3c0ed98e54e 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -83,6 +83,7 @@ import 'vs/workbench/services/userDataSync/common/settingsMergeService'; import 'vs/workbench/services/path/common/remotePathService'; import 'vs/workbench/services/remote/common/remoteExplorerService'; import 'vs/workbench/services/workingCopy/common/workingCopyService'; +import 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';