diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts index 839bdbd75d8..6a8b0b8854c 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChat.ts @@ -21,6 +21,8 @@ export const enum TerminalChatCommandId { RunCommand = 'workbench.action.terminal.chat.runCommand', InsertCommand = 'workbench.action.terminal.chat.insertCommand', ViewInChat = 'workbench.action.terminal.chat.viewInChat', + PreviousFromHistory = 'workbench.action.terminal.chat.previousFromHistory', + NextFromHistory = 'workbench.action.terminal.chat.nextFromHistory', } export const MENU_TERMINAL_CHAT_INPUT = MenuId.for('terminalChatInput'); diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts index af3ffe462fb..0face61a30e 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatActions.ts @@ -40,7 +40,7 @@ registerActiveXtermAction({ return; } const contr = TerminalChatController.activeChatWidget || TerminalChatController.get(activeInstance); - contr?.chatWidget?.reveal(); + contr?.reveal(); } }); @@ -368,3 +368,42 @@ registerActiveXtermAction({ } }); +registerActiveXtermAction({ + id: TerminalChatCommandId.PreviousFromHistory, + title: localize2('previousFromHistory', 'Previous From History'), + precondition: ContextKeyExpr.and( + ContextKeyExpr.has(`config.${TerminalSettingId.ExperimentalInlineChat}`), + TerminalChatContextKeys.responseContainsCodeBlock.notEqualsTo(undefined) + ), + keybinding: { + weight: KeybindingWeight.EditorCore + 10, // win against core_command + primary: KeyCode.UpArrow, + }, + run: (_xterm, _accessor, activeInstance) => { + if (isDetachedTerminalInstance(activeInstance)) { + return; + } + const contr = TerminalChatController.activeChatWidget || TerminalChatController.get(activeInstance); + contr?.populateHistory(true); + } +}); + +registerActiveXtermAction({ + id: TerminalChatCommandId.NextFromHistory, + title: localize2('nextFromHistory', 'Next From History'), + precondition: ContextKeyExpr.and( + ContextKeyExpr.has(`config.${TerminalSettingId.ExperimentalInlineChat}`), + TerminalChatContextKeys.responseContainsCodeBlock.notEqualsTo(undefined) + ), + keybinding: { + weight: KeybindingWeight.EditorCore + 10, // win against core_command + primary: KeyCode.DownArrow, + }, + run: (_xterm, _accessor, activeInstance) => { + if (isDetachedTerminalInstance(activeInstance)) { + return; + } + const contr = TerminalChatController.activeChatWidget || TerminalChatController.get(activeInstance); + contr?.populateHistory(false); + } +}); diff --git a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts index d19904b8d51..643dce683aa 100644 --- a/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts +++ b/src/vs/workbench/contrib/terminalContrib/chat/browser/terminalChatController.ts @@ -25,6 +25,7 @@ import { TerminalChatWidget } from 'vs/workbench/contrib/terminalContrib/chat/br import { ChatModel, ChatRequestModel, IChatRequestVariableData, getHistoryEntriesFromModel } from 'vs/workbench/contrib/chat/common/chatModel'; import { TerminalChatContextKeys } from 'vs/workbench/contrib/terminalContrib/chat/browser/terminalChat'; import { MarkdownString } from 'vs/base/common/htmlContent'; +import { InlineChatHistory } from 'vs/workbench/contrib/inlineChat/browser/inlineChatHistory'; const enum Message { NONE = 0, @@ -71,6 +72,7 @@ export class TerminalChatController extends Disposable implements ITerminalContr private _currentRequest: ChatRequestModel | undefined; + private readonly _history: InlineChatHistory; private _lastInput: string | undefined; private _lastResponseContent: string | undefined; get lastResponseContent(): string | undefined { @@ -106,6 +108,8 @@ export class TerminalChatController extends Disposable implements ITerminalContr this._responseSupportsIssueReportingContextKey = TerminalChatContextKeys.responseSupportsIssueReporting.bindTo(this._contextKeyService); this._sessionResponseVoteContextKey = TerminalChatContextKeys.sessionResponseVote.bindTo(this._contextKeyService); + this._history = this._instantiationService.createInstance(InlineChatHistory, 'terminal-chat-history'); + if (!this._configurationService.getValue(TerminalSettingId.ExperimentalInlineChat)) { return; } @@ -270,6 +274,7 @@ export class TerminalChatController extends Disposable implements ITerminalContr }; await model.waitForInitialization(); + this._history.update(this._lastInput); const request: IParsedChatRequest = { text: this._lastInput, parts: [] @@ -376,6 +381,14 @@ export class TerminalChatController extends Disposable implements ITerminalContr } } + populateHistory(up: boolean) { + const entry = this._history.populateHistory(this.getInput(), up); + if (entry) { + this.updateInput(entry, true); + } + } + + // TODO: Move to register calls, don't override override dispose() { if (this._currentRequest) { this._model.value?.cancelRequest(this._currentRequest);