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

dispose inputs when closing them

上级 1d451bc0
......@@ -422,7 +422,7 @@ export class CloseEditorAction extends Action {
// Get Top Editor at Position
let visibleEditors = this.editorService.getVisibleEditors();
if (visibleEditors[position]) {
input = visibleEditors[position].input;
input = <EditorInput>visibleEditors[position].input;
}
}
......@@ -555,7 +555,7 @@ export class CloseOtherEditorsInGroupAction extends Action {
const active = this.editorService.getActiveEditor();
if (active) {
position = typeof position === 'number' ? position : active.position;
input = input ? input : active.input;
input = input ? input : <EditorInput>active.input;
}
if (typeof position === 'number' && input) {
......
......@@ -38,7 +38,7 @@ import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollect
import {IMessageService, IMessageWithAction, Severity} from 'vs/platform/message/common/message';
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {IProgressService} from 'vs/platform/progress/common/progress';
import {EditorStacksModel, EditorGroup} from 'vs/workbench/common/editor/editorStacksModel';
import {EditorStacksModel, EditorGroup, IEditorIdentifier} from 'vs/workbench/common/editor/editorStacksModel';
class ProgressMonitor {
......@@ -72,11 +72,10 @@ export class EditorPart extends Part implements IEditorPart {
private dimension: Dimension;
private sideBySideControl: ISideBySideEditorControl;
private memento: any;
private stacksModel: EditorStacksModel;
private stacks: EditorStacksModel;
// The following data structures are partitioned into array of Position as provided by Services.POSITION array
private visibleInputs: EditorInput[];
private visibleInputListeners: Function[];
private visibleEditors: BaseEditor[];
private visibleEditorListeners: Function[][];
private instantiatedEditors: BaseEditor[][];
......@@ -85,7 +84,7 @@ export class EditorPart extends Part implements IEditorPart {
private mapEditorCreationPromiseToEditor: { [editorId: string]: TPromise<BaseEditor>; }[];
private editorOpenToken: number[];
private editorSetInputErrorCounter: number[];
private pendingEditorInputsToClose: { input: EditorInput; position: Position }[];
private pendingEditorInputsToClose: IEditorIdentifier[];
private pendingEditorInputCloseTimeout: number;
constructor(
......@@ -100,7 +99,6 @@ export class EditorPart extends Part implements IEditorPart {
super(id);
this.visibleInputs = [];
this.visibleInputListeners = [];
this.visibleEditors = [];
this.editorOpenToken = arrays.fill(POSITIONS.length, () => 0);
......@@ -116,13 +114,16 @@ export class EditorPart extends Part implements IEditorPart {
this.pendingEditorInputsToClose = [];
this.pendingEditorInputCloseTimeout = null;
this.stacksModel = this.instantiationService.createInstance(EditorStacksModel);
this.stacks = this.instantiationService.createInstance(EditorStacksModel);
this.registerListeners();
}
private registerListeners(): void {
this.toUnbind.push(this.eventService.addListener(WorkbenchEventType.EDITOR_INPUT_STATE_CHANGED, (event: EditorInputEvent) => this.onEditorInputStateChanged(event)));
const unbind = this.stacks.onEditorDisposed(editor => this.onEditorDisposed(editor));
this.toUnbind.push(() => unbind.dispose());
}
private onEditorInputStateChanged(event: EditorInputEvent): void {
......@@ -131,6 +132,11 @@ export class EditorPart extends Part implements IEditorPart {
}
}
private onEditorDisposed(identifier: IEditorIdentifier): void {
this.pendingEditorInputsToClose.push(identifier);
this.startDelayedCloseEditorsFromInputDispose();
}
public openEditor(input: EditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise<BaseEditor>;
public openEditor(input: EditorInput, options?: EditorOptions, position?: Position, widthRatios?: number[]): TPromise<BaseEditor>;
public openEditor(input: EditorInput, options?: EditorOptions, arg3?: any, widthRatios?: number[]): TPromise<BaseEditor> {
......@@ -162,12 +168,6 @@ export class EditorPart extends Part implements IEditorPart {
// Remember as visible input for this position
this.visibleInputs[position] = input;
// Dispose previous input listener if any
if (this.visibleInputListeners[position]) {
this.visibleInputListeners[position]();
this.visibleInputListeners[position] = null;
}
// Open: input is provided
return this.doOpenEditor(input, options, position, widthRatios);
}
......@@ -190,18 +190,6 @@ export class EditorPart extends Part implements IEditorPart {
options = this.findSideOptions(input, options, position);
}
// Close editor when input provided and input gets disposed
this.visibleInputListeners[position] = input.addListener(EventType.DISPOSE, () => {
// Keep the inputs to close. We use this to support multiple inputs closing
// right after each other and this helps avoid layout issues with the delayed
// timeout based closing below
if (input === this.visibleInputs[position]) {
this.pendingEditorInputsToClose.push({ input, position });
this.startDelayedCloseEditorsFromInputDispose();
}
});
// Progress Monitor & Ref Counting
this.editorOpenToken[position]++;
const editorOpenToken = this.editorOpenToken[position];
......@@ -523,12 +511,6 @@ export class EditorPart extends Part implements IEditorPart {
// Update visible inputs for position
this.visibleInputs[position] = null;
// Dispose previous input listener if any
if (this.visibleInputListeners[position]) {
this.visibleInputListeners[position]();
this.visibleInputListeners[position] = null;
}
// Reset counter
this.editorSetInputErrorCounter[position] = 0;
......@@ -564,7 +546,7 @@ export class EditorPart extends Part implements IEditorPart {
// Update stacks model
const group = this.groupAt(position);
this.modifyGroups(() => this.stacksModel.closeGroup(group));
this.modifyGroups(() => this.stacks.closeGroup(group));
// Emit Input-Changed Event
this.emit(WorkbenchEventType.EDITOR_INPUT_CHANGED, new EditorEvent(null, null, null, null, position));
......@@ -712,7 +694,7 @@ export class EditorPart extends Part implements IEditorPart {
}
public getStacksModel(): EditorStacksModel {
return this.stacksModel;
return this.stacks;
}
public getActiveEditorInput(): EditorInput {
......@@ -743,14 +725,13 @@ export class EditorPart extends Part implements IEditorPart {
}
// Update stacks model
this.modifyGroups(() => this.stacksModel.moveGroup(this.groupAt(from), to));
this.modifyGroups(() => this.stacks.moveGroup(this.groupAt(from), to));
// Move widgets
this.sideBySideControl.move(from, to);
// Move data structures
arrays.move(this.visibleInputs, from, to);
arrays.move(this.visibleInputListeners, from, to);
arrays.move(this.visibleEditors, from, to);
arrays.move(this.visibleEditorListeners, from, to);
arrays.move(this.editorOpenToken, from, to);
......@@ -843,7 +824,7 @@ export class EditorPart extends Part implements IEditorPart {
// Update stacks model
let activePosition = this.sideBySideControl.getActivePosition();
if (typeof activePosition === 'number') {
this.stacksModel.setActive(this.groupAt(activePosition));
this.stacks.setActive(this.groupAt(activePosition));
}
// Emit as editor input change event so that clients get aware of new active editor
......@@ -873,7 +854,7 @@ export class EditorPart extends Part implements IEditorPart {
}
public restoreEditors(): TPromise<BaseEditor[]> {
const editors = this.stacksModel.groups.map((group, index) => {
const editors = this.stacks.groups.map((group, index) => {
return {
input: group.activeEditor,
position: index
......@@ -888,8 +869,8 @@ export class EditorPart extends Part implements IEditorPart {
let widthRatios = editorState.widthRatio;
let activePosition: Position;
if (this.stacksModel.groups.length) {
activePosition = this.stacksModel.positionOfGroup(this.stacksModel.activeGroup);
if (this.stacks.groups.length) {
activePosition = this.stacks.positionOfGroup(this.stacks.activeGroup);
}
return this.doOpenEditors(editors, activePosition, widthRatios);
......@@ -960,7 +941,7 @@ export class EditorPart extends Part implements IEditorPart {
}
public groupAt(position: Position): EditorGroup {
return this.stacksModel.groups[position];
return this.stacks.groups[position];
}
public activateGroup(position: Position): void {
......@@ -968,7 +949,7 @@ export class EditorPart extends Part implements IEditorPart {
if (editor) {
// Update stacks model
this.stacksModel.setActive(this.groupAt(position));
this.stacks.setActive(this.groupAt(position));
// Update UI
this.sideBySideControl.setActive(editor);
......@@ -1105,16 +1086,6 @@ export class EditorPart extends Part implements IEditorPart {
}
}
// Input listeners
for (let i = 0; i < this.visibleInputListeners.length; i++) {
let listener = this.visibleInputListeners[i];
if (listener) {
listener();
}
this.visibleInputListeners = [];
}
// Pass to active editors
this.visibleEditors.forEach((editor) => {
if (editor) {
......@@ -1245,11 +1216,27 @@ export class EditorPart extends Part implements IEditorPart {
if (this.pendingEditorInputCloseTimeout === null) {
this.pendingEditorInputCloseTimeout = setTimeout(() => {
// Close all
TPromise.join(this.pendingEditorInputsToClose
.sort((c1, c2) => c2.position - c1.position) // reduce layout work by starting right first
.map(c => this.closeEditor(c.position, c.input))) // close input at position
.done(null, errors.onUnexpectedError);
// Split between active and inactive editors
const activeEditors: IEditorIdentifier[] = [];
const inactiveEditors: IEditorIdentifier[] = [];
this.pendingEditorInputsToClose.forEach(identifier => {
if (identifier.group.isActive(identifier.editor)) {
activeEditors.push(identifier);
} else {
inactiveEditors.push(identifier);
}
});
// Close all inactive first
TPromise.join(inactiveEditors.map(inactive => this.closeEditor(this.stacks.positionOfGroup(inactive.group), inactive.editor))).done(() => {
// Close active ones second
TPromise.join(activeEditors
.sort((a1, a2) => this.stacks.positionOfGroup(a2.group) - this.stacks.positionOfGroup(a1.group)) // reduce layout work by starting right first
.map(active => this.closeEditor(this.stacks.positionOfGroup(active.group), active.editor))
).done(null, errors.onUnexpectedError);
}, errors.onUnexpectedError);
// Reset
this.pendingEditorInputCloseTimeout = null;
......@@ -1279,7 +1266,6 @@ export class EditorPart extends Part implements IEditorPart {
let to = <Position>arg2;
this.doRochade(this.visibleInputs, from, to, null);
this.doRochade(this.visibleInputListeners, from, to, null);
this.doRochade(this.visibleEditors, from, to, null);
this.doRochade(this.editorOpenToken, from, to, null);
this.doRochade(this.mapEditorInstantiationPromiseToEditor, from, to, Object.create(null));
......@@ -1306,18 +1292,18 @@ export class EditorPart extends Part implements IEditorPart {
this.modifyGroups(() => {
for (let i = 0; i < position; i++) {
if (!this.hasGroup(i)) {
this.stacksModel.openGroup('', false, i);
this.stacks.openGroup('', false, i);
}
}
group = this.stacksModel.openGroup('', activate, position);
group = this.stacks.openGroup('', activate, position);
});
} else {
this.renameGroups(); // ensure group labels are proper
}
if (activate) {
this.stacksModel.setActive(group);
this.stacks.setActive(group);
}
return group;
......@@ -1333,25 +1319,25 @@ export class EditorPart extends Part implements IEditorPart {
}
private renameGroups(): void {
const groups = this.stacksModel.groups;
const groups = this.stacks.groups;
if (groups.length > 0) {
// LEFT | CENTER | RIGHT
if (groups.length > 2) {
this.stacksModel.renameGroup(this.groupAt(Position.LEFT), EditorPart.GROUP_LEFT_LABEL);
this.stacksModel.renameGroup(this.groupAt(Position.CENTER), EditorPart.GROUP_CENTER_LABEL);
this.stacksModel.renameGroup(this.groupAt(Position.RIGHT), EditorPart.GROUP_RIGHT_LABEL);
this.stacks.renameGroup(this.groupAt(Position.LEFT), EditorPart.GROUP_LEFT_LABEL);
this.stacks.renameGroup(this.groupAt(Position.CENTER), EditorPart.GROUP_CENTER_LABEL);
this.stacks.renameGroup(this.groupAt(Position.RIGHT), EditorPart.GROUP_RIGHT_LABEL);
}
// LEFT | RIGHT
else if (groups.length > 1) {
this.stacksModel.renameGroup(this.groupAt(Position.LEFT), EditorPart.GROUP_LEFT_LABEL);
this.stacksModel.renameGroup(this.groupAt(Position.CENTER), EditorPart.GROUP_RIGHT_LABEL);
this.stacks.renameGroup(this.groupAt(Position.LEFT), EditorPart.GROUP_LEFT_LABEL);
this.stacks.renameGroup(this.groupAt(Position.CENTER), EditorPart.GROUP_RIGHT_LABEL);
}
// LEFT
else {
this.stacksModel.renameGroup(this.groupAt(Position.LEFT), EditorPart.GROUP_LEFT_LABEL);
this.stacks.renameGroup(this.groupAt(Position.LEFT), EditorPart.GROUP_LEFT_LABEL);
}
}
}
......
......@@ -53,6 +53,12 @@ export enum ConfirmResult {
export abstract class EditorInput extends EventEmitter implements IEditorInput {
private disposed: boolean;
constructor() {
super();
this.disposed = false;
}
/**
* Returns the unique id of this input.
*/
......@@ -96,13 +102,6 @@ export abstract class EditorInput extends EventEmitter implements IEditorInput {
return null;
}
/**
* Returns true if this input is identical to the otherInput.
*/
public matches(otherInput: any): boolean {
return this === otherInput;
}
/**
* Returns a type of EditorModel that represents the resolved input. Subclasses should
* override to provide a meaningful model. The optional second argument allows to specify
......@@ -140,9 +139,17 @@ export abstract class EditorInput extends EventEmitter implements IEditorInput {
}
/**
* Called when the editor is closed. Subclasses can free resources as needed.
* Called when this input is no longer opened in any editor. Subclasses can free resources as needed.
*/
public close(): void {
this.dispose();
}
/**
* Returns true if this input is identical to the otherInput.
*/
public matches(otherInput: any): boolean {
return this === otherInput;
}
/**
......@@ -280,11 +287,6 @@ export abstract class BaseDiffEditorInput extends EditorInput {
public revert(): TPromise<boolean> {
return this._modifiedInput.revert();
}
public close(): void {
this._originalInput.close();
this._modifiedInput.close();
}
}
/**
......
......@@ -197,10 +197,6 @@ export class DiffEditorInput extends BaseDiffEditorInput {
this.cachedModel = null;
}
// Delegate to Inputs
this.originalInput.dispose();
this.modifiedInput.dispose();
super.dispose();
}
}
......
......@@ -14,7 +14,8 @@ import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/c
import {dispose, IDisposable} from 'vs/base/common/lifecycle';
import {IEditorRegistry, Extensions} from 'vs/workbench/browser/parts/editor/baseEditor';
import {Registry} from 'vs/platform/platform';
import {Position, Direction, IEditorInput} from 'vs/platform/editor/common/editor';
import {Position, Direction} from 'vs/platform/editor/common/editor';
import {DiffEditorInput} from 'vs/workbench/common/editor/diffEditorInput';
export interface IEditorGroup {
......@@ -72,7 +73,7 @@ export interface IEditorStacksModel {
export interface IEditorIdentifier {
group: IEditorGroup;
editor: IEditorInput;
editor: EditorInput;
}
export type GroupIdentifier = number;
......@@ -118,6 +119,7 @@ export class EditorGroup implements IEditorGroup {
private _onEditorActivated: Emitter<EditorInput>;
private _onEditorOpened: Emitter<EditorInput>;
private _onEditorClosed: Emitter<IGroupEvent>;
private _onEditorDisposed: Emitter<EditorInput>;
private _onEditorMoved: Emitter<EditorInput>;
private _onEditorPinned: Emitter<EditorInput>;
private _onEditorUnpinned: Emitter<EditorInput>;
......@@ -142,12 +144,13 @@ export class EditorGroup implements IEditorGroup {
this._onEditorActivated = new Emitter<EditorInput>();
this._onEditorOpened = new Emitter<EditorInput>();
this._onEditorClosed = new Emitter<IGroupEvent>();
this._onEditorDisposed = new Emitter<EditorInput>();
this._onEditorMoved = new Emitter<EditorInput>();
this._onEditorPinned = new Emitter<EditorInput>();
this._onEditorUnpinned = new Emitter<EditorInput>();
this._onEditorChanged = new Emitter<EditorInput>();
this.toDispose.push(this._onEditorActivated, this._onEditorOpened, this._onEditorClosed, this._onEditorMoved, this._onEditorPinned, this._onEditorUnpinned, this._onEditorChanged);
this.toDispose.push(this._onEditorActivated, this._onEditorOpened, this._onEditorClosed, this._onEditorDisposed, this._onEditorMoved, this._onEditorPinned, this._onEditorUnpinned, this._onEditorChanged);
}
public get id(): GroupIdentifier {
......@@ -178,6 +181,10 @@ export class EditorGroup implements IEditorGroup {
return this._onEditorClosed.event;
}
public get onEditorDisposed(): Event<EditorInput> {
return this._onEditorDisposed.event;
}
public get onEditorMoved(): Event<EditorInput> {
return this._onEditorMoved.event;
}
......@@ -270,6 +277,21 @@ export class EditorGroup implements IEditorGroup {
this.preview = editor;
}
// Re-emit disposal of editor input as our own event
const l1 = editor.addOneTimeDisposableListener('dispose', () => {
if (this.indexOf(editor) >= 0) {
this._onEditorDisposed.fire(editor);
}
});
// Clean up dispose listeners once the editor gets closed
const l2 = this.onEditorClosed(event => {
if (event.editor.matches(editor)) {
l1.dispose();
l2.dispose();
}
});
// Event
this.fireEvent(this._onEditorOpened, editor);
......@@ -326,9 +348,6 @@ export class EditorGroup implements IEditorGroup {
pinned = false;
}
// Close it
editor.close();
// Remove from arrays
this.splice(index, true);
......@@ -587,6 +606,7 @@ export class EditorStacksModel implements IEditorStacksModel {
private _onGroupActivated: Emitter<EditorGroup>;
private _onGroupRenamed: Emitter<EditorGroup>;
private _onModelChanged: Emitter<EditorGroup>;
private _onEditorDisposed: Emitter<IEditorIdentifier>;
constructor(
@IStorageService private storageService: IStorageService,
......@@ -607,8 +627,9 @@ export class EditorStacksModel implements IEditorStacksModel {
this._onGroupMoved = new Emitter<EditorGroup>();
this._onGroupRenamed = new Emitter<EditorGroup>();
this._onModelChanged = new Emitter<EditorGroup>();
this._onEditorDisposed = new Emitter<IEditorIdentifier>();
this.toDispose.push(this._onGroupOpened, this._onGroupClosed, this._onGroupActivated, this._onGroupMoved, this._onGroupRenamed, this._onModelChanged);
this.toDispose.push(this._onGroupOpened, this._onGroupClosed, this._onGroupActivated, this._onGroupMoved, this._onGroupRenamed, this._onModelChanged, this._onEditorDisposed);
this.registerListeners();
}
......@@ -641,6 +662,10 @@ export class EditorStacksModel implements IEditorStacksModel {
return this._onModelChanged.event;
}
public get onEditorDisposed(): Event<IEditorIdentifier> {
return this._onEditorDisposed.event;
}
public get groups(): EditorGroup[] {
this.ensureLoaded();
......@@ -786,6 +811,8 @@ export class EditorStacksModel implements IEditorStacksModel {
return this._groups.indexOf(group);
}
public positionOfGroup(group: IEditorGroup);
public positionOfGroup(group: EditorGroup);
public positionOfGroup(group: EditorGroup): Position {
return this.indexOf(group);
}
......@@ -988,9 +1015,10 @@ export class EditorStacksModel implements IEditorStacksModel {
// Funnel editor changes in the group through our event aggregator
const l1 = group.onEditorChanged(e => this._onModelChanged.fire(group));
const l2 = group.onEditorClosed(e => this.onEditorClosed(e));
const l3 = this.onGroupClosed(g => {
const l3 = group.onEditorDisposed(editor => this._onEditorDisposed.fire({ editor, group }));
const l4 = this.onGroupClosed(g => {
if (g === group) {
dispose(l1, l2, l3);
dispose(l1, l2, l3, l4);
}
});
......@@ -1009,23 +1037,41 @@ export class EditorStacksModel implements IEditorStacksModel {
}
private onEditorClosed(event: IGroupEvent): void {
if (!event.pinned) {
return; // we only care about pinned editors
const editor = event.editor;
// Close the editor when it is no longer open in any group
if (!this.isOpen(editor)) {
editor.close();
// Also take care of diff editor inputs that wrap around 2 editors
if (editor instanceof DiffEditorInput) {
[editor.getOriginalInput(), editor.getModifiedInput()].forEach(editor => {
if (!this.isOpen(editor)) {
editor.close();
}
});
}
}
const editor = event.editor;
const registry = Registry.as<IEditorRegistry>(Extensions.Editors);
// Track closing of pinned editor to support to reopen closed editors
if (event.pinned) {
const registry = Registry.as<IEditorRegistry>(Extensions.Editors);
const factory = registry.getEditorInputFactory(editor.getId());
if (factory) {
let value = factory.serialize(editor);
if (typeof value === 'string') {
this.recentlyClosedEditors.push({ id: editor.getId(), value });
this.recentlyClosedEditors = this.recentlyClosedEditors.slice(0, 10); // upper bound of recently closed
const factory = registry.getEditorInputFactory(editor.getId());
if (factory) {
let value = factory.serialize(editor);
if (typeof value === 'string') {
this.recentlyClosedEditors.push({ id: editor.getId(), value });
this.recentlyClosedEditors = this.recentlyClosedEditors.slice(0, 10); // upper bound of recently closed
}
}
}
}
private isOpen(editor: EditorInput): boolean {
return this._groups.some(g => g.indexOf(editor) >= 0);
}
private onShutdown(): void {
this.save();
......
......@@ -275,6 +275,15 @@ export class FileEditorInput extends CommonFileEditorInput {
});
}
public close(): void {
let inputs: FileEditorInput[] = [this, ...FileEditorInput.getAll(this.resource)];
inputs.forEach(input => {
if (!input.isDisposed()) {
input.dispose(true);
}
});
}
private indexOfClient(): number {
if (!types.isUndefinedOrNull(FileEditorInput.FILE_EDITOR_MODEL_CLIENTS[this.resource.toString()])) {
for (let i = 0; i < FileEditorInput.FILE_EDITOR_MODEL_CLIENTS[this.resource.toString()].length; i++) {
......
......@@ -67,7 +67,7 @@ suite('Workbench - EditorInput', () => {
assert(!diffInput.matches(null));
diffInput.dispose();
assert.equal(counter, 2);
assert.equal(counter, 0);
});
test('DiffEditorInput disposes when input inside disposes', function () {
......
......@@ -6,7 +6,7 @@
'use strict';
import * as assert from 'assert';
import {EditorStacksModel, IEditorStacksModel, IEditorGroup, EditorGroup, setOpenEditorDirection} from 'vs/workbench/common/editor/editorStacksModel';
import {EditorStacksModel, IEditorIdentifier, IEditorGroup, EditorGroup, setOpenEditorDirection} from 'vs/workbench/common/editor/editorStacksModel';
import {EditorInput} from 'vs/workbench/common/editor';
import {TestStorageService, TestLifecycleService, TestContextService, TestWorkspace, TestConfiguration} from 'vs/workbench/test/common/servicesTestUtils';
import {InstantiationService} from 'vs/platform/instantiation/common/instantiationService';
......@@ -18,6 +18,7 @@ import {IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory} fr
import {Registry} from 'vs/platform/platform';
import {Position, Direction} from 'vs/platform/editor/common/editor';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {DiffEditorInput} from 'vs/workbench/common/editor/diffEditorInput';
function create(): EditorStacksModel {
let services = new ServiceCollection();
......@@ -36,6 +37,7 @@ interface ModelEvents {
closed: IEditorGroup[];
moved: IEditorGroup[];
renamed: IEditorGroup[];
disposed: IEditorIdentifier[];
}
interface GroupEvents {
......@@ -47,13 +49,14 @@ interface GroupEvents {
moved: EditorInput[];
}
function modelListener(model: IEditorStacksModel): ModelEvents {
function modelListener(model: EditorStacksModel): ModelEvents {
const modelEvents = {
opened: [],
activated: [],
closed: [],
moved: [],
renamed: []
renamed: [],
disposed: []
};
model.onGroupOpened(g => modelEvents.opened.push(g));
......@@ -61,6 +64,7 @@ function modelListener(model: IEditorStacksModel): ModelEvents {
model.onGroupClosed(g => modelEvents.closed.push(g));
model.onGroupMoved(g => modelEvents.moved.push(g));
model.onGroupRenamed(g => modelEvents.renamed.push(g));
model.onEditorDisposed(e => modelEvents.disposed.push(e));
return modelEvents;
}
......@@ -1395,4 +1399,108 @@ suite('Editor Stacks Model', () => {
assert.equal(previous.group, group1);
assert.equal(previous.editor, input3);
});
test('Stack - Multiple Editors - Editor Dispose', function () {
const model = create();
const events = modelListener(model);
const group1 = model.openGroup('group1');
const group2 = model.openGroup('group2');
const input1 = input();
const input2 = input();
const input3 = input();
group1.openEditor(input1, { pinned: true, active: true });
group1.openEditor(input2, { pinned: true, active: true });
group1.openEditor(input3, { pinned: true, active: true });
group2.openEditor(input1, { pinned: true, active: true });
group2.openEditor(input2, { pinned: true, active: true });
input1.dispose();
assert.equal(events.disposed.length, 2);
assert.ok(events.disposed[0].editor.matches(input1));
assert.ok(events.disposed[1].editor.matches(input1));
input3.dispose();
assert.equal(events.disposed.length, 3);
assert.ok(events.disposed[2].editor.matches(input3));
const input4 = input();
const input5 = input();
group1.openEditor(input4, { pinned: false, active: true });
group1.openEditor(input5, { pinned: false, active: true });
input4.dispose();
assert.equal(events.disposed.length, 3);
model.closeGroup(group2);
input2.dispose();
assert.equal(events.disposed.length, 4);
});
test('Stack - Multiple Editors - Editor Disposed on Close', function () {
const model = create();
const group1 = model.openGroup('group1');
const group2 = model.openGroup('group2');
const input1 = input();
const input2 = input();
const input3 = input();
const input4 = input();
group1.openEditor(input1, { pinned: true, active: true });
group1.openEditor(input2, { pinned: true, active: true });
group1.openEditor(input3, { pinned: true, active: true });
group1.openEditor(input4, { pinned: true, active: true });
group1.closeEditor(input3);
assert.equal(input3.isDisposed(), true);
group2.openEditor(input2, { pinned: true, active: true });
group2.openEditor(input3, { pinned: true, active: true });
group2.openEditor(input4, { pinned: true, active: true });
group1.closeEditor(input2);
assert.equal(input2.isDisposed(), false);
group2.closeEditor(input2);
assert.equal(input2.isDisposed(), true);
group1.closeAllEditors();
assert.equal(input4.isDisposed(), false);
model.closeGroups();
assert.equal(input4.isDisposed(), true);
});
test('Stack - Multiple Editors - Editor Disposed on Close (Diff Editor)', function () {
const model = create();
const group1 = model.openGroup('group1');
const input1 = input();
const input2 = input();
const diffInput = new DiffEditorInput('name', 'description', input1, input2);
group1.openEditor(diffInput, { pinned: true, active: true});
group1.openEditor(input1, { pinned: true, active: true });
group1.closeEditor(diffInput);
assert.equal(diffInput.isDisposed(), true);
assert.equal(input2.isDisposed(), true);
assert.equal(input1.isDisposed(), false);
});
});
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册