diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts index 6a8b0b8854c..4b3de0e684f 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts @@ -19,7 +19,9 @@ export const enum TerminalChatCommandId { FeedbackUnhelpful = 'workbench.action.terminal.chat.feedbackUnhelpful', FeedbackReportIssue = 'workbench.action.terminal.chat.feedbackReportIssue', RunCommand = 'workbench.action.terminal.chat.runCommand', + RunFirstCommand = 'workbench.action.terminal.chat.runFirstCommand', InsertCommand = 'workbench.action.terminal.chat.insertCommand', + InsertFirstCommand = 'workbench.action.terminal.chat.insertFirstCommand', ViewInChat = 'workbench.action.terminal.chat.viewInChat', PreviousFromHistory = 'workbench.action.terminal.chat.previousFromHistory', NextFromHistory = 'workbench.action.terminal.chat.nextFromHistory', @@ -39,6 +41,7 @@ export const enum TerminalChatContextKeyStrings { ChatAgentRegistered = 'terminalChatAgentRegistered', ChatResponseEditorFocused = 'terminalChatResponseEditorFocused', ChatResponseContainsCodeBlock = 'terminalChatResponseContainsCodeBlock', + ChatResponseContainsMultipleCodeBlocks = 'terminalChatResponseContainsMultipleCodeBlocks', ChatResponseSupportsIssueReporting = 'terminalChatResponseSupportsIssueReporting', ChatSessionResponseVote = 'terminalChatSessionResponseVote', } @@ -64,6 +67,9 @@ export namespace TerminalChatContextKeys { /** The type of chat response, if any */ export const responseContainsCodeBlock = new RawContextKey(TerminalChatContextKeyStrings.ChatResponseContainsCodeBlock, false, localize('chatResponseContainsCodeBlockContextKey', "Whether the chat response contains a code block.")); + /** The type of chat response, if any */ + export const responseContainsMultipleCodeBlocks = new RawContextKey(TerminalChatContextKeyStrings.ChatResponseContainsMultipleCodeBlocks, false, localize('chatResponseContainsMultipleCodeBlocksContextKey', "Whether the chat response contains multiple code blocks.")); + /** Whether the response supports issue reporting */ export const responseSupportsIssueReporting = new RawContextKey(TerminalChatContextKeyStrings.ChatResponseSupportsIssueReporting, false, localize('chatResponseSupportsIssueReportingContextKey', "Whether the response supports issue reporting")); diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts index 9ce75d222dc..7f1869b6525 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts @@ -156,7 +156,8 @@ registerActiveXtermAction({ ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalChatContextKeys.requestActive.negate(), TerminalChatContextKeys.agentRegistered, - TerminalChatContextKeys.responseContainsCodeBlock + TerminalChatContextKeys.responseContainsCodeBlock, + TerminalChatContextKeys.responseContainsMultipleCodeBlocks.negate() ), icon: Codicon.play, keybinding: { @@ -168,7 +169,39 @@ registerActiveXtermAction({ id: MENU_TERMINAL_CHAT_WIDGET_STATUS, group: '0_main', order: 0, - when: ContextKeyExpr.and(TerminalChatContextKeys.responseContainsCodeBlock, TerminalChatContextKeys.requestActive.negate()) + when: ContextKeyExpr.and(TerminalChatContextKeys.responseContainsCodeBlock, TerminalChatContextKeys.responseContainsMultipleCodeBlocks.negate(), TerminalChatContextKeys.requestActive.negate()) + }, + run: (_xterm, _accessor, activeInstance) => { + if (isDetachedTerminalInstance(activeInstance)) { + return; + } + const contr = TerminalChatController.activeChatWidget || TerminalChatController.get(activeInstance); + contr?.acceptCommand(true); + } +}); + +registerActiveXtermAction({ + id: TerminalChatCommandId.RunFirstCommand, + title: localize2('runFirstCommand', 'Run First Chat Command'), + shortTitle: localize2('runFirst', 'Run First'), + precondition: ContextKeyExpr.and( + ContextKeyExpr.has(`config.${TerminalSettingId.ExperimentalInlineChat}`), + ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), + TerminalChatContextKeys.requestActive.negate(), + TerminalChatContextKeys.agentRegistered, + TerminalChatContextKeys.responseContainsMultipleCodeBlocks + ), + icon: Codicon.play, + keybinding: { + when: TerminalChatContextKeys.requestActive.negate(), + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyMod.CtrlCmd | KeyCode.Enter, + }, + menu: { + id: MENU_TERMINAL_CHAT_WIDGET_STATUS, + group: '0_main', + order: 0, + when: ContextKeyExpr.and(TerminalChatContextKeys.responseContainsMultipleCodeBlocks, TerminalChatContextKeys.requestActive.negate()) }, run: (_xterm, _accessor, activeInstance) => { if (isDetachedTerminalInstance(activeInstance)) { @@ -188,7 +221,8 @@ registerActiveXtermAction({ ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), TerminalChatContextKeys.requestActive.negate(), TerminalChatContextKeys.agentRegistered, - TerminalChatContextKeys.responseContainsCodeBlock + TerminalChatContextKeys.responseContainsCodeBlock, + TerminalChatContextKeys.responseContainsMultipleCodeBlocks.negate() ), keybinding: { when: TerminalChatContextKeys.requestActive.negate(), @@ -199,7 +233,38 @@ registerActiveXtermAction({ id: MENU_TERMINAL_CHAT_WIDGET_STATUS, group: '0_main', order: 1, - when: ContextKeyExpr.and(TerminalChatContextKeys.responseContainsCodeBlock, TerminalChatContextKeys.requestActive.negate()) + when: ContextKeyExpr.and(TerminalChatContextKeys.responseContainsCodeBlock, TerminalChatContextKeys.responseContainsMultipleCodeBlocks.negate(), TerminalChatContextKeys.requestActive.negate()) + }, + run: (_xterm, _accessor, activeInstance) => { + if (isDetachedTerminalInstance(activeInstance)) { + return; + } + const contr = TerminalChatController.activeChatWidget || TerminalChatController.get(activeInstance); + contr?.acceptCommand(false); + } +}); + +registerActiveXtermAction({ + id: TerminalChatCommandId.InsertFirstCommand, + title: localize2('insertFirstCommand', 'Insert First Chat Command'), + shortTitle: localize2('insertFirst', 'Insert First'), + precondition: ContextKeyExpr.and( + ContextKeyExpr.has(`config.${TerminalSettingId.ExperimentalInlineChat}`), + ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated), + TerminalChatContextKeys.requestActive.negate(), + TerminalChatContextKeys.agentRegistered, + TerminalChatContextKeys.responseContainsMultipleCodeBlocks + ), + keybinding: { + when: TerminalChatContextKeys.requestActive.negate(), + weight: KeybindingWeight.WorkbenchContrib, + primary: KeyMod.Alt | KeyCode.Enter, + }, + menu: { + id: MENU_TERMINAL_CHAT_WIDGET_STATUS, + group: '0_main', + order: 1, + when: ContextKeyExpr.and(TerminalChatContextKeys.responseContainsMultipleCodeBlocks, TerminalChatContextKeys.requestActive.negate()) }, run: (_xterm, _accessor, activeInstance) => { if (isDetachedTerminalInstance(activeInstance)) { diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts index 9393e976205..dbedd62df9f 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts @@ -63,6 +63,7 @@ export class TerminalChatController extends Disposable implements ITerminalContr private readonly _requestActiveContextKey: IContextKey; private readonly _terminalAgentRegisteredContextKey: IContextKey; private readonly _responseContainsCodeBlockContextKey: IContextKey; + private readonly _responseContainsMulitpleCodeBlocksContextKey: IContextKey; private readonly _responseSupportsIssueReportingContextKey: IContextKey; private readonly _sessionResponseVoteContextKey: IContextKey; @@ -103,6 +104,7 @@ export class TerminalChatController extends Disposable implements ITerminalContr this._requestActiveContextKey = TerminalChatContextKeys.requestActive.bindTo(this._contextKeyService); this._terminalAgentRegisteredContextKey = TerminalChatContextKeys.agentRegistered.bindTo(this._contextKeyService); this._responseContainsCodeBlockContextKey = TerminalChatContextKeys.responseContainsCodeBlock.bindTo(this._contextKeyService); + this._responseContainsMulitpleCodeBlocksContextKey = TerminalChatContextKeys.responseContainsMultipleCodeBlocks.bindTo(this._contextKeyService); this._responseSupportsIssueReportingContextKey = TerminalChatContextKeys.responseSupportsIssueReporting.bindTo(this._contextKeyService); this._sessionResponseVoteContextKey = TerminalChatContextKeys.sessionResponseVote.bindTo(this._contextKeyService); @@ -327,7 +329,10 @@ export class TerminalChatController extends Disposable implements ITerminalContr this._chatAccessibilityService.acceptResponse(responseContent, accessibilityRequestId); const containsCode = responseContent.includes('```'); this._chatWidget?.value.inlineChatWidget.updateChatMessage({ message: new MarkdownString(responseContent), requestId: this._currentRequest.id, providerId: 'terminal' }, false, containsCode); - this._responseContainsCodeBlockContextKey.set(containsCode); + const firstCodeBlock = await this.chatWidget?.inlineChatWidget.getCodeBlockInfo(0); + const secondCodeBlock = await this.chatWidget?.inlineChatWidget.getCodeBlockInfo(1); + this._responseContainsCodeBlockContextKey.set(!!firstCodeBlock); + this._responseContainsMulitpleCodeBlocksContextKey.set(!!secondCodeBlock); this._chatWidget?.value.inlineChatWidget.updateToolbar(true); } const supportIssueReporting = this._currentRequest?.response?.agent?.metadata?.supportIssueReporting;