diff --git a/src/vs/workbench/api/common/extHostEditorTabs.ts b/src/vs/workbench/api/common/extHostEditorTabs.ts index 17201e69e0e..5d6033c4849 100644 --- a/src/vs/workbench/api/common/extHostEditorTabs.ts +++ b/src/vs/workbench/api/common/extHostEditorTabs.ts @@ -36,7 +36,7 @@ export interface IEditorTabGroups { all: IEditorTabGroup[]; activeTabGroup: IEditorTabGroup | undefined; readonly onDidChangeTabGroup: Event; - readonly onDidChangeActiveTabGroup: Event; + readonly onDidChangeActiveTabGroup: Event; } export interface IExtHostEditorTabs extends IExtHostEditorTabsShape { @@ -52,7 +52,7 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs { private readonly _onDidChangeTabGroup = new Emitter(); - private readonly _onDidChangeActiveTabGroup = new Emitter(); + private readonly _onDidChangeActiveTabGroup = new Emitter(); private _tabGroups: IEditorTabGroups = { all: [], @@ -72,6 +72,7 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs { $acceptEditorTabModel(tabGroups: IEditorTabGroupDto[]): void { // Clears the tab groups array this._tabGroups.all.length = 0; + let activeGroupFound = false; for (const group of tabGroups) { let activeTab: IEditorTab | undefined; const tabs = group.tabs.map(tab => { @@ -90,6 +91,7 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs { // If the currrent group is active, set the active group to be that group. // We must use the same object so we pull from the array to allow for reference equality if (group.isActive) { + activeGroupFound = true; const oldActiveTabGroup = this._tabGroups.activeTabGroup; this._tabGroups.activeTabGroup = this._tabGroups.all[this._tabGroups.all.length - 1]; // Diff the old and current active group to decide if we should fire a change event @@ -98,6 +100,11 @@ export class ExtHostEditorTabs implements IExtHostEditorTabs { } } } + // No active group was found in the model (most common case is model was empty) fire undefined event + if (!activeGroupFound) { + this._tabGroups.activeTabGroup = undefined; + this._onDidChangeActiveTabGroup.fire(undefined); + } this._onDidChangeTabGroup.fire(); } diff --git a/src/vs/workbench/api/test/browser/extHostEditorTabs.test.ts b/src/vs/workbench/api/test/browser/extHostEditorTabs.test.ts index 06806429cd1..6be6712566c 100644 --- a/src/vs/workbench/api/test/browser/extHostEditorTabs.test.ts +++ b/src/vs/workbench/api/test/browser/extHostEditorTabs.test.ts @@ -150,4 +150,65 @@ suite('ExtHostEditorTabs', function () { assert.strictEqual(first.activeTab, first.tabs[0]); assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup, first); }); + + test('onDidChangeActiveTabGroup fires properly', function () { + const extHostEditorTabs = new ExtHostEditorTabs( + SingleProxyRPCProtocol(new class extends mock() { + // override/implement $moveTab or $closeTab + }) + ); + + let count = 0; + let activeTabGroupFromEvent: IEditorTabGroup | undefined = undefined; + extHostEditorTabs.tabGroups.onDidChangeActiveTabGroup((tabGroup) => { + count++; + activeTabGroupFromEvent = tabGroup; + }); + + + assert.strictEqual(extHostEditorTabs.tabGroups.all.length, 0); + assert.strictEqual(extHostEditorTabs.tabGroups.activeTabGroup, undefined); + assert.strictEqual(count, 0); + const tabModel = [{ + isActive: true, + viewColumn: 0, + groupId: 12, + tabs: [], + activeTab: undefined + }]; + extHostEditorTabs.$acceptEditorTabModel(tabModel); + assert.ok(extHostEditorTabs.tabGroups.activeTabGroup); + let activeTabGroup: IEditorTabGroup = extHostEditorTabs.tabGroups.activeTabGroup; + assert.strictEqual(count, 1); + assert.strictEqual(activeTabGroup, activeTabGroupFromEvent); + // Firing again with same model shouldn't cause a change + extHostEditorTabs.$acceptEditorTabModel(tabModel); + assert.strictEqual(count, 1); + // Changing a property should fire a change + tabModel[0].viewColumn = 1; + extHostEditorTabs.$acceptEditorTabModel(tabModel); + assert.strictEqual(count, 2); + activeTabGroup = extHostEditorTabs.tabGroups.activeTabGroup; + assert.strictEqual(activeTabGroup, activeTabGroupFromEvent); + // Changing the active tab group should fire a change + tabModel[0].isActive = false; + tabModel.push({ + isActive: true, + viewColumn: 0, + groupId: 13, + tabs: [], + activeTab: undefined + }); + extHostEditorTabs.$acceptEditorTabModel(tabModel); + assert.strictEqual(count, 3); + activeTabGroup = extHostEditorTabs.tabGroups.activeTabGroup; + assert.strictEqual(activeTabGroup, activeTabGroupFromEvent); + + // Empty tab model should fire a change and return undefined + extHostEditorTabs.$acceptEditorTabModel([]); + assert.strictEqual(count, 4); + activeTabGroup = extHostEditorTabs.tabGroups.activeTabGroup; + assert.strictEqual(activeTabGroup, undefined); + assert.strictEqual(activeTabGroup, activeTabGroupFromEvent); + }); }); diff --git a/src/vscode-dts/vscode.proposed.tabs.d.ts b/src/vscode-dts/vscode.proposed.tabs.d.ts index 348d08a9f3d..f08d94ddda6 100644 --- a/src/vscode-dts/vscode.proposed.tabs.d.ts +++ b/src/vscode-dts/vscode.proposed.tabs.d.ts @@ -115,7 +115,7 @@ declare module 'vscode' { * An {@link Event} which fires when the active group changes. * Whether it be which group is active or its properties. */ - onDidChangeActiveTabGroup: Event; + onDidChangeActiveTabGroup: Event; } interface TabGroup {