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

debt - introduce a helper to store editor view state with a upper limit

上级 0ab93fc6
......@@ -743,6 +743,24 @@ export class LinkedMap<K, V> {
this._tail = item;
}
}
public toJSON(): [K, V][] {
const data: [K, V][] = [];
this.forEach((value, key) => {
data.push([key, value]);
});
return data;
}
public fromJSON(data: [K, V][]): void {
this.clear();
for (const [key, value] of data) {
this.set(key, value);
}
}
}
export class LRUCache<K, V> extends LinkedMap<K, V> {
......
......@@ -200,6 +200,33 @@ suite('Map', () => {
assert.deepStrictEqual(cache.values(), values);
});
test('LinkedMap - toJSON / fromJSON', () => {
let map = new LinkedMap<string, string>();
map.set('ak', 'av');
map.set('bk', 'bv');
map.set('ck', 'cv');
const json = map.toJSON();
map = new LinkedMap<string, string>();
map.fromJSON(json);
let i = 0;
map.forEach((value, key) => {
if (i === 0) {
assert.equal(key, 'ak');
assert.equal(value, 'av');
} else if (i === 1) {
assert.equal(key, 'bk');
assert.equal(value, 'bv');
} else if (i === 2) {
assert.equal(key, 'ck');
assert.equal(value, 'cv');
}
i++;
});
});
test('PathIterator', function () {
const iter = new PathIterator();
iter.reset('file:///usr/bin/file.txt');
......
......@@ -143,7 +143,7 @@ export class TextDiffEditor extends BaseTextEditor {
this.diffNavigatorDisposables = dispose(this.diffNavigatorDisposables);
// Remember view settings if input changes
this.saveTextDiffEditorViewStateForInput(this.input);
this.saveTextDiffEditorViewState(this.input);
// Set input and resolve
return super.setInput(input, options).then(() => {
......@@ -172,7 +172,7 @@ export class TextDiffEditor extends BaseTextEditor {
// Otherwise restore View State
let hasPreviousViewState = false;
if (!optionsGotApplied) {
hasPreviousViewState = this.restoreViewState(input);
hasPreviousViewState = this.restoreTextDiffEditorViewState(input);
}
this.diffNavigator = new DiffNavigator(diffEditor, {
......@@ -199,7 +199,7 @@ export class TextDiffEditor extends BaseTextEditor {
});
}
private restoreViewState(input: EditorInput): boolean {
private restoreTextDiffEditorViewState(input: EditorInput): boolean {
if (input instanceof DiffEditorInput) {
const resource = this.toDiffEditorViewStateResource(input);
if (resource) {
......@@ -306,7 +306,7 @@ export class TextDiffEditor extends BaseTextEditor {
this.diffNavigatorDisposables = dispose(this.diffNavigatorDisposables);
// Keep editor view state in settings to restore when coming back
this.saveTextDiffEditorViewStateForInput(this.input);
this.saveTextDiffEditorViewState(this.input);
// Clear Model
this.getControl().setModel(null);
......@@ -335,7 +335,7 @@ export class TextDiffEditor extends BaseTextEditor {
return super.loadTextEditorViewState(resource) as IDiffEditorViewState; // overridden for text diff editor support
}
private saveTextDiffEditorViewStateForInput(input: EditorInput): void {
private saveTextDiffEditorViewState(input: EditorInput): void {
if (!(input instanceof DiffEditorInput)) {
return; // only supported for diff editor inputs
}
......
......@@ -13,7 +13,7 @@ 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 { CodeEditor } from 'vs/editor/browser/codeEditor';
import { EditorInput, EditorOptions } from 'vs/workbench/common/editor';
import { EditorInput, EditorOptions, EditorViewStateMemento } from 'vs/workbench/common/editor';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { IEditorViewState, IEditor } from 'vs/editor/common/editorCommon';
import { Position } from 'vs/platform/editor/common/editor';
......@@ -45,12 +45,13 @@ export abstract class BaseTextEditor extends BaseEditor {
private _editorContainer: HTMLElement;
private hasPendingConfigurationChange: boolean;
private lastAppliedEditorOptions: IEditorOptions;
private editorViewStateMemento: EditorViewStateMemento<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,
......@@ -58,6 +59,8 @@ export abstract class BaseTextEditor extends BaseEditor {
) {
super(id, telemetryService, themeService);
this.editorViewStateMemento = new EditorViewStateMemento<IEditorViewState>(this.getMemento(storageService, Scope.WORKSPACE), TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY, 100);
this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.handleConfigurationChangeEvent(this.configurationService.getValue<IEditorConfiguration>(this.getResource()))));
}
......@@ -237,23 +240,7 @@ export abstract class BaseTextEditor extends BaseEditor {
return;
}
const memento = this.getMemento(this.storageService, Scope.WORKSPACE);
let textEditorViewStateMemento: { [key: string]: { [position: number]: IEditorViewState } } = memento[TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY];
if (!textEditorViewStateMemento) {
textEditorViewStateMemento = Object.create(null);
memento[TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY] = textEditorViewStateMemento;
}
let lastKnownViewState = textEditorViewStateMemento[resource.toString()];
if (!lastKnownViewState) {
lastKnownViewState = Object.create(null);
textEditorViewStateMemento[resource.toString()] = lastKnownViewState;
}
if (typeof this.position === 'number') {
lastKnownViewState[this.position] = editorViewState;
}
this.editorViewStateMemento.saveState(resource, this.position, editorViewState);
}
protected retrieveTextEditorViewState(resource: URI): IEditorViewState {
......@@ -283,27 +270,16 @@ export abstract class BaseTextEditor extends BaseEditor {
* Clears the text editor view state for the given resources.
*/
protected clearTextEditorViewState(resources: URI[]): void {
const memento = this.getMemento(this.storageService, Scope.WORKSPACE);
const textEditorViewStateMemento: { [key: string]: { [position: number]: IEditorViewState } } = memento[TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY];
if (textEditorViewStateMemento) {
resources.forEach(resource => delete textEditorViewStateMemento[resource.toString()]);
}
resources.forEach(resource => {
this.editorViewStateMemento.clearState(resource);
});
}
/**
* Loads the text editor view state for the given resource and returns it.
*/
protected loadTextEditorViewState(resource: URI): IEditorViewState {
const memento = this.getMemento(this.storageService, Scope.WORKSPACE);
const textEditorViewStateMemento: { [key: string]: { [position: number]: IEditorViewState } } = memento[TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY];
if (textEditorViewStateMemento) {
const viewState = textEditorViewStateMemento[resource.toString()];
if (viewState) {
return viewState[this.position];
}
}
return null;
return this.editorViewStateMemento.loadState(resource, this.position);
}
private updateEditorConfiguration(configuration = this.configurationService.getValue<IEditorConfiguration>(this.getResource())): void {
......@@ -345,6 +321,14 @@ export abstract class BaseTextEditor extends BaseEditor {
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();
......
......@@ -67,7 +67,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
}
// Remember view settings if input changes
this.saveTextEditorViewStateForInput(this.input);
this.saveTextResourceEditorViewState(this.input);
// Set input and resolve
return super.setInput(input, options).then(() => {
......@@ -97,7 +97,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
// Otherwise restore View State
if (!optionsGotApplied) {
this.restoreViewState(input);
this.restoreTextResourceEditorViewState(input);
}
return void 0;
......@@ -105,7 +105,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
});
}
private restoreViewState(input: EditorInput) {
private restoreTextResourceEditorViewState(input: EditorInput) {
if (input instanceof UntitledEditorInput || input instanceof ResourceEditorInput) {
const viewState = this.loadTextEditorViewState(input.getResource());
if (viewState) {
......@@ -153,7 +153,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
public clearInput(): void {
// Keep editor view state in settings to restore when coming back
this.saveTextEditorViewStateForInput(this.input);
this.saveTextResourceEditorViewState(this.input);
// Clear Model
this.getControl().setModel(null);
......@@ -165,14 +165,14 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
// Save View State (only for untitled)
if (this.input instanceof UntitledEditorInput) {
this.saveTextEditorViewStateForInput(this.input);
this.saveTextResourceEditorViewState(this.input);
}
// Call Super
super.shutdown();
}
protected saveTextEditorViewStateForInput(input: EditorInput): void {
private saveTextResourceEditorViewState(input: EditorInput): void {
if (!(input instanceof UntitledEditorInput) && !(input instanceof ResourceEditorInput)) {
return; // only enabled for untitled and resource inputs
}
......
......@@ -17,6 +17,7 @@ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
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';
export const TextCompareEditorVisible = new RawContextKey<boolean>('textCompareEditorVisible', false);
......@@ -908,6 +909,114 @@ export function toResource(editor: IEditorInput, options?: IResourceOptions): UR
return null;
}
export interface IEditorViewStates<T> {
[Position.ONE]?: T;
[Position.TWO]?: T;
[Position.THREE]?: T;
}
export class EditorViewStateMemento<T> {
private cache: LRUCache<string, IEditorViewStates<T>>;
constructor(private memento: object, private key: string, private limit: number = 10) { }
public saveState(resource: URI, position: Position, state: T): void;
public saveState(editor: EditorInput, position: Position, state: T): void;
public saveState(resourceOrEditor: URI | EditorInput, position: Position, state: T): void {
if (typeof position !== 'number') {
return; // we need a position at least
}
const resource = this.doGetResource(resourceOrEditor);
if (resource) {
const cache = this.doLoad();
let viewStates = cache.get(resource.toString());
if (!viewStates) {
viewStates = Object.create(null) as IEditorViewStates<T>;
cache.set(resource.toString(), viewStates);
}
viewStates[position] = state;
// Automatically clear when editor input gets disposed if any
if (resourceOrEditor instanceof EditorInput) {
once(resourceOrEditor.onDispose)(() => {
this.clearState(resource);
});
}
}
}
public loadState(resource: URI, position: Position): T;
public loadState(editor: EditorInput, position: Position): T;
public loadState(resourceOrEditor: URI | EditorInput, position: Position): T {
if (typeof position !== 'number') {
return void 0; // we need a position at least
}
const resource = this.doGetResource(resourceOrEditor);
if (resource) {
const cache = this.doLoad();
const viewStates = cache.get(resource.toString());
if (viewStates) {
return viewStates[position];
}
}
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, IEditorViewStates<T>> {
if (!this.cache) {
this.cache = new LRUCache<string, T>(this.limit);
// Restore from serialized map state
const rawViewState = this.memento[this.key];
if (Array.isArray(rawViewState)) {
this.cache.fromJSON(rawViewState);
}
// Migration from old object state
else if (rawViewState) {
const keys = Object.keys(rawViewState);
keys.forEach((key, index) => {
if (index < this.limit) {
this.cache.set(key, rawViewState[key]);
}
});
}
}
return this.cache;
}
public save(): void {
const cache = this.doLoad();
this.memento[this.key] = cache.toJSON();
}
}
class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry {
private instantiationService: IInstantiationService;
private fileInputFactory: IFileInputFactory;
......
......@@ -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 } from 'vs/workbench/common/editor';
import { EditorOptions, EditorInput, EditorViewStateMemento } from 'vs/workbench/common/editor';
import { Position } from 'vs/platform/editor/common/editor';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
......@@ -22,7 +22,6 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import URI from 'vs/base/common/uri';
import { Scope } from 'vs/workbench/common/memento';
import { Dimension } from 'vs/base/browser/dom';
import { BaseWebviewEditor } from 'vs/workbench/parts/webview/electron-browser/baseWebviewEditor';
......@@ -50,6 +49,8 @@ export class HtmlPreviewPart extends BaseWebviewEditor {
private _content: HTMLElement;
private _scrollYPercentage: number = 0;
private editorViewStateMemento: EditorViewStateMemento<HtmlPreviewEditorViewState>;
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService,
......@@ -58,10 +59,12 @@ export class HtmlPreviewPart extends BaseWebviewEditor {
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
@IOpenerService private readonly _openerService: IOpenerService,
@IPartService private readonly _partService: IPartService,
@IStorageService private readonly _storageService: IStorageService,
@IStorageService readonly _storageService: IStorageService,
@ITextModelService private readonly _textModelResolverService: ITextModelService
) {
super(HtmlPreviewPart.ID, telemetryService, themeService, contextKeyService);
this.editorViewStateMemento = new EditorViewStateMemento<HtmlPreviewEditorViewState>(this.getMemento(_storageService, Scope.WORKSPACE), this.viewStateStorageKey);
}
dispose(): void {
......@@ -105,7 +108,7 @@ export class HtmlPreviewPart extends BaseWebviewEditor {
this._webview.mountTo(this._content);
if (this.input && this.input instanceof HtmlInput) {
const state = this.loadViewState(this.input.getResource());
const state = this.loadHTMLPreviewViewState(this.input);
this._scrollYPercentage = state ? state.scrollYPercentage : 0;
this.webview.initialScrollProgress = this._scrollYPercentage;
......@@ -167,7 +170,7 @@ export class HtmlPreviewPart extends BaseWebviewEditor {
public clearInput(): void {
if (this.input instanceof HtmlInput) {
this.saveViewState(this.input.getResource(), {
this.saveHTMLPreviewViewState(this.input, {
scrollYPercentage: this._scrollYPercentage
});
}
......@@ -178,7 +181,7 @@ export class HtmlPreviewPart extends BaseWebviewEditor {
public shutdown(): void {
if (this.input instanceof HtmlInput) {
this.saveViewState(this.input.getResource(), {
this.saveHTMLPreviewViewState(this.input, {
scrollYPercentage: this._scrollYPercentage
});
}
......@@ -199,7 +202,7 @@ export class HtmlPreviewPart extends BaseWebviewEditor {
if (this.input instanceof HtmlInput) {
oldOptions = this.input.options;
this.saveViewState(this.input.getResource(), {
this.saveHTMLPreviewViewState(this.input, {
scrollYPercentage: this._scrollYPercentage
});
}
......@@ -236,7 +239,7 @@ export class HtmlPreviewPart extends BaseWebviewEditor {
this.webview.contents = this.model.getLinesContent().join('\n');
}
});
const state = this.loadViewState(resourceUri);
const state = this.loadHTMLPreviewViewState(input);
this._scrollYPercentage = state ? state.scrollYPercentage : 0;
this.webview.baseUrl = resourceUri.toString(true);
this.webview.options = input.options;
......@@ -252,34 +255,19 @@ export class HtmlPreviewPart extends BaseWebviewEditor {
return this.getId() + '.editorViewState';
}
protected saveViewState(resource: URI | string, editorViewState: HtmlPreviewEditorViewState): void {
const memento = this.getMemento(this._storageService, Scope.WORKSPACE);
let editorViewStateMemento: { [key: string]: { [position: number]: HtmlPreviewEditorViewState } } = memento[this.viewStateStorageKey];
if (!editorViewStateMemento) {
editorViewStateMemento = Object.create(null);
memento[this.viewStateStorageKey] = editorViewStateMemento;
}
let fileViewState = editorViewStateMemento[resource.toString()];
if (!fileViewState) {
fileViewState = Object.create(null);
editorViewStateMemento[resource.toString()] = fileViewState;
}
private saveHTMLPreviewViewState(input: HtmlInput, editorViewState: HtmlPreviewEditorViewState): void {
this.editorViewStateMemento.saveState(input, this.position, editorViewState);
}
if (typeof this.position === 'number') {
fileViewState[this.position] = editorViewState;
}
private loadHTMLPreviewViewState(input: HtmlInput): HtmlPreviewEditorViewState {
return this.editorViewStateMemento.loadState(input, this.position);
}
protected loadViewState(resource: URI | string): HtmlPreviewEditorViewState | null {
const memento = this.getMemento(this._storageService, Scope.WORKSPACE);
const editorViewStateMemento: { [key: string]: { [position: number]: HtmlPreviewEditorViewState } } = memento[this.viewStateStorageKey];
if (editorViewStateMemento) {
const fileViewState = editorViewStateMemento[resource.toString()];
if (fileViewState) {
return fileViewState[this.position];
}
}
return null;
protected saveMemento(): void {
// ensure to first save our view state memento
this.editorViewStateMemento.save();
super.saveMemento();
}
}
......@@ -12,7 +12,7 @@ import * as strings from 'vs/base/common/strings';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { EditorOptions } from 'vs/workbench/common/editor';
import { EditorOptions, EditorViewStateMemento } 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';
......@@ -55,12 +55,6 @@ interface IWalkThroughEditorViewState {
viewState: IViewState;
}
interface IWalkThroughEditorViewStates {
0?: IWalkThroughEditorViewState;
1?: IWalkThroughEditorViewState;
2?: IWalkThroughEditorViewState;
}
class WalkThroughCodeEditor extends CodeEditor {
constructor(
......@@ -91,6 +85,7 @@ export class WalkThroughPart extends BaseEditor {
private scrollbar: DomScrollableElement;
private editorFocus: IContextKey<boolean>;
private size: Dimension;
private editorViewStateMemento: EditorViewStateMemento<IWalkThroughEditorViewState>;
constructor(
@ITelemetryService telemetryService: ITelemetryService,
......@@ -99,13 +94,14 @@ export class WalkThroughPart extends BaseEditor {
@IInstantiationService private instantiationService: IInstantiationService,
@IOpenerService private openerService: IOpenerService,
@IKeybindingService private keybindingService: IKeybindingService,
@IStorageService private storageService: IStorageService,
@IStorageService storageService: IStorageService,
@IContextKeyService private contextKeyService: IContextKeyService,
@IConfigurationService private configurationService: IConfigurationService,
@INotificationService private notificationService: INotificationService
) {
super(WalkThroughPart.ID, telemetryService, themeService);
this.editorFocus = WALK_THROUGH_FOCUS.bindTo(this.contextKeyService);
this.editorViewStateMemento = new EditorViewStateMemento<IWalkThroughEditorViewState>(this.getMemento(storageService, Scope.WORKSPACE), WALK_THROUGH_EDITOR_VIEW_STATE_PREFERENCE_KEY);
}
createEditor(container: HTMLElement): void {
......@@ -279,7 +275,7 @@ export class WalkThroughPart extends BaseEditor {
}
if (this.input instanceof WalkThroughInput) {
this.saveTextEditorViewState(this.input.getResource());
this.saveTextEditorViewState(this.input);
}
this.contentDisposables = dispose(this.contentDisposables);
......@@ -300,7 +296,7 @@ export class WalkThroughPart extends BaseEditor {
input.onReady(this.content.firstElementChild as HTMLElement);
}
this.scrollbar.scanDomNode();
this.loadTextEditorViewState(input.getResource());
this.loadTextEditorViewState(input);
this.updatedScrollPosition();
return;
}
......@@ -430,7 +426,7 @@ export class WalkThroughPart extends BaseEditor {
input.onReady(innerContent);
}
this.scrollbar.scanDomNode();
this.loadTextEditorViewState(input.getResource());
this.loadTextEditorViewState(input);
this.updatedScrollPosition();
});
}
......@@ -494,61 +490,46 @@ export class WalkThroughPart extends BaseEditor {
});
}
private saveTextEditorViewState(resource: URI): void {
const memento = this.getMemento(this.storageService, Scope.WORKSPACE);
let editorViewStateMemento: { [key: string]: { [position: number]: IWalkThroughEditorViewState } } = memento[WALK_THROUGH_EDITOR_VIEW_STATE_PREFERENCE_KEY];
if (!editorViewStateMemento) {
editorViewStateMemento = Object.create(null);
memento[WALK_THROUGH_EDITOR_VIEW_STATE_PREFERENCE_KEY] = editorViewStateMemento;
}
private saveTextEditorViewState(input: WalkThroughInput): void {
const scrollPosition = this.scrollbar.getScrollPosition();
const editorViewState: IWalkThroughEditorViewState = {
this.editorViewStateMemento.saveState(input, this.position, {
viewState: {
scrollTop: scrollPosition.scrollTop,
scrollLeft: scrollPosition.scrollLeft
}
};
let fileViewState = editorViewStateMemento[resource.toString()];
if (!fileViewState) {
fileViewState = Object.create(null);
editorViewStateMemento[resource.toString()] = fileViewState;
}
if (typeof this.position === 'number') {
fileViewState[this.position] = editorViewState;
}
});
}
private loadTextEditorViewState(resource: URI) {
const memento = this.getMemento(this.storageService, Scope.WORKSPACE);
const editorViewStateMemento: { [key: string]: IWalkThroughEditorViewStates } = memento[WALK_THROUGH_EDITOR_VIEW_STATE_PREFERENCE_KEY];
if (editorViewStateMemento) {
const fileViewState = editorViewStateMemento[resource.toString()];
if (fileViewState) {
const state = fileViewState[this.position];
if (state) {
this.scrollbar.setScrollPosition(state.viewState);
}
}
private loadTextEditorViewState(input: WalkThroughInput) {
const state = this.editorViewStateMemento.loadState(input, this.position);
if (state) {
this.scrollbar.setScrollPosition(state.viewState);
}
}
public clearInput(): void {
if (this.input instanceof WalkThroughInput) {
this.saveTextEditorViewState(this.input.getResource());
this.saveTextEditorViewState(this.input);
}
super.clearInput();
}
public shutdown(): void {
if (this.input instanceof WalkThroughInput) {
this.saveTextEditorViewState(this.input.getResource());
this.saveTextEditorViewState(this.input);
}
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);
......
......@@ -7,9 +7,9 @@
import * as assert from 'assert';
import { TPromise } from 'vs/base/common/winjs.base';
import { EditorInput, toResource } from 'vs/workbench/common/editor';
import { EditorInput, toResource, EditorViewStateMemento } from 'vs/workbench/common/editor';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { IEditorModel } from 'vs/platform/editor/common/editor';
import { IEditorModel, Position } 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';
......@@ -86,4 +86,129 @@ 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 () {
interface TestViewState {
line: number;
}
const rawMemento = Object.create(null);
let memento = new EditorViewStateMemento<TestViewState>(rawMemento, 'key', 3);
let res = memento.loadState(URI.file('/A'), Position.ONE);
assert.ok(!res);
memento.saveState(URI.file('/A'), Position.ONE, { line: 3 });
res = memento.loadState(URI.file('/A'), Position.ONE);
assert.ok(res);
assert.equal(res.line, 3);
memento.saveState(URI.file('/A'), Position.TWO, { line: 5 });
res = memento.loadState(URI.file('/A'), Position.TWO);
assert.ok(res);
assert.equal(res.line, 5);
// Ensure capped at 3 elements
memento.saveState(URI.file('/B'), Position.ONE, { line: 1 });
memento.saveState(URI.file('/C'), Position.ONE, { line: 1 });
memento.saveState(URI.file('/D'), Position.ONE, { line: 1 });
memento.saveState(URI.file('/E'), Position.ONE, { line: 1 });
assert.ok(!memento.loadState(URI.file('/A'), Position.ONE));
assert.ok(!memento.loadState(URI.file('/B'), Position.ONE));
assert.ok(memento.loadState(URI.file('/C'), Position.ONE));
assert.ok(memento.loadState(URI.file('/D'), Position.ONE));
assert.ok(memento.loadState(URI.file('/E'), Position.ONE));
memento.save();
memento = new EditorViewStateMemento(rawMemento, 'key', 3);
assert.ok(memento.loadState(URI.file('/C'), Position.ONE));
assert.ok(memento.loadState(URI.file('/D'), Position.ONE));
assert.ok(memento.loadState(URI.file('/E'), Position.ONE));
memento.clearState(URI.file('/C'));
memento.clearState(URI.file('/E'));
assert.ok(!memento.loadState(URI.file('/C'), Position.ONE));
assert.ok(memento.loadState(URI.file('/D'), Position.ONE));
assert.ok(!memento.loadState(URI.file('/E'), Position.ONE));
});
test('EditorViewStateMemento - use with editor input', function () {
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>(rawMemento, 'key', 3);
const testInputA = new TestEditorInput(URI.file('/A'));
let res = memento.loadState(testInputA, Position.ONE);
assert.ok(!res);
memento.saveState(testInputA, Position.ONE, { line: 3 });
res = memento.loadState(testInputA, Position.ONE);
assert.ok(res);
assert.equal(res.line, 3);
// State removed when input gets disposed
testInputA.dispose();
res = memento.loadState(testInputA, Position.ONE);
assert.ok(!res);
});
test('EditorViewStateMemento - migration', function () {
interface TestViewState {
line: number;
}
const rawMemento = {
'key': {
[URI.file('/A').toString()]: {
0: {
line: 5
}
},
[URI.file('/B').toString()]: {
0: {
line: 1
},
1: {
line: 2
}
}
}
};
let memento = new EditorViewStateMemento<TestViewState>(rawMemento, 'key', 3);
let res = memento.loadState(URI.file('/A'), Position.ONE);
assert.ok(res);
assert.equal(res.line, 5);
res = memento.loadState(URI.file('/B'), Position.ONE);
assert.ok(res);
assert.equal(res.line, 1);
res = memento.loadState(URI.file('/B'), Position.TWO);
assert.ok(res);
assert.equal(res.line, 2);
});
});
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册