mirror of
https://github.com/Microsoft/vscode
synced 2024-09-19 02:26:04 +00:00
editor - introduce and use editor memento
This commit is contained in:
parent
e8fc894322
commit
32202834a7
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 interface IEditorMemento<T> {
|
||||
|
||||
export class EditorViewStateMemento<T> {
|
||||
private cache: LRUCache<string, MapGroupToViewStates<T>>;
|
||||
saveState(group: IEditorGroup, resource: URI, state: T): void;
|
||||
saveState(group: IEditorGroup, editor: EditorInput, state: T): void;
|
||||
|
||||
constructor(
|
||||
private editorGroupService: IEditorGroupsService,
|
||||
private memento: object,
|
||||
private key: string,
|
||||
private limit: number = 10
|
||||
) { }
|
||||
loadState(group: IEditorGroup, resource: URI): T;
|
||||
loadState(group: IEditorGroup, editor: EditorInput): T;
|
||||
|
||||
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;
|
||||
|
||||
// Automatically clear when editor input gets disposed if any
|
||||
if (resourceOrEditor instanceof EditorInput) {
|
||||
once(resourceOrEditor.onDispose)(() => {
|
||||
this.clearState(resource);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue