diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts index ac533fdd353..11c67f568db 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts @@ -374,15 +374,18 @@ export function registerChatCodeBlockActions() { const editor = codeEditorService.getFocusedCodeEditor(); const editorUri = editor?.getModel()?.uri; const curCodeBlockInfo = editorUri ? widget.getCodeBlockInfoForEditor(editorUri) : undefined; + const focused = !widget.inputEditor.hasWidgetFocus() && widget.getFocus(); + const focusedResponse = isResponseVM(focused) ? focused : undefined; - const focusResponse = curCodeBlockInfo ? + const currentResponse = curCodeBlockInfo ? curCodeBlockInfo.element : - widget.viewModel?.getItems().reverse().find((item): item is IChatResponseViewModel => isResponseVM(item)); - if (!focusResponse) { + (focusedResponse ?? widget.viewModel?.getItems().reverse().find((item): item is IChatResponseViewModel => isResponseVM(item))); + if (!currentResponse) { return; } - const responseCodeblocks = widget.getCodeBlockInfosForResponse(focusResponse); + widget.reveal(currentResponse); + const responseCodeblocks = widget.getCodeBlockInfosForResponse(currentResponse); const focusIdx = curCodeBlockInfo ? (curCodeBlockInfo.codeBlockIndex + (reverse ? -1 : 1) + responseCodeblocks.length) % responseCodeblocks.length : reverse ? responseCodeblocks.length - 1 : 0; diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatMoveActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatMoveActions.ts index 161ec9cdf6e..292147cbc27 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatMoveActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatMoveActions.ts @@ -23,8 +23,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic const getMoveToEditorChatActionDescriptorForViewTitle = (viewId: string, providerId: string): Readonly & { viewId: string } => ({ id: `workbench.action.chat.${providerId}.openInEditor`, title: { - value: localize('chat.openInEditor.label', "Open In Editor"), - original: 'Open In Editor' + value: localize('chat.openInEditor.label', "Open Session In Editor"), + original: 'Open Session In Editor' }, category: CHAT_CATEGORY, precondition: CONTEXT_PROVIDER_EXISTS, diff --git a/src/vs/workbench/contrib/chat/browser/chat.ts b/src/vs/workbench/contrib/chat/browser/chat.ts index d5f4a134ed5..ba977100111 100644 --- a/src/vs/workbench/contrib/chat/browser/chat.ts +++ b/src/vs/workbench/contrib/chat/browser/chat.ts @@ -5,7 +5,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService'; -import { IChatResponseViewModel, IChatViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel'; +import { IChatRequestViewModel, IChatResponseViewModel, IChatViewModel, IChatWelcomeMessageViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel'; import { Event } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -35,6 +35,8 @@ export interface IChatCodeBlockInfo { focus(): void; } +export type ChatTreeItem = IChatRequestViewModel | IChatResponseViewModel | IChatWelcomeMessageViewModel; + export type IChatWidgetViewContext = { viewId: string } | { resource: boolean }; export interface IChatWidget { @@ -44,6 +46,8 @@ export interface IChatWidget { readonly inputEditor: ICodeEditor; readonly providerId: string; + reveal(item: ChatTreeItem): void; + getFocus(): ChatTreeItem | undefined; acceptInput(query?: string): void; focusLastMessage(): void; focusInput(): void; diff --git a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts index 8ae6050e0c0..77e0fa45ed4 100644 --- a/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts +++ b/src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @@ -18,6 +18,7 @@ import { FuzzyScore } from 'vs/base/common/filters'; import { IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent'; import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ResourceMap } from 'vs/base/common/map'; +import { marked } from 'vs/base/common/marked/marked'; import { FileAccess } from 'vs/base/common/network'; import { ThemeIcon } from 'vs/base/common/themables'; import { withNullAsUndefined } from 'vs/base/common/types'; @@ -37,6 +38,7 @@ import { ViewportSemanticTokensContribution } from 'vs/editor/contrib/semanticTo import { SmartSelectController } from 'vs/editor/contrib/smartSelect/browser/smartSelect'; import { WordHighlighterContribution } from 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter'; import { localize } from 'vs/nls'; +import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { IMenuEntryActionViewItemOptions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { MenuWorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; import { MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; @@ -47,25 +49,21 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILogService } from 'vs/platform/log/common/log'; import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles'; -import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; -import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; -import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; +import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution'; import { IChatCodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/actions/chatCodeblockActions'; -import { IChatCodeBlockInfo } from 'vs/workbench/contrib/chat/browser/chat'; +import { ChatTreeItem, IChatCodeBlockInfo } from 'vs/workbench/contrib/chat/browser/chat'; import { ChatFollowups } from 'vs/workbench/contrib/chat/browser/chatFollowups'; import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions'; import { CONTEXT_REQUEST, CONTEXT_RESPONSE, CONTEXT_RESPONSE_HAS_PROVIDER_ID, CONTEXT_RESPONSE_VOTE } from 'vs/workbench/contrib/chat/common/chatContextKeys'; import { IChatReplyFollowup, IChatService, ISlashCommand, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; -import { IChatRequestViewModel, IChatResponseViewModel, IChatWelcomeMessageViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel'; +import { IChatResponseViewModel, IChatWelcomeMessageViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel'; import { IWordCountResult, getNWords } from 'vs/workbench/contrib/chat/common/chatWordCounter'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; -import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution'; -import { marked } from 'vs/base/common/marked/marked'; +import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; +import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; +import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; const $ = dom.$; -export type ChatTreeItem = IChatRequestViewModel | IChatResponseViewModel | IChatWelcomeMessageViewModel; - interface IChatListItemTemplate { rowContainer: HTMLElement; titleToolbar: MenuWorkbenchToolBar; diff --git a/src/vs/workbench/contrib/chat/browser/chatWidget.ts b/src/vs/workbench/contrib/chat/browser/chatWidget.ts index 34354670c0c..085e4bd2873 100644 --- a/src/vs/workbench/contrib/chat/browser/chatWidget.ts +++ b/src/vs/workbench/contrib/chat/browser/chatWidget.ts @@ -3,13 +3,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { alert } from 'vs/base/browser/ui/aria/aria'; import * as dom from 'vs/base/browser/dom'; +import { alert } from 'vs/base/browser/ui/aria/aria'; import { ITreeContextMenuEvent, ITreeElement } from 'vs/base/browser/ui/tree/tree'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter } from 'vs/base/common/event'; import { Disposable, DisposableStore, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { isEqual } from 'vs/base/common/resources'; +import { withNullAsUndefined } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import 'vs/css!./media/chat'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -23,16 +24,16 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle import { WorkbenchObjectTree } from 'vs/platform/list/browser/listService'; import { IViewsService } from 'vs/workbench/common/views'; import { clearChatSession } from 'vs/workbench/contrib/chat/browser/actions/chatClear'; -import { IChatCodeBlockInfo, IChatWidget, IChatWidgetService, IChatWidgetViewContext } from 'vs/workbench/contrib/chat/browser/chat'; +import { ChatTreeItem, IChatCodeBlockInfo, IChatWidget, IChatWidgetService, IChatWidgetViewContext } from 'vs/workbench/contrib/chat/browser/chat'; import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart'; -import { IChatRendererDelegate, ChatListItemRenderer, ChatAccessibilityProvider, ChatListDelegate, ChatTreeItem } from 'vs/workbench/contrib/chat/browser/chatListRenderer'; +import { ChatAccessibilityProvider, ChatListDelegate, ChatListItemRenderer, IChatRendererDelegate } from 'vs/workbench/contrib/chat/browser/chatListRenderer'; import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions'; import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane'; import { CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_SESSION } from 'vs/workbench/contrib/chat/common/chatContextKeys'; import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService'; import { IChatModel } from 'vs/workbench/contrib/chat/common/chatModel'; import { IChatReplyFollowup, IChatService, ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService'; -import { IChatResponseViewModel, ChatViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel'; +import { ChatViewModel, IChatResponseViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel'; const $ = dom.$; @@ -370,6 +371,14 @@ export class ChatWidget extends Disposable implements IChatWidget { } } + getFocus(): ChatTreeItem | undefined { + return withNullAsUndefined(this.tree.getFocus()[0]); + } + + reveal(item: ChatTreeItem): void { + this.tree.reveal(item); + } + async acceptInput(query?: string | IChatReplyFollowup): Promise { if (this.viewModel) { const editorValue = this.inputPart.inputEditor.getValue();