Skip to content

Commit 9c534ef

Browse files
committed
start on accessible chat view
1 parent 23b487b commit 9c534ef

File tree

5 files changed

+84
-4
lines changed

5 files changed

+84
-4
lines changed

src/vs/workbench/contrib/accessibility/browser/accessibility.contribution.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,5 @@ class EditorAccessibilityHelpContribution extends Disposable {
132132

133133
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
134134
workbenchRegistry.registerWorkbenchContribution(EditorAccessibilityHelpContribution, LifecyclePhase.Eventually);
135+
136+

src/vs/workbench/contrib/accessibility/browser/accessibilityContribution.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,17 @@ export const AccessibilityHelpAction = registerCommand(new MultiCommand({
7979
}
8080
}
8181
}));
82+
83+
84+
export const AccessibilityViewAction = registerCommand(new MultiCommand({
85+
id: 'editor.action.accessibilityView',
86+
precondition: undefined,
87+
kbOpts: {
88+
primary: KeyMod.Alt | KeyCode.F2,
89+
weight: KeybindingWeight.WorkbenchContrib,
90+
linux: {
91+
primary: KeyMod.Alt | KeyMod.Shift | KeyCode.F1,
92+
secondary: [KeyMod.Alt | KeyCode.F1]
93+
}
94+
}
95+
}));

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

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { registerChatExecuteActions } from 'vs/workbench/contrib/chat/browser/ac
2222
import { registerChatQuickQuestionActions } from 'vs/workbench/contrib/chat/browser/actions/chatQuickInputActions';
2323
import { registerChatTitleActions } from 'vs/workbench/contrib/chat/browser/actions/chatTitleActions';
2424
import { registerChatExportActions } from 'vs/workbench/contrib/chat/browser/actions/chatImportExport';
25-
import { IChatAccessibilityService, IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
25+
import { IChatAccessibilityService, IChatWidget, IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
2626
import { ChatContributionService } from 'vs/workbench/contrib/chat/browser/chatContributionServiceImpl';
2727
import { ChatEditor, IChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatEditor';
2828
import { ChatEditorInput, ChatEditorInputSerializer } from 'vs/workbench/contrib/chat/browser/chatEditorInput';
@@ -37,6 +37,12 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle
3737
import '../common/chatColors';
3838
import { registerMoveActions } from 'vs/workbench/contrib/chat/browser/actions/chatMoveActions';
3939
import { registerClearActions } from 'vs/workbench/contrib/chat/browser/actions/chatClearActions';
40+
import { AccessibilityViewAction } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
41+
import { IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
42+
import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';
43+
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
44+
import { IChatResponseViewModel, isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
45+
import { KeyCode } from 'vs/base/common/keyCodes';
4046

4147
// Register configuration
4248
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
@@ -119,8 +125,58 @@ class ChatResolverContribution extends Disposable {
119125
}
120126
}
121127

128+
class ChatAccessibileViewContribution extends Disposable {
129+
static ID: 'chatAccessibleViewContribution';
130+
constructor() {
131+
super();
132+
this._register(AccessibilityViewAction.addImplementation(100, 'chat', accessor => {
133+
const accessibleViewService = accessor.get(IAccessibleViewService);
134+
const codeEditorService = accessor.get(ICodeEditorService);
135+
const editor = codeEditorService.getActiveCodeEditor() || codeEditorService.getFocusedCodeEditor();
136+
const editorUri = editor?.getModel()?.uri;
137+
const widgetService = accessor.get(IChatWidgetService);
138+
const widget: IChatWidget | undefined = widgetService.lastFocusedWidget;
139+
const focused = widget?.getFocus();
140+
if (!widget || !focused) {
141+
return false;
142+
}
143+
function provideContent(): string {
144+
if (!widget) {
145+
return 'No response data';
146+
}
147+
const curCodeBlockInfo = editorUri ? widget.getCodeBlockInfoForEditor(editorUri) : undefined;
148+
149+
const currentResponse = curCodeBlockInfo ?
150+
curCodeBlockInfo.element :
151+
(focused ?? widget.viewModel?.getItems().reverse().find((item): item is IChatResponseViewModel => isResponseVM(item)));
152+
if (!currentResponse) {
153+
return 'No response data';
154+
}
155+
// TODO: allow this for requests
156+
return isResponseVM(currentResponse) ? currentResponse.response.value : 'No response data';
157+
}
158+
accessibleViewService.registerProvider({
159+
id: 'chat',
160+
provideContent,
161+
onClose() {
162+
widget.reveal(focused, true);
163+
},
164+
onKeyDown(e: IKeyboardEvent) {
165+
if (e.keyCode === KeyCode.Escape) {
166+
widget.reveal(focused, true);
167+
}
168+
},
169+
options: { ariaLabel: nls.localize('chatAccessibleView', "Chat Accessible View") }
170+
});
171+
accessibleViewService.show('chat');
172+
return true;
173+
}));
174+
}
175+
}
176+
122177
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
123178
workbenchContributionsRegistry.registerWorkbenchContribution(ChatResolverContribution, LifecyclePhase.Starting);
179+
workbenchContributionsRegistry.registerWorkbenchContribution(ChatAccessibileViewContribution, LifecyclePhase.Eventually);
124180
Registry.as<IEditorFactoryRegistry>(EditorExtensions.EditorFactory).registerEditorSerializer(ChatEditorInput.TypeID, ChatEditorInputSerializer);
125181

126182
registerChatActions();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export interface IChatWidget {
5454
readonly inputEditor: ICodeEditor;
5555
readonly providerId: string;
5656

57-
reveal(item: ChatTreeItem): void;
57+
reveal(item: ChatTreeItem, focus?: boolean): void;
5858
getFocus(): ChatTreeItem | undefined;
5959
acceptInput(query?: string): void;
6060
focusLastMessage(): void;

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,16 @@ export class ChatWidget extends Disposable implements IChatWidget {
376376
return withNullAsUndefined(this.tree.getFocus()[0]);
377377
}
378378

379-
reveal(item: ChatTreeItem): void {
380-
this.tree.reveal(item);
379+
reveal(item: ChatTreeItem, focus?: boolean): void {
380+
if (focus) {
381+
const itemToFocus = this.tree.getNode(null).children.find(i => i.element?.id === item.id);
382+
if (!itemToFocus) {
383+
return;
384+
}
385+
this.tree.setFocus([itemToFocus.element]);
386+
} else {
387+
this.tree.reveal(item);
388+
}
381389
}
382390

383391
async acceptInput(query?: string | IChatReplyFollowup): Promise<void> {

0 commit comments

Comments
 (0)