From cd4abdd71cfc522bedbc992ad3eb6148542dd8d1 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Fri, 31 Oct 2025 14:34:55 -0400 Subject: [PATCH] only show chat terminal hint if there are hidden terminals (#274399) --- .../terminal/browser/terminalTabbedView.ts | 6 +++ .../terminal/browser/terminalTabsChatEntry.ts | 5 ++- .../chat/browser/terminalChat.ts | 4 ++ .../chat/browser/terminalChatService.ts | 44 ++++++++++++++----- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts index f47a4250d8f..3af84473dfa 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabbedView.ts @@ -140,6 +140,12 @@ export class TerminalTabbedView extends Disposable { this._updateChatTerminalsEntry(); })); + this._register(contextKeyService.onDidChangeContext(e => { + if (e.affectsSome(new Set(['hasHiddenChatTerminals']))) { + this._refreshShowTabs(); + this._updateChatTerminalsEntry(); + } + })); this._attachEventListeners(parentElement, this._terminalContainer); this._register(this._terminalGroupService.onDidChangePanelOrientation((orientation) => { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTabsChatEntry.ts b/src/vs/workbench/contrib/terminal/browser/terminalTabsChatEntry.ts index fc0976bdb12..5a19d03319c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTabsChatEntry.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTabsChatEntry.ts @@ -11,6 +11,7 @@ import { localize } from '../../../../nls.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { ITerminalChatService } from './terminal.js'; import * as dom from '../../../../base/browser/dom.js'; +import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; export class TerminalTabsChatEntry extends Disposable { @@ -28,6 +29,7 @@ export class TerminalTabsChatEntry extends Disposable { private readonly _tabContainer: HTMLElement, @ICommandService private readonly _commandService: ICommandService, @ITerminalChatService private readonly _terminalChatService: ITerminalChatService, + @IContextKeyService private readonly _contextKeyService: IContextKeyService, ) { super(); @@ -61,9 +63,8 @@ export class TerminalTabsChatEntry extends Disposable { update(): void { const chatTerminalCount = this._terminalChatService.getToolSessionTerminalInstances().length; - const hasChatTerminals = chatTerminalCount > 0; - if (!hasChatTerminals) { + if (!this._contextKeyService.getContextKeyValue('hasHiddenChatTerminals')) { this._entry.style.display = 'none'; this._label.textContent = ''; this._entry.removeAttribute('aria-label'); diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts index 3b478d1c284..3a8fe31106b 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts @@ -37,6 +37,7 @@ export const enum TerminalChatContextKeyStrings { ChatResponseSupportsIssueReporting = 'terminalChatResponseSupportsIssueReporting', ChatSessionResponseVote = 'terminalChatSessionResponseVote', ChatHasTerminals = 'hasChatTerminals', + ChatHasHiddenTerminals = 'hasHiddenChatTerminals', } @@ -65,4 +66,7 @@ export namespace TerminalChatContextKeys { /** Has terminals created via chat */ export const hasChatTerminals = new RawContextKey(TerminalChatContextKeyStrings.ChatHasTerminals, false, localize('terminalHasChatTerminals', "Whether there are any chat terminals.")); + + /** Has hidden chat terminals */ + export const hasHiddenChatTerminals = new RawContextKey(TerminalChatContextKeyStrings.ChatHasHiddenTerminals, false, localize('terminalHasHiddenChatTerminals', "Whether there are any hidden chat terminals.")); } diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatService.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatService.ts index e151ab62d21..4e8535ba9c6 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatService.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatService.ts @@ -40,6 +40,7 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ private readonly _pendingRestoredMappings = new Map(); private readonly _hasToolTerminalContext: IContextKey; + private readonly _hasHiddenToolTerminalContext: IContextKey; constructor( @ILogService private readonly _logService: ILogService, @@ -51,6 +52,7 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ super(); this._hasToolTerminalContext = TerminalChatContextKeys.hasChatTerminals.bindTo(this._contextKeyService); + this._hasHiddenToolTerminalContext = TerminalChatContextKeys.hasHiddenChatTerminals.bindTo(this._contextKeyService); this._restoreFromStorage(); } @@ -66,28 +68,47 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ this._terminalInstancesByToolSessionId.delete(terminalToolSessionId); this._terminalInstanceListenersByToolSessionId.deleteAndDispose(terminalToolSessionId); this._persistToStorage(); - this._updateHasToolTerminalContextKey(); - })); - const listener = this._register(instance.capabilities.get(TerminalCapability.CommandDetection)!.onCommandFinished(e => { - this._commandIdByToolSessionId.set(terminalToolSessionId, e.id); - this._persistToStorage(); - listener.dispose(); + this._updateHasToolTerminalContextKeys(); })); + const commandDetection = instance.capabilities.get(TerminalCapability.CommandDetection); + if (commandDetection) { + const listener = this._register(commandDetection.onCommandFinished(e => { + this._commandIdByToolSessionId.set(terminalToolSessionId, e.id); + this._persistToStorage(); + listener.dispose(); + })); + } else { + this._register(instance.capabilities.onDidAddCapability(capability => { + if (capability.id === TerminalCapability.CommandDetection) { + const commandDetection = instance.capabilities.get(TerminalCapability.CommandDetection); + if (commandDetection) { + const listener = this._register(commandDetection.onCommandFinished(e => { + this._commandIdByToolSessionId.set(terminalToolSessionId, e.id); + this._persistToStorage(); + listener.dispose(); + })); + } + } + })); + } this._register(this._chatService.onDidDisposeSession(e => { if (LocalChatSessionUri.parseLocalSessionId(e.sessionResource) === terminalToolSessionId) { this._terminalInstancesByToolSessionId.delete(terminalToolSessionId); this._terminalInstanceListenersByToolSessionId.deleteAndDispose(terminalToolSessionId); this._commandIdByToolSessionId.delete(terminalToolSessionId); this._persistToStorage(); - this._updateHasToolTerminalContextKey(); + this._updateHasToolTerminalContextKeys(); } })); + // Update context keys when terminal instances change (including when terminals are created, disposed, revealed, or hidden) + this._register(this._terminalService.onDidChangeInstances(() => this._updateHasToolTerminalContextKeys())); + if (typeof instance.persistentProcessId === 'number') { this._persistToStorage(); } - this._updateHasToolTerminalContextKey(); + this._updateHasToolTerminalContextKeys(); } getTerminalCommandIdByToolSessionId(terminalToolSessionId: string | undefined): string | undefined { @@ -181,7 +202,7 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ } private _persistToStorage(): void { - this._updateHasToolTerminalContextKey(); + this._updateHasToolTerminalContextKeys(); try { const entries: [string, number][] = []; for (const [toolSessionId, instance] of this._terminalInstancesByToolSessionId.entries()) { @@ -208,8 +229,11 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ } } - private _updateHasToolTerminalContextKey(): void { + private _updateHasToolTerminalContextKeys(): void { const toolCount = this._terminalInstancesByToolSessionId.size; this._hasToolTerminalContext.set(toolCount > 0); + const foregroundInstances = new Set(this._terminalService.foregroundInstances.map(i => i.instanceId)); + const hiddenToolCount = Array.from(this._terminalInstancesByToolSessionId.values()).filter(instance => !foregroundInstances.has(instance.instanceId)).length; + this._hasHiddenToolTerminalContext.set(hiddenToolCount > 0); } }