Skip to content

Commit 784e72b

Browse files
authored
Improve "next codeblock" navigation (microsoft#183744)
* Improve "next codeblock" navigation Operate on the current focused response, or the last one, and scroll to the selected item * Normalize command title
1 parent b53fb02 commit 784e72b

File tree

5 files changed

+35
-21
lines changed

5 files changed

+35
-21
lines changed

src/vs/workbench/contrib/chat/browser/actions/chatCodeblockActions.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -374,15 +374,18 @@ export function registerChatCodeBlockActions() {
374374
const editor = codeEditorService.getFocusedCodeEditor();
375375
const editorUri = editor?.getModel()?.uri;
376376
const curCodeBlockInfo = editorUri ? widget.getCodeBlockInfoForEditor(editorUri) : undefined;
377+
const focused = !widget.inputEditor.hasWidgetFocus() && widget.getFocus();
378+
const focusedResponse = isResponseVM(focused) ? focused : undefined;
377379

378-
const focusResponse = curCodeBlockInfo ?
380+
const currentResponse = curCodeBlockInfo ?
379381
curCodeBlockInfo.element :
380-
widget.viewModel?.getItems().reverse().find((item): item is IChatResponseViewModel => isResponseVM(item));
381-
if (!focusResponse) {
382+
(focusedResponse ?? widget.viewModel?.getItems().reverse().find((item): item is IChatResponseViewModel => isResponseVM(item)));
383+
if (!currentResponse) {
382384
return;
383385
}
384386

385-
const responseCodeblocks = widget.getCodeBlockInfosForResponse(focusResponse);
387+
widget.reveal(currentResponse);
388+
const responseCodeblocks = widget.getCodeBlockInfosForResponse(currentResponse);
386389
const focusIdx = curCodeBlockInfo ?
387390
(curCodeBlockInfo.codeBlockIndex + (reverse ? -1 : 1) + responseCodeblocks.length) % responseCodeblocks.length :
388391
reverse ? responseCodeblocks.length - 1 : 0;

src/vs/workbench/contrib/chat/browser/actions/chatMoveActions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
2323
const getMoveToEditorChatActionDescriptorForViewTitle = (viewId: string, providerId: string): Readonly<IAction2Options> & { viewId: string } => ({
2424
id: `workbench.action.chat.${providerId}.openInEditor`,
2525
title: {
26-
value: localize('chat.openInEditor.label', "Open In Editor"),
27-
original: 'Open In Editor'
26+
value: localize('chat.openInEditor.label', "Open Session In Editor"),
27+
original: 'Open Session In Editor'
2828
},
2929
category: CHAT_CATEGORY,
3030
precondition: CONTEXT_PROVIDER_EXISTS,

src/vs/workbench/contrib/chat/browser/chat.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
77
import { ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService';
8-
import { IChatResponseViewModel, IChatViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel';
8+
import { IChatRequestViewModel, IChatResponseViewModel, IChatViewModel, IChatWelcomeMessageViewModel } from 'vs/workbench/contrib/chat/common/chatViewModel';
99
import { Event } from 'vs/base/common/event';
1010
import { URI } from 'vs/base/common/uri';
1111
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
@@ -35,6 +35,8 @@ export interface IChatCodeBlockInfo {
3535
focus(): void;
3636
}
3737

38+
export type ChatTreeItem = IChatRequestViewModel | IChatResponseViewModel | IChatWelcomeMessageViewModel;
39+
3840
export type IChatWidgetViewContext = { viewId: string } | { resource: boolean };
3941

4042
export interface IChatWidget {
@@ -44,6 +46,8 @@ export interface IChatWidget {
4446
readonly inputEditor: ICodeEditor;
4547
readonly providerId: string;
4648

49+
reveal(item: ChatTreeItem): void;
50+
getFocus(): ChatTreeItem | undefined;
4751
acceptInput(query?: string): void;
4852
focusLastMessage(): void;
4953
focusInput(): void;

src/vs/workbench/contrib/chat/browser/chatListRenderer.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { FuzzyScore } from 'vs/base/common/filters';
1818
import { IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent';
1919
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
2020
import { ResourceMap } from 'vs/base/common/map';
21+
import { marked } from 'vs/base/common/marked/marked';
2122
import { FileAccess } from 'vs/base/common/network';
2223
import { ThemeIcon } from 'vs/base/common/themables';
2324
import { withNullAsUndefined } from 'vs/base/common/types';
@@ -37,6 +38,7 @@ import { ViewportSemanticTokensContribution } from 'vs/editor/contrib/semanticTo
3738
import { SmartSelectController } from 'vs/editor/contrib/smartSelect/browser/smartSelect';
3839
import { WordHighlighterContribution } from 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter';
3940
import { localize } from 'vs/nls';
41+
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
4042
import { IMenuEntryActionViewItemOptions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
4143
import { MenuWorkbenchToolBar } from 'vs/platform/actions/browser/toolbar';
4244
import { MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
@@ -47,25 +49,21 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
4749
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
4850
import { ILogService } from 'vs/platform/log/common/log';
4951
import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles';
50-
import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer';
51-
import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard';
52-
import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
52+
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
5353
import { IChatCodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/actions/chatCodeblockActions';
54-
import { IChatCodeBlockInfo } from 'vs/workbench/contrib/chat/browser/chat';
54+
import { ChatTreeItem, IChatCodeBlockInfo } from 'vs/workbench/contrib/chat/browser/chat';
5555
import { ChatFollowups } from 'vs/workbench/contrib/chat/browser/chatFollowups';
5656
import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions';
5757
import { CONTEXT_REQUEST, CONTEXT_RESPONSE, CONTEXT_RESPONSE_HAS_PROVIDER_ID, CONTEXT_RESPONSE_VOTE } from 'vs/workbench/contrib/chat/common/chatContextKeys';
5858
import { IChatReplyFollowup, IChatService, ISlashCommand, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
59-
import { IChatRequestViewModel, IChatResponseViewModel, IChatWelcomeMessageViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
59+
import { IChatResponseViewModel, IChatWelcomeMessageViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
6060
import { IWordCountResult, getNWords } from 'vs/workbench/contrib/chat/common/chatWordCounter';
61-
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
62-
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
63-
import { marked } from 'vs/base/common/marked/marked';
61+
import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer';
62+
import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard';
63+
import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
6464

6565
const $ = dom.$;
6666

67-
export type ChatTreeItem = IChatRequestViewModel | IChatResponseViewModel | IChatWelcomeMessageViewModel;
68-
6967
interface IChatListItemTemplate {
7068
rowContainer: HTMLElement;
7169
titleToolbar: MenuWorkbenchToolBar;

src/vs/workbench/contrib/chat/browser/chatWidget.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { alert } from 'vs/base/browser/ui/aria/aria';
76
import * as dom from 'vs/base/browser/dom';
7+
import { alert } from 'vs/base/browser/ui/aria/aria';
88
import { ITreeContextMenuEvent, ITreeElement } from 'vs/base/browser/ui/tree/tree';
99
import { CancellationToken } from 'vs/base/common/cancellation';
1010
import { Emitter } from 'vs/base/common/event';
1111
import { Disposable, DisposableStore, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle';
1212
import { isEqual } from 'vs/base/common/resources';
13+
import { withNullAsUndefined } from 'vs/base/common/types';
1314
import { URI } from 'vs/base/common/uri';
1415
import 'vs/css!./media/chat';
1516
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
@@ -23,16 +24,16 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
2324
import { WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
2425
import { IViewsService } from 'vs/workbench/common/views';
2526
import { clearChatSession } from 'vs/workbench/contrib/chat/browser/actions/chatClear';
26-
import { IChatCodeBlockInfo, IChatWidget, IChatWidgetService, IChatWidgetViewContext } from 'vs/workbench/contrib/chat/browser/chat';
27+
import { ChatTreeItem, IChatCodeBlockInfo, IChatWidget, IChatWidgetService, IChatWidgetViewContext } from 'vs/workbench/contrib/chat/browser/chat';
2728
import { ChatInputPart } from 'vs/workbench/contrib/chat/browser/chatInputPart';
28-
import { IChatRendererDelegate, ChatListItemRenderer, ChatAccessibilityProvider, ChatListDelegate, ChatTreeItem } from 'vs/workbench/contrib/chat/browser/chatListRenderer';
29+
import { ChatAccessibilityProvider, ChatListDelegate, ChatListItemRenderer, IChatRendererDelegate } from 'vs/workbench/contrib/chat/browser/chatListRenderer';
2930
import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions';
3031
import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
3132
import { CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_SESSION } from 'vs/workbench/contrib/chat/common/chatContextKeys';
3233
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
3334
import { IChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
3435
import { IChatReplyFollowup, IChatService, ISlashCommand } from 'vs/workbench/contrib/chat/common/chatService';
35-
import { IChatResponseViewModel, ChatViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
36+
import { ChatViewModel, IChatResponseViewModel, isRequestVM, isResponseVM, isWelcomeVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
3637

3738
const $ = dom.$;
3839

@@ -370,6 +371,14 @@ export class ChatWidget extends Disposable implements IChatWidget {
370371
}
371372
}
372373

374+
getFocus(): ChatTreeItem | undefined {
375+
return withNullAsUndefined(this.tree.getFocus()[0]);
376+
}
377+
378+
reveal(item: ChatTreeItem): void {
379+
this.tree.reveal(item);
380+
}
381+
373382
async acceptInput(query?: string | IChatReplyFollowup): Promise<void> {
374383
if (this.viewModel) {
375384
const editorValue = this.inputPart.inputEditor.getValue();

0 commit comments

Comments
 (0)