mirror of
https://github.com/microsoft/vscode.git
synced 2026-02-15 07:28:05 +00:00
Add chat session title to View Chat Terminals action (#274828)
This commit is contained in:
@@ -134,6 +134,28 @@ export interface ITerminalChatService {
|
||||
*/
|
||||
getToolSessionTerminalInstances(): readonly ITerminalInstance[];
|
||||
|
||||
/**
|
||||
* Returns the tool session ID for a given terminal instance, if it has been registered.
|
||||
* @param instance The terminal instance to look up
|
||||
* @returns The tool session ID if found, undefined otherwise
|
||||
*/
|
||||
getToolSessionIdForInstance(instance: ITerminalInstance): string | undefined;
|
||||
|
||||
/**
|
||||
* Associate a chat session ID with a terminal instance. This is used to retrieve the chat
|
||||
* session title for display purposes.
|
||||
* @param chatSessionId The chat session ID
|
||||
* @param instance The terminal instance
|
||||
*/
|
||||
registerTerminalInstanceWithChatSession(chatSessionId: string, instance: ITerminalInstance): void;
|
||||
|
||||
/**
|
||||
* Returns the chat session ID for a given terminal instance, if it has been registered.
|
||||
* @param instance The terminal instance to look up
|
||||
* @returns The chat session ID if found, undefined otherwise
|
||||
*/
|
||||
getChatSessionIdForInstance(instance: ITerminalInstance): string | undefined;
|
||||
|
||||
isBackgroundTerminal(terminalToolSessionId?: string): boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { KeybindingWeight } from '../../../../../platform/keybinding/common/keyb
|
||||
import { ChatViewId, IChatWidgetService } from '../../../chat/browser/chat.js';
|
||||
import { ChatContextKeys } from '../../../chat/common/chatContextKeys.js';
|
||||
import { IChatService } from '../../../chat/common/chatService.js';
|
||||
import { LocalChatSessionUri } from '../../../chat/common/chatUri.js';
|
||||
import { ChatAgentLocation } from '../../../chat/common/constants.js';
|
||||
import { AbstractInline1ChatAction } from '../../../inlineChat/browser/inlineChatActions.js';
|
||||
import { isDetachedTerminalInstance, ITerminalChatService, ITerminalEditorService, ITerminalGroupService, ITerminalInstance, ITerminalService } from '../../../terminal/browser/terminal.js';
|
||||
@@ -327,6 +328,7 @@ registerAction2(class ShowChatTerminalsAction extends Action2 {
|
||||
const terminalChatService = accessor.get(ITerminalChatService);
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
const chatService = accessor.get(IChatService);
|
||||
|
||||
const visible = new Set<ITerminalInstance>([...groupService.instances, ...editorService.instances]);
|
||||
const toolInstances = terminalChatService.getToolSessionTerminalInstances();
|
||||
@@ -357,9 +359,29 @@ registerAction2(class ShowChatTerminalsAction extends Action2 {
|
||||
const iconId = instantiationService.invokeFunction(getIconId, instance);
|
||||
const label = `$(${iconId}) ${instance.title}`;
|
||||
const lastCommand = instance.capabilities.get(TerminalCapability.CommandDetection)?.commands.at(-1)?.command;
|
||||
|
||||
// Get the chat session title
|
||||
const chatSessionId = terminalChatService.getChatSessionIdForInstance(instance);
|
||||
let chatSessionTitle: string | undefined;
|
||||
if (chatSessionId) {
|
||||
const sessionUri = LocalChatSessionUri.forSession(chatSessionId);
|
||||
// Try to get title from active session first, then fall back to persisted title
|
||||
chatSessionTitle = chatService.getSession(sessionUri)?.title || chatService.getPersistedSessionTitle(sessionUri);
|
||||
}
|
||||
|
||||
// Build description: chat session title and/or hidden status
|
||||
let description: string | undefined;
|
||||
if (chatSessionTitle && isBackground) {
|
||||
description = `${chatSessionTitle} • ${hiddenLocalized}`;
|
||||
} else if (chatSessionTitle) {
|
||||
description = chatSessionTitle;
|
||||
} else if (isBackground) {
|
||||
description = hiddenLocalized;
|
||||
}
|
||||
|
||||
metas.push({
|
||||
label,
|
||||
description: isBackground ? hiddenLocalized : undefined,
|
||||
description,
|
||||
detail: lastCommand ? lastCommandLocalized(lastCommand) : undefined,
|
||||
id: String(instance.instanceId),
|
||||
isBackground
|
||||
|
||||
@@ -26,7 +26,10 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ
|
||||
declare _serviceBrand: undefined;
|
||||
|
||||
private readonly _terminalInstancesByToolSessionId = new Map<string, ITerminalInstance>();
|
||||
private readonly _toolSessionIdByTerminalInstance = new Map<ITerminalInstance, string>();
|
||||
private readonly _chatSessionIdByTerminalInstance = new Map<ITerminalInstance, string>();
|
||||
private readonly _terminalInstanceListenersByToolSessionId = this._register(new DisposableMap<string, IDisposable>());
|
||||
private readonly _chatSessionListenersByTerminalInstance = this._register(new DisposableMap<ITerminalInstance, IDisposable>());
|
||||
private readonly _onDidRegisterTerminalInstanceForToolSession = new Emitter<ITerminalInstance>();
|
||||
readonly onDidRegisterTerminalInstanceWithToolSession: Event<ITerminalInstance> = this._onDidRegisterTerminalInstanceForToolSession.event;
|
||||
|
||||
@@ -61,9 +64,11 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ
|
||||
return;
|
||||
}
|
||||
this._terminalInstancesByToolSessionId.set(terminalToolSessionId, instance);
|
||||
this._toolSessionIdByTerminalInstance.set(instance, terminalToolSessionId);
|
||||
this._onDidRegisterTerminalInstanceForToolSession.fire(instance);
|
||||
this._terminalInstanceListenersByToolSessionId.set(terminalToolSessionId, instance.onDisposed(() => {
|
||||
this._terminalInstancesByToolSessionId.delete(terminalToolSessionId);
|
||||
this._toolSessionIdByTerminalInstance.delete(instance);
|
||||
this._terminalInstanceListenersByToolSessionId.deleteAndDispose(terminalToolSessionId);
|
||||
this._persistToStorage();
|
||||
this._updateHasToolTerminalContextKeys();
|
||||
@@ -72,6 +77,7 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ
|
||||
this._register(this._chatService.onDidDisposeSession(e => {
|
||||
if (LocalChatSessionUri.parseLocalSessionId(e.sessionResource) === terminalToolSessionId) {
|
||||
this._terminalInstancesByToolSessionId.delete(terminalToolSessionId);
|
||||
this._toolSessionIdByTerminalInstance.delete(instance);
|
||||
this._terminalInstanceListenersByToolSessionId.deleteAndDispose(terminalToolSessionId);
|
||||
this._persistToStorage();
|
||||
this._updateHasToolTerminalContextKeys();
|
||||
@@ -108,6 +114,32 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ
|
||||
return Array.from(new Set(this._terminalInstancesByToolSessionId.values()));
|
||||
}
|
||||
|
||||
getToolSessionIdForInstance(instance: ITerminalInstance): string | undefined {
|
||||
return this._toolSessionIdByTerminalInstance.get(instance);
|
||||
}
|
||||
|
||||
registerTerminalInstanceWithChatSession(chatSessionId: string, instance: ITerminalInstance): void {
|
||||
// If already registered with the same session ID, skip to avoid duplicate listeners
|
||||
if (this._chatSessionIdByTerminalInstance.get(instance) === chatSessionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up previous listener if the instance was registered with a different session
|
||||
this._chatSessionListenersByTerminalInstance.deleteAndDispose(instance);
|
||||
|
||||
this._chatSessionIdByTerminalInstance.set(instance, chatSessionId);
|
||||
// Clean up when the instance is disposed
|
||||
const disposable = instance.onDisposed(() => {
|
||||
this._chatSessionIdByTerminalInstance.delete(instance);
|
||||
this._chatSessionListenersByTerminalInstance.deleteAndDispose(instance);
|
||||
});
|
||||
this._chatSessionListenersByTerminalInstance.set(instance, disposable);
|
||||
}
|
||||
|
||||
getChatSessionIdForInstance(instance: ITerminalInstance): string | undefined {
|
||||
return this._chatSessionIdByTerminalInstance.get(instance);
|
||||
}
|
||||
|
||||
isBackgroundTerminal(terminalToolSessionId?: string): boolean {
|
||||
if (!terminalToolSessionId) {
|
||||
return false;
|
||||
@@ -144,9 +176,11 @@ export class TerminalChatService extends Disposable implements ITerminalChatServ
|
||||
for (const [toolSessionId, persistentProcessId] of this._pendingRestoredMappings) {
|
||||
if (persistentProcessId === instance.shellLaunchConfig.attachPersistentProcess?.id) {
|
||||
this._terminalInstancesByToolSessionId.set(toolSessionId, instance);
|
||||
this._toolSessionIdByTerminalInstance.set(instance, toolSessionId);
|
||||
this._onDidRegisterTerminalInstanceForToolSession.fire(instance);
|
||||
this._terminalInstanceListenersByToolSessionId.set(toolSessionId, instance.onDisposed(() => {
|
||||
this._terminalInstancesByToolSessionId.delete(toolSessionId);
|
||||
this._toolSessionIdByTerminalInstance.delete(instance);
|
||||
this._terminalInstanceListenersByToolSessionId.deleteAndDispose(toolSessionId);
|
||||
this._persistToStorage();
|
||||
}));
|
||||
|
||||
@@ -705,6 +705,7 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
|
||||
const profile = await this._profileFetcher.getCopilotProfile();
|
||||
const toolTerminal = await this._terminalToolCreator.createTerminal(profile, token);
|
||||
this._terminalChatService.registerTerminalInstanceWithToolSession(terminalToolSessionId, toolTerminal.instance);
|
||||
this._terminalChatService.registerTerminalInstanceWithChatSession(chatSessionId, toolTerminal.instance);
|
||||
this._registerInputListener(toolTerminal);
|
||||
this._sessionTerminalAssociations.set(chatSessionId, toolTerminal);
|
||||
if (token.isCancellationRequested) {
|
||||
@@ -726,6 +727,7 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
|
||||
const profile = await this._profileFetcher.getCopilotProfile();
|
||||
const toolTerminal = await this._terminalToolCreator.createTerminal(profile, token);
|
||||
this._terminalChatService.registerTerminalInstanceWithToolSession(terminalToolSessionId, toolTerminal.instance);
|
||||
this._terminalChatService.registerTerminalInstanceWithChatSession(chatSessionId, toolTerminal.instance);
|
||||
this._registerInputListener(toolTerminal);
|
||||
this._sessionTerminalAssociations.set(chatSessionId, toolTerminal);
|
||||
if (token.isCancellationRequested) {
|
||||
@@ -766,6 +768,7 @@ export class RunInTerminalTool extends Disposable implements IToolImpl {
|
||||
shellIntegrationQuality: association.shellIntegrationQuality
|
||||
};
|
||||
this._sessionTerminalAssociations.set(association.sessionId, toolTerminal);
|
||||
this._terminalChatService.registerTerminalInstanceWithChatSession(association.sessionId, instance);
|
||||
|
||||
// Listen for terminal disposal to clean up storage
|
||||
this._register(instance.onDisposed(() => {
|
||||
|
||||
Reference in New Issue
Block a user