提交 32202834 编写于 作者: B Benjamin Pasero

editor - introduce and use editor memento

上级 e8fc8943
......@@ -6,11 +6,16 @@
import { TPromise } from 'vs/base/common/winjs.base';
import { Panel } from 'vs/workbench/browser/panel';
import { EditorInput, EditorOptions, IEditor } from 'vs/workbench/common/editor';
import { EditorInput, EditorOptions, IEditor, GroupIdentifier, IEditorMemento } from 'vs/workbench/common/editor';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IEditorGroup } from 'vs/workbench/services/group/common/editorGroupsService';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { LRUCache } from 'vs/base/common/map';
import URI from 'vs/base/common/uri';
import { once } from 'vs/base/common/event';
import { isEmptyObject } from 'vs/base/common/types';
/**
* The base class of editors in the workbench. Editors register themselves for specific editor inputs.
......@@ -27,6 +32,8 @@ import { IEditorGroup } from 'vs/workbench/services/group/common/editorGroupsSer
*/
export abstract class BaseEditor extends Panel implements IEditor {
private static readonly EDITOR_MEMENTOS: Map<string, EditorMemento<any>> = new Map<string, EditorMemento<any>>();
protected _input: EditorInput;
private _options: EditorOptions;
......@@ -135,6 +142,26 @@ export abstract class BaseEditor extends Panel implements IEditor {
return true;
}
protected getEditorMemento<T>(storageService: IStorageService, editorGroupService: IEditorGroupsService, key: string, limit: number = 10): IEditorMemento<T> {
const mementoKey = `${this.getId()}${key}`;
let editorMemento = BaseEditor.EDITOR_MEMENTOS.get(mementoKey);
if (!editorMemento) {
editorMemento = new EditorMemento(editorGroupService, this.getMemento(storageService), key, limit);
BaseEditor.EDITOR_MEMENTOS.set(mementoKey, editorMemento);
}
return editorMemento;
}
shutdown(): void {
// Save all editor mementos
BaseEditor.EDITOR_MEMENTOS.forEach(editorMemento => editorMemento.shutdown());
super.shutdown();
}
dispose(): void {
this._input = null;
this._options = null;
......@@ -143,3 +170,120 @@ export abstract class BaseEditor extends Panel implements IEditor {
super.dispose();
}
}
interface MapGroupToMemento<T> {
[group: number]: T;
}
export class EditorMemento<T> implements IEditorMemento<T> {
private cache: LRUCache<string, MapGroupToMemento<T>>;
private isShutdown: boolean;
constructor(
private editorGroupService: IEditorGroupsService,
private memento: object,
private key: string,
private limit: number
) { }
saveState(group: IEditorGroup, resource: URI, state: T): void;
saveState(group: IEditorGroup, editor: EditorInput, state: T): void;
saveState(group: IEditorGroup, resourceOrEditor: URI | EditorInput, state: T): void {
const resource = this.doGetResource(resourceOrEditor);
if (!resource || !group) {
return; // we are not in a good state to save any state for a resource
}
const cache = this.doLoad();
let mementoForResource = cache.get(resource.toString());
if (!mementoForResource) {
mementoForResource = Object.create(null) as MapGroupToMemento<T>;
cache.set(resource.toString(), mementoForResource);
}
mementoForResource[group.id] = state;
// Automatically clear when editor input gets disposed if any
if (resourceOrEditor instanceof EditorInput) {
once(resourceOrEditor.onDispose)(() => {
this.clearState(resource);
});
}
}
loadState(group: IEditorGroup, resource: URI): T;
loadState(group: IEditorGroup, editor: EditorInput): T;
loadState(group: IEditorGroup, resourceOrEditor: URI | EditorInput): T {
const resource = this.doGetResource(resourceOrEditor);
if (!resource || !group) {
return void 0; // we are not in a good state to load any state for a resource
}
const cache = this.doLoad();
const mementoForResource = cache.get(resource.toString());
if (mementoForResource) {
return mementoForResource[group.id];
}
return void 0;
}
clearState(resource: URI): void;
clearState(editor: EditorInput): void;
clearState(resourceOrEditor: URI | EditorInput): void {
const resource = this.doGetResource(resourceOrEditor);
if (resource) {
const cache = this.doLoad();
cache.delete(resource.toString());
}
}
private doGetResource(resourceOrEditor: URI | EditorInput): URI {
if (resourceOrEditor instanceof EditorInput) {
return resourceOrEditor.getResource();
}
return resourceOrEditor;
}
private doLoad(): LRUCache<string, MapGroupToMemento<T>> {
if (!this.cache) {
this.cache = new LRUCache<string, MapGroupToMemento<T>>(this.limit);
// Restore from serialized map state
const rawEditorMemento = this.memento[this.key];
if (Array.isArray(rawEditorMemento)) {
this.cache.fromJSON(rawEditorMemento);
}
}
return this.cache;
}
shutdown(): void {
if (this.isShutdown) {
return; // only shutdown once
}
const cache = this.doLoad();
// Remove groups from states that no longer exist
cache.forEach((mapGroupToMemento, resource) => {
Object.keys(mapGroupToMemento).forEach(group => {
const groupId: GroupIdentifier = Number(group);
if (!this.editorGroupService.getGroup(groupId)) {
delete mapGroupToMemento[groupId];
if (isEmptyObject(mapGroupToMemento)) {
cache.delete(resource);
}
}
});
});
this.memento[this.key] = cache.toJSON();
this.isShutdown = true;
}
}
\ No newline at end of file
......@@ -14,7 +14,7 @@ import * as types from 'vs/base/common/types';
import { IDiffEditor } from 'vs/editor/browser/editorBrowser';
import { IDiffEditorOptions, IEditorOptions as ICodeEditorOptions } from 'vs/editor/common/config/editorOptions';
import { BaseTextEditor, IEditorConfiguration } from 'vs/workbench/browser/parts/editor/textEditor';
import { TextEditorOptions, EditorInput, EditorOptions, TEXT_DIFF_EDITOR_ID, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, ITextDiffEditor } from 'vs/workbench/common/editor';
import { TextEditorOptions, EditorInput, EditorOptions, TEXT_DIFF_EDITOR_ID, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, ITextDiffEditor, IEditorMemento } from 'vs/workbench/common/editor';
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { DiffNavigator } from 'vs/editor/browser/widget/diffNavigator';
......@@ -36,6 +36,7 @@ import { once } from 'vs/base/common/event';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { CancellationToken } from 'vs/base/common/cancellation';
import { EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor';
/**
* The text editor that leverages the diff text editor for the editing experience.
......@@ -45,7 +46,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
public static readonly ID = TEXT_DIFF_EDITOR_ID;
private diffNavigator: DiffNavigator;
private diffNavigatorDisposables: IDisposable[];
private diffNavigatorDisposables: IDisposable[] = [];
private nextDiffAction: NavigateAction;
private previousDiffAction: NavigateAction;
private toggleIgnoreTrimWhitespaceAction: ToggleIgnoreTrimWhitespaceAction;
......@@ -63,7 +64,6 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
) {
super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService);
this.diffNavigatorDisposables = [];
this.toUnbind.push(this._actualConfigurationService.onDidChangeConfiguration((e) => {
if (e.affectsConfiguration('diffEditor.ignoreTrimWhitespace')) {
this.updateIgnoreTrimWhitespaceAction();
......@@ -71,8 +71,8 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
}));
}
protected getEditorViewStateStorage(): object {
return Object.create(null); // do not persist in storage as diff editors are never persisted
protected getEditorMemento<T>(storageService: IStorageService, editorGroupService: IEditorGroupsService, key: string, limit: number = 10): IEditorMemento<T> {
return new EditorMemento(editorGroupService, Object.create(null), key, limit); // do not persist in storage as diff editors are never persisted
}
public getTitle(): string {
......
......@@ -12,14 +12,13 @@ import * as types from 'vs/base/common/types';
import * as errors from 'vs/base/common/errors';
import * as DOM from 'vs/base/browser/dom';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { EditorInput, EditorOptions, EditorViewStateMemento, ITextEditor } from 'vs/workbench/common/editor';
import { EditorInput, EditorOptions, IEditorMemento, ITextEditor } from 'vs/workbench/common/editor';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { IEditorViewState, IEditor } from 'vs/editor/common/editorCommon';
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 { Scope } from 'vs/workbench/common/memento';
import { ITextFileService, SaveReason, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
......@@ -44,13 +43,13 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
private _editorContainer: HTMLElement;
private hasPendingConfigurationChange: boolean;
private lastAppliedEditorOptions: IEditorOptions;
private editorViewStateMemento: EditorViewStateMemento<IEditorViewState>;
private editorMemento: IEditorMemento<IEditorViewState>;
constructor(
id: string,
@ITelemetryService telemetryService: ITelemetryService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IStorageService private storageService: IStorageService,
@IStorageService storageService: IStorageService,
@ITextResourceConfigurationService private readonly _configurationService: ITextResourceConfigurationService,
@IThemeService protected themeService: IThemeService,
@ITextFileService private readonly _textFileService: ITextFileService,
......@@ -59,15 +58,11 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
) {
super(id, telemetryService, themeService);
this.editorViewStateMemento = new EditorViewStateMemento<IEditorViewState>(editorGroupService, this.getEditorViewStateStorage(), TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY, 100);
this.editorMemento = this.getEditorMemento<IEditorViewState>(storageService, editorGroupService, TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY, 100);
this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.handleConfigurationChangeEvent(this.configurationService.getValue<IEditorConfiguration>(this.getResource()))));
}
protected getEditorViewStateStorage(): object {
return this.getMemento(this.storageService, Scope.WORKSPACE);
}
protected get instantiationService(): IInstantiationService {
return this._instantiationService;
}
......@@ -237,7 +232,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
return;
}
this.editorViewStateMemento.saveState(this.group, resource, editorViewState);
this.editorMemento.saveState(this.group, resource, editorViewState);
}
protected retrieveTextEditorViewState(resource: URI): IEditorViewState {
......@@ -264,7 +259,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
*/
protected clearTextEditorViewState(resources: URI[]): void {
resources.forEach(resource => {
this.editorViewStateMemento.clearState(resource);
this.editorMemento.clearState(resource);
});
}
......@@ -272,7 +267,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
* Loads the text editor view state for the given resource and returns it.
*/
protected loadTextEditorViewState(resource: URI): IEditorViewState {
return this.editorViewStateMemento.loadState(this.group, resource);
return this.editorMemento.loadState(this.group, resource);
}
private updateEditorConfiguration(configuration = this.configurationService.getValue<IEditorConfiguration>(this.getResource())): void {
......@@ -314,14 +309,6 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
protected abstract getAriaLabel(): string;
protected saveMemento(): void {
// ensure to first save our view state memento
this.editorViewStateMemento.save();
super.saveMemento();
}
public dispose(): void {
this.lastAppliedEditorOptions = void 0;
this.editorControl.dispose();
......
......@@ -17,8 +17,7 @@ import { RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/con
import { Registry } from 'vs/platform/registry/common/platform';
import { ITextModel } from 'vs/editor/common/model';
import { Schemas } from 'vs/base/common/network';
import { LRUCache } from 'vs/base/common/map';
import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/group/common/editorGroupsService';
import { IEditorGroup } from 'vs/workbench/services/group/common/editorGroupsService';
import { ICompositeControl } from 'vs/workbench/common/composite';
import { ActionRunner, IAction } from 'vs/base/common/actions';
......@@ -1019,115 +1018,16 @@ export enum CloseDirection {
RIGHT
}
interface MapGroupToViewStates<T> {
[group: number]: T;
}
export class EditorViewStateMemento<T> {
private cache: LRUCache<string, MapGroupToViewStates<T>>;
constructor(
private editorGroupService: IEditorGroupsService,
private memento: object,
private key: string,
private limit: number = 10
) { }
public saveState(group: IEditorGroup, resource: URI, state: T): void;
public saveState(group: IEditorGroup, editor: EditorInput, state: T): void;
public saveState(group: IEditorGroup, resourceOrEditor: URI | EditorInput, state: T): void {
const resource = this.doGetResource(resourceOrEditor);
if (!resource || !group) {
return; // we are not in a good state to save any viewstate for a resource
}
const cache = this.doLoad();
let viewStates = cache.get(resource.toString());
if (!viewStates) {
viewStates = Object.create(null) as MapGroupToViewStates<T>;
cache.set(resource.toString(), viewStates);
}
viewStates[group.id] = state;
export interface IEditorMemento<T> {
// Automatically clear when editor input gets disposed if any
if (resourceOrEditor instanceof EditorInput) {
once(resourceOrEditor.onDispose)(() => {
this.clearState(resource);
});
}
}
saveState(group: IEditorGroup, resource: URI, state: T): void;
saveState(group: IEditorGroup, editor: EditorInput, state: T): void;
public loadState(group: IEditorGroup, resource: URI): T;
public loadState(group: IEditorGroup, editor: EditorInput): T;
public loadState(group: IEditorGroup, resourceOrEditor: URI | EditorInput): T {
const resource = this.doGetResource(resourceOrEditor);
if (!resource || !group) {
return void 0; // we are not in a good state to load any viewstate for a resource
}
loadState(group: IEditorGroup, resource: URI): T;
loadState(group: IEditorGroup, editor: EditorInput): T;
const cache = this.doLoad();
const viewStates = cache.get(resource.toString());
if (viewStates) {
return viewStates[group.id];
}
return void 0;
}
public clearState(resource: URI): void;
public clearState(editor: EditorInput): void;
public clearState(resourceOrEditor: URI | EditorInput): void {
const resource = this.doGetResource(resourceOrEditor);
if (resource) {
const cache = this.doLoad();
cache.delete(resource.toString());
}
}
private doGetResource(resourceOrEditor: URI | EditorInput): URI {
if (resourceOrEditor instanceof EditorInput) {
return resourceOrEditor.getResource();
}
return resourceOrEditor;
}
private doLoad(): LRUCache<string, MapGroupToViewStates<T>> {
if (!this.cache) {
this.cache = new LRUCache<string, MapGroupToViewStates<T>>(this.limit);
// Restore from serialized map state
const rawViewState = this.memento[this.key];
if (Array.isArray(rawViewState)) {
this.cache.fromJSON(rawViewState);
}
}
return this.cache;
}
public save(): void {
const cache = this.doLoad();
// Remove groups from states that no longer exist
cache.forEach((mapGroupToViewStates, resource) => {
Object.keys(mapGroupToViewStates).forEach(group => {
const groupId: GroupIdentifier = Number(group);
if (!this.editorGroupService.getGroup(groupId)) {
delete mapGroupToViewStates[groupId];
if (types.isEmptyObject(mapGroupToViewStates)) {
cache.delete(resource);
}
}
});
});
this.memento[this.key] = cache.toJSON();
}
clearState(resource: URI): void;
clearState(editor: EditorInput): void;
}
class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry {
......
......@@ -9,7 +9,7 @@ import { localize } from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
import { ITextModel } from 'vs/editor/common/model';
import { empty as EmptyDisposable, IDisposable, dispose, IReference } from 'vs/base/common/lifecycle';
import { EditorOptions, EditorInput, EditorViewStateMemento } from 'vs/workbench/common/editor';
import { EditorOptions, EditorInput, IEditorMemento } from 'vs/workbench/common/editor';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
import { HtmlInput, HtmlInputOptions, areHtmlInputOptionsEqual } from 'vs/workbench/parts/html/common/htmlInput';
......@@ -19,7 +19,6 @@ import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/r
import { Parts, IPartService } from 'vs/workbench/services/part/common/partService';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Scope } from 'vs/workbench/common/memento';
import { Dimension } from 'vs/base/browser/dom';
import { BaseWebviewEditor } from 'vs/workbench/parts/webview/electron-browser/baseWebviewEditor';
import { WebviewElement, WebviewOptions } from 'vs/workbench/parts/webview/electron-browser/webviewElement';
......@@ -49,22 +48,22 @@ export class HtmlPreviewPart extends BaseWebviewEditor {
private _content: HTMLElement;
private _scrollYPercentage: number = 0;
private editorViewStateMemento: EditorViewStateMemento<HtmlPreviewEditorViewState>;
private editorMemento: IEditorMemento<HtmlPreviewEditorViewState>;
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService,
@IContextKeyService contextKeyService: IContextKeyService,
@ITelemetryService readonly telemetryService: ITelemetryService,
@IThemeService readonly themeService: IThemeService,
@IContextKeyService readonly contextKeyService: IContextKeyService,
@IOpenerService private readonly _openerService: IOpenerService,
@IPartService private readonly _partService: IPartService,
@IStorageService readonly _storageService: IStorageService,
@ITextModelService private readonly _textModelResolverService: ITextModelService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IEditorGroupsService editorGroupService: IEditorGroupsService
@IEditorGroupsService readonly editorGroupService: IEditorGroupsService
) {
super(HtmlPreviewPart.ID, telemetryService, themeService, contextKeyService);
this.editorViewStateMemento = new EditorViewStateMemento<HtmlPreviewEditorViewState>(editorGroupService, this.getMemento(_storageService, Scope.WORKSPACE), this.viewStateStorageKey);
this.editorMemento = this.getEditorMemento<HtmlPreviewEditorViewState>(_storageService, editorGroupService, this.viewStateStorageKey);
}
dispose(): void {
......@@ -247,18 +246,10 @@ export class HtmlPreviewPart extends BaseWebviewEditor {
}
private saveHTMLPreviewViewState(input: HtmlInput, editorViewState: HtmlPreviewEditorViewState): void {
this.editorViewStateMemento.saveState(this.group, input, editorViewState);
this.editorMemento.saveState(this.group, input, editorViewState);
}
private loadHTMLPreviewViewState(input: HtmlInput): HtmlPreviewEditorViewState {
return this.editorViewStateMemento.loadState(this.group, input);
}
protected saveMemento(): void {
// ensure to first save our view state memento
this.editorViewStateMemento.save();
super.saveMemento();
return this.editorMemento.loadState(this.group, input);
}
}
......@@ -11,7 +11,7 @@ import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import * as strings from 'vs/base/common/strings';
import URI from 'vs/base/common/uri';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { EditorOptions, EditorViewStateMemento } from 'vs/workbench/common/editor';
import { EditorOptions, IEditorMemento } from 'vs/workbench/common/editor';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { WalkThroughInput } from 'vs/workbench/parts/welcome/walkThrough/node/walkThroughInput';
......@@ -23,7 +23,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { localize } from 'vs/nls';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Scope } from 'vs/workbench/common/memento';
import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { once } from 'vs/base/common/event';
......@@ -65,7 +64,7 @@ export class WalkThroughPart extends BaseEditor {
private scrollbar: DomScrollableElement;
private editorFocus: IContextKey<boolean>;
private size: Dimension;
private editorViewStateMemento: EditorViewStateMemento<IWalkThroughEditorViewState>;
private editorMemento: IEditorMemento<IWalkThroughEditorViewState>;
constructor(
@ITelemetryService telemetryService: ITelemetryService,
......@@ -82,7 +81,7 @@ export class WalkThroughPart extends BaseEditor {
) {
super(WalkThroughPart.ID, telemetryService, themeService);
this.editorFocus = WALK_THROUGH_FOCUS.bindTo(this.contextKeyService);
this.editorViewStateMemento = new EditorViewStateMemento<IWalkThroughEditorViewState>(editorGroupService, this.getMemento(storageService, Scope.WORKSPACE), WALK_THROUGH_EDITOR_VIEW_STATE_PREFERENCE_KEY);
this.editorMemento = this.getEditorMemento<IWalkThroughEditorViewState>(storageService, editorGroupService, WALK_THROUGH_EDITOR_VIEW_STATE_PREFERENCE_KEY);
}
createEditor(container: HTMLElement): void {
......@@ -476,7 +475,7 @@ export class WalkThroughPart extends BaseEditor {
private saveTextEditorViewState(input: WalkThroughInput): void {
const scrollPosition = this.scrollbar.getScrollPosition();
this.editorViewStateMemento.saveState(this.group, input, {
this.editorMemento.saveState(this.group, input, {
viewState: {
scrollTop: scrollPosition.scrollTop,
scrollLeft: scrollPosition.scrollLeft
......@@ -485,7 +484,7 @@ export class WalkThroughPart extends BaseEditor {
}
private loadTextEditorViewState(input: WalkThroughInput) {
const state = this.editorViewStateMemento.loadState(this.group, input);
const state = this.editorMemento.loadState(this.group, input);
if (state) {
this.scrollbar.setScrollPosition(state.viewState);
}
......@@ -505,14 +504,6 @@ export class WalkThroughPart extends BaseEditor {
super.shutdown();
}
protected saveMemento(): void {
// ensure to first save our view state memento
this.editorViewStateMemento.save();
super.saveMemento();
}
dispose(): void {
this.editorFocus.reset();
this.contentDisposables = dispose(this.contentDisposables);
......
......@@ -6,7 +6,7 @@
'use strict';
import * as assert from 'assert';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { BaseEditor, EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor';
import { EditorInput, EditorOptions, IEditorInputFactory, IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
......@@ -14,12 +14,14 @@ import * as Platform from 'vs/platform/registry/common/platform';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { workbenchInstantiationService, TestEditorGroup } from 'vs/workbench/test/workbenchTestServices';
import { workbenchInstantiationService, TestEditorGroup, TestEditorGroupsService } from 'vs/workbench/test/workbenchTestServices';
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
import URI from 'vs/base/common/uri';
import { IEditorRegistry, Extensions, EditorDescriptor } from 'vs/workbench/browser/editor';
import { CancellationToken } from 'vs/base/common/cancellation';
import { TPromise } from 'vs/base/common/winjs.base';
import { IEditorModel } from 'vs/platform/editor/common/editor';
const NullThemeService = new TestThemeService();
......@@ -188,6 +190,116 @@ suite('Workbench base editor', () => {
assert(factory);
});
test('EditorMemento - basics', function () {
const testGroup0 = new TestEditorGroup(0);
const testGroup1 = new TestEditorGroup(1);
const testGroup4 = new TestEditorGroup(4);
const editorGroupService = new TestEditorGroupsService([
testGroup0,
testGroup1,
new TestEditorGroup(2)
]);
interface TestViewState {
line: number;
}
const rawMemento = Object.create(null);
let memento = new EditorMemento<TestViewState>(editorGroupService, rawMemento, 'key', 3);
let res = memento.loadState(testGroup0, URI.file('/A'));
assert.ok(!res);
memento.saveState(testGroup0, URI.file('/A'), { line: 3 });
res = memento.loadState(testGroup0, URI.file('/A'));
assert.ok(res);
assert.equal(res.line, 3);
memento.saveState(testGroup1, URI.file('/A'), { line: 5 });
res = memento.loadState(testGroup1, URI.file('/A'));
assert.ok(res);
assert.equal(res.line, 5);
// Ensure capped at 3 elements
memento.saveState(testGroup0, URI.file('/B'), { line: 1 });
memento.saveState(testGroup0, URI.file('/C'), { line: 1 });
memento.saveState(testGroup0, URI.file('/D'), { line: 1 });
memento.saveState(testGroup0, URI.file('/E'), { line: 1 });
assert.ok(!memento.loadState(testGroup0, URI.file('/A')));
assert.ok(!memento.loadState(testGroup0, URI.file('/B')));
assert.ok(memento.loadState(testGroup0, URI.file('/C')));
assert.ok(memento.loadState(testGroup0, URI.file('/D')));
assert.ok(memento.loadState(testGroup0, URI.file('/E')));
// Save at an unknown group
memento.saveState(testGroup4, URI.file('/E'), { line: 1 });
assert.ok(memento.loadState(testGroup4, URI.file('/E'))); // only gets removed when memento is saved
memento.saveState(testGroup4, URI.file('/C'), { line: 1 });
assert.ok(memento.loadState(testGroup4, URI.file('/C'))); // only gets removed when memento is saved
memento.shutdown();
memento = new EditorMemento(editorGroupService, rawMemento, 'key', 3);
assert.ok(memento.loadState(testGroup0, URI.file('/C')));
assert.ok(memento.loadState(testGroup0, URI.file('/D')));
assert.ok(memento.loadState(testGroup0, URI.file('/E')));
// Check on entries no longer there from invalid groups
assert.ok(!memento.loadState(testGroup4, URI.file('/E')));
assert.ok(!memento.loadState(testGroup4, URI.file('/C')));
memento.clearState(URI.file('/C'));
memento.clearState(URI.file('/E'));
assert.ok(!memento.loadState(testGroup0, URI.file('/C')));
assert.ok(memento.loadState(testGroup0, URI.file('/D')));
assert.ok(!memento.loadState(testGroup0, URI.file('/E')));
});
test('EditoMemento - use with editor input', function () {
const testGroup0 = new TestEditorGroup(0);
interface TestViewState {
line: number;
}
class TestEditorInput extends EditorInput {
constructor(private resource: URI, private id = 'testEditorInput') {
super();
}
public getTypeId() { return 'testEditorInput'; }
public resolve(): TPromise<IEditorModel> { return null; }
public matches(other: TestEditorInput): boolean {
return other && this.id === other.id && other instanceof TestEditorInput;
}
public getResource(): URI {
return this.resource;
}
}
const rawMemento = Object.create(null);
let memento = new EditorMemento<TestViewState>(new TestEditorGroupsService(), rawMemento, 'key', 3);
const testInputA = new TestEditorInput(URI.file('/A'));
let res = memento.loadState(testGroup0, testInputA);
assert.ok(!res);
memento.saveState(testGroup0, testInputA, { line: 3 });
res = memento.loadState(testGroup0, testInputA);
assert.ok(res);
assert.equal(res.line, 3);
// State removed when input gets disposed
testInputA.dispose();
res = memento.loadState(testGroup0, testInputA);
assert.ok(!res);
});
return {
MyEditor: MyEditor,
MyOtherEditor: MyOtherEditor
......
......@@ -7,13 +7,13 @@
import * as assert from 'assert';
import { TPromise } from 'vs/base/common/winjs.base';
import { EditorInput, toResource, EditorViewStateMemento } from 'vs/workbench/common/editor';
import { EditorInput, toResource } from 'vs/workbench/common/editor';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { IEditorModel } from 'vs/platform/editor/common/editor';
import URI from 'vs/base/common/uri';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { workbenchInstantiationService, TestEditorGroupsService, TestEditorGroup } from 'vs/workbench/test/workbenchTestServices';
import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices';
import { Schemas } from 'vs/base/common/network';
class ServiceAccessor {
......@@ -86,114 +86,4 @@ suite('Workbench editor', () => {
assert.equal(toResource(file, { supportSideBySide: true, filter: Schemas.file }).toString(), file.getResource().toString());
assert.equal(toResource(file, { supportSideBySide: true, filter: [Schemas.file, Schemas.untitled] }).toString(), file.getResource().toString());
});
test('EditorViewStateMemento - basics', function () {
const testGroup0 = new TestEditorGroup(0);
const testGroup1 = new TestEditorGroup(1);
const testGroup4 = new TestEditorGroup(4);
const editorGroupService = new TestEditorGroupsService([
testGroup0,
testGroup1,
new TestEditorGroup(2)
]);
interface TestViewState {
line: number;
}
const rawMemento = Object.create(null);
let memento = new EditorViewStateMemento<TestViewState>(editorGroupService, rawMemento, 'key', 3);
let res = memento.loadState(testGroup0, URI.file('/A'));
assert.ok(!res);
memento.saveState(testGroup0, URI.file('/A'), { line: 3 });
res = memento.loadState(testGroup0, URI.file('/A'));
assert.ok(res);
assert.equal(res.line, 3);
memento.saveState(testGroup1, URI.file('/A'), { line: 5 });
res = memento.loadState(testGroup1, URI.file('/A'));
assert.ok(res);
assert.equal(res.line, 5);
// Ensure capped at 3 elements
memento.saveState(testGroup0, URI.file('/B'), { line: 1 });
memento.saveState(testGroup0, URI.file('/C'), { line: 1 });
memento.saveState(testGroup0, URI.file('/D'), { line: 1 });
memento.saveState(testGroup0, URI.file('/E'), { line: 1 });
assert.ok(!memento.loadState(testGroup0, URI.file('/A')));
assert.ok(!memento.loadState(testGroup0, URI.file('/B')));
assert.ok(memento.loadState(testGroup0, URI.file('/C')));
assert.ok(memento.loadState(testGroup0, URI.file('/D')));
assert.ok(memento.loadState(testGroup0, URI.file('/E')));
// Save at an unknown group
memento.saveState(testGroup4, URI.file('/E'), { line: 1 });
assert.ok(memento.loadState(testGroup4, URI.file('/E'))); // only gets removed when memento is saved
memento.saveState(testGroup4, URI.file('/C'), { line: 1 });
assert.ok(memento.loadState(testGroup4, URI.file('/C'))); // only gets removed when memento is saved
memento.save();
memento = new EditorViewStateMemento(editorGroupService, rawMemento, 'key', 3);
assert.ok(memento.loadState(testGroup0, URI.file('/C')));
assert.ok(memento.loadState(testGroup0, URI.file('/D')));
assert.ok(memento.loadState(testGroup0, URI.file('/E')));
// Check on entries no longer there from invalid groups
assert.ok(!memento.loadState(testGroup4, URI.file('/E')));
assert.ok(!memento.loadState(testGroup4, URI.file('/C')));
memento.clearState(URI.file('/C'));
memento.clearState(URI.file('/E'));
assert.ok(!memento.loadState(testGroup0, URI.file('/C')));
assert.ok(memento.loadState(testGroup0, URI.file('/D')));
assert.ok(!memento.loadState(testGroup0, URI.file('/E')));
});
test('EditorViewStateMemento - use with editor input', function () {
const testGroup0 = new TestEditorGroup(0);
interface TestViewState {
line: number;
}
class TestEditorInput extends EditorInput {
constructor(private resource: URI, private id = 'testEditorInput') {
super();
}
public getTypeId() { return 'testEditorInput'; }
public resolve(): TPromise<IEditorModel> { return null; }
public matches(other: TestEditorInput): boolean {
return other && this.id === other.id && other instanceof TestEditorInput;
}
public getResource(): URI {
return this.resource;
}
}
const rawMemento = Object.create(null);
let memento = new EditorViewStateMemento<TestViewState>(new TestEditorGroupsService(), rawMemento, 'key', 3);
const testInputA = new TestEditorInput(URI.file('/A'));
let res = memento.loadState(testGroup0, testInputA);
assert.ok(!res);
memento.saveState(testGroup0, testInputA, { line: 3 });
res = memento.loadState(testGroup0, testInputA);
assert.ok(res);
assert.equal(res.line, 3);
// State removed when input gets disposed
testInputA.dispose();
res = memento.loadState(testGroup0, testInputA);
assert.ok(!res);
});
});
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册