mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
Merge pull request #188318 from microsoft/merogge/accessible-view-hint
add accessible view hint, next/previous iterations through chat responses, hint about navigating through notifications/chat responses
This commit is contained in:
@@ -25,6 +25,8 @@ import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { IntervalCounter } from 'vs/base/common/async';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { NotificationsToastsVisibleContext } from 'vs/workbench/common/contextkeys';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
interface INotificationToast {
|
||||
readonly item: INotificationViewItem;
|
||||
@@ -83,7 +85,9 @@ export class NotificationsToasts extends Themable implements INotificationsToast
|
||||
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@ILifecycleService private readonly lifecycleService: ILifecycleService,
|
||||
@IHostService private readonly hostService: IHostService
|
||||
@IHostService private readonly hostService: IHostService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService
|
||||
) {
|
||||
super(themeService);
|
||||
|
||||
@@ -187,11 +191,24 @@ export class NotificationsToasts extends Themable implements INotificationsToast
|
||||
const notificationList = this.instantiationService.createInstance(NotificationsList, notificationToast, {
|
||||
verticalScrollMode: ScrollbarVisibility.Hidden,
|
||||
widgetAriaLabel: (() => {
|
||||
if (!item.source) {
|
||||
return localize('notificationAriaLabel', "{0}, notification", item.message.raw);
|
||||
let accessibleViewHint: string | undefined;
|
||||
const keybinding = this._keybindingService.lookupKeybinding('editor.action.accessibleView')?.getAriaLabel();
|
||||
if (this._configurationService.getValue('accessibility.verbosity.notification')) {
|
||||
accessibleViewHint = keybinding ? localize('chatAccessibleViewHint', "Inspect the response in the accessible view with {0}", keybinding) : localize('chatAccessibleViewHintNoKb', "Inspect the response in the accessible view via the command Open Accessible View which is currently not triggerable via keybinding");
|
||||
}
|
||||
|
||||
return localize('notificationWithSourceAriaLabel', "{0}, source: {1}, notification", item.message.raw, item.source);
|
||||
if (!item.source) {
|
||||
if (accessibleViewHint) {
|
||||
return localize('notificationAriaLabelViewHint', "{0}, notification {1}", item.message.raw, accessibleViewHint);
|
||||
} else {
|
||||
return localize('notificationAriaLabel', "{0}, notification", item.message.raw);
|
||||
}
|
||||
}
|
||||
if (accessibleViewHint) {
|
||||
return localize('notificationWithSourceAriaLabelViewHint', "{0}, source: {1}, notification {2}", item.message.raw, item.source, accessibleViewHint);
|
||||
} else {
|
||||
return localize('notificationWithSourceAriaLabel', "{0}, source: {1}, notification", item.message.raw, item.source);
|
||||
}
|
||||
})()
|
||||
});
|
||||
itemDisposables.add(notificationList);
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/b
|
||||
import { localize } from 'vs/nls';
|
||||
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { AccessibilityHelpAction, AccessibleViewAction, AccessibleViewNextAction, AccessibleViewPreviousAction, registerAccessibilityConfiguration } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
import { AccessibilityHelpAction, AccessibilityVerbositySettingId, AccessibleViewAction, AccessibleViewNextAction, AccessibleViewPreviousAction, registerAccessibilityConfiguration } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
@@ -36,7 +36,7 @@ class AccessibilityHelpProvider implements IAccessibleContentProvider {
|
||||
this._editor.focus();
|
||||
}
|
||||
options: IAccessibleViewOptions = { type: AccessibleViewType.HelpMenu, ariaLabel: localize('editor-help', "editor accessibility help"), readMoreUrl: 'https://go.microsoft.com/fwlink/?linkid=851010' };
|
||||
verbositySettingKey: string = 'editor';
|
||||
verbositySettingKey = AccessibilityVerbositySettingId.Editor;
|
||||
constructor(
|
||||
private readonly _editor: ICodeEditor,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService
|
||||
@@ -118,7 +118,7 @@ class HoverAccessibleViewContribution extends Disposable {
|
||||
return false;
|
||||
}
|
||||
accessibleViewService.show({
|
||||
verbositySettingKey: 'hover',
|
||||
verbositySettingKey: AccessibilityVerbositySettingId.Hover,
|
||||
provideContent() { return editorHoverContent; },
|
||||
onClose() { },
|
||||
options: this._options
|
||||
@@ -135,7 +135,7 @@ class HoverAccessibleViewContribution extends Disposable {
|
||||
return false;
|
||||
}
|
||||
accessibleViewService.show({
|
||||
verbositySettingKey: 'hover',
|
||||
verbositySettingKey: AccessibilityVerbositySettingId.Hover,
|
||||
provideContent() { return extensionHoverContent; },
|
||||
onClose() { },
|
||||
options: this._options
|
||||
@@ -208,7 +208,7 @@ class NotificationAccessibleViewContribution extends Disposable {
|
||||
list.focusPrevious();
|
||||
renderAccessibleView();
|
||||
},
|
||||
verbositySettingKey: 'notifications',
|
||||
verbositySettingKey: AccessibilityVerbositySettingId.Notification,
|
||||
options: {
|
||||
ariaLabel: localize('notification', "Notification Accessible View"),
|
||||
type: AccessibleViewType.View
|
||||
|
||||
@@ -17,7 +17,10 @@ export const enum AccessibilityVerbositySettingId {
|
||||
Chat = 'accessibility.verbosity.panelChat',
|
||||
InlineChat = 'accessibility.verbosity.inlineChat',
|
||||
KeybindingsEditor = 'accessibility.verbosity.keybindingsEditor',
|
||||
Notebook = 'accessibility.verbosity.notebook'
|
||||
Notebook = 'accessibility.verbosity.notebook',
|
||||
Editor = 'accessibility.verbosity.editor',
|
||||
Hover = 'accessibility.verbosity.hover',
|
||||
Notification = 'accessibility.verbosity.notification'
|
||||
}
|
||||
|
||||
const baseProperty: object = {
|
||||
@@ -54,6 +57,14 @@ const configuration: IConfigurationNode = {
|
||||
[AccessibilityVerbositySettingId.Notebook]: {
|
||||
description: localize('verbosity.notebook', 'Provide information about how to focus the cell container or inner editor when a notebook cell is focused.'),
|
||||
...baseProperty
|
||||
},
|
||||
[AccessibilityVerbositySettingId.Hover]: {
|
||||
description: localize('verbosity.hover', 'Provide information about how to open the hover in an accessible view.'),
|
||||
...baseProperty
|
||||
},
|
||||
[AccessibilityVerbositySettingId.Notification]: {
|
||||
description: localize('verbosity.notification', 'Provide information about how to open the notification in an accessible view.'),
|
||||
...baseProperty
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -118,7 +129,7 @@ export const AccessibleViewNextAction = registerCommand(new MultiCommand({
|
||||
menuOpts: [{
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: localize('editor.action.accessibleViewNext', "Next Accessible View"),
|
||||
title: localize('editor.action.accessibleViewNext', "Show Next in Accessible View"),
|
||||
order: 1
|
||||
}],
|
||||
}));
|
||||
@@ -133,7 +144,7 @@ export const AccessibleViewPreviousAction = registerCommand(new MultiCommand({
|
||||
menuOpts: [{
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: localize('editor.action.accessibleViewPrevious', "Previous Accessible View"),
|
||||
title: localize('editor.action.accessibleViewPrevious', "Show Previous in Accessible View"),
|
||||
order: 1
|
||||
}],
|
||||
}));
|
||||
|
||||
@@ -25,6 +25,8 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
|
||||
import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { AccessibilityVerbositySettingId, AccessibleViewAction, AccessibleViewNextAction } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
|
||||
const enum DEFAULT {
|
||||
WIDTH = 800,
|
||||
@@ -32,7 +34,7 @@ const enum DEFAULT {
|
||||
}
|
||||
|
||||
export interface IAccessibleContentProvider {
|
||||
verbositySettingKey: string;
|
||||
verbositySettingKey: AccessibilityVerbositySettingId;
|
||||
provideContent(): string;
|
||||
onClose(): void;
|
||||
onKeyDown?(e: IKeyboardEvent): void;
|
||||
@@ -48,6 +50,7 @@ export interface IAccessibleViewService {
|
||||
show(provider: IAccessibleContentProvider): void;
|
||||
next(): void;
|
||||
previous(): void;
|
||||
getOpenAriaHint(verbositySettingKey: AccessibilityVerbositySettingId): string;
|
||||
}
|
||||
|
||||
export const enum AccessibleViewType {
|
||||
@@ -79,7 +82,8 @@ class AccessibleView extends Disposable {
|
||||
@IModelService private readonly _modelService: IModelService,
|
||||
@IContextViewService private readonly _contextViewService: IContextViewService,
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService
|
||||
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService
|
||||
) {
|
||||
super();
|
||||
this._accessiblityHelpIsShown = accessibilityHelpIsShown.bindTo(this._contextKeyService);
|
||||
@@ -169,7 +173,7 @@ class AccessibleView extends Disposable {
|
||||
? AccessibilityHelpNLS.changeConfigToOnMac
|
||||
: AccessibilityHelpNLS.changeConfigToOnWinLinux
|
||||
);
|
||||
if (accessibilitySupport && provider.verbositySettingKey === 'editor') {
|
||||
if (accessibilitySupport && provider.verbositySettingKey === AccessibilityVerbositySettingId.Editor) {
|
||||
message = AccessibilityHelpNLS.auto_on;
|
||||
message += '\n';
|
||||
} else if (!accessibilitySupport) {
|
||||
@@ -193,7 +197,7 @@ class AccessibleView extends Disposable {
|
||||
model.setLanguage(provider.options.language);
|
||||
}
|
||||
container.appendChild(this._editorContainer);
|
||||
this._editorWidget.updateOptions({ ariaLabel: provider.options.ariaLabel });
|
||||
this._editorWidget.updateOptions({ ariaLabel: provider.next && provider.previous ? localize('accessibleViewAriaLabelWithNav', "{0} {1}", provider.options.ariaLabel, this._getNavigationAriaHint(provider.verbositySettingKey)) : localize('accessibleViewAriaLabel', "{0}", provider.options.ariaLabel) });
|
||||
this._editorWidget.focus();
|
||||
});
|
||||
const disposableStore = new DisposableStore();
|
||||
@@ -235,6 +239,16 @@ class AccessibleView extends Disposable {
|
||||
}
|
||||
return this._modelService.createModel(resource.fragment, null, resource, false);
|
||||
}
|
||||
|
||||
private _getNavigationAriaHint(verbositySettingKey: AccessibilityVerbositySettingId): string {
|
||||
let hint = '';
|
||||
const nextKeybinding = this._keybindingService.lookupKeybinding(AccessibleViewNextAction.id)?.getAriaLabel();
|
||||
const previousKeybinding = this._keybindingService.lookupKeybinding(AccessibleViewNextAction.id)?.getAriaLabel();
|
||||
if (this._configurationService.getValue(verbositySettingKey)) {
|
||||
hint = (nextKeybinding && previousKeybinding) ? localize('chatAccessibleViewNextPreviousHint', "Show the next {0} or previous {1} item in the accessible view", nextKeybinding, previousKeybinding) : localize('chatAccessibleViewNextPreviousHintNoKb', "Show the next or previous item in the accessible view by configuring keybindings for Show Next / Previous in Accessible View");
|
||||
}
|
||||
return hint;
|
||||
}
|
||||
}
|
||||
|
||||
export class AccessibleViewService extends Disposable implements IAccessibleViewService {
|
||||
@@ -242,7 +256,9 @@ export class AccessibleViewService extends Disposable implements IAccessibleView
|
||||
private _accessibleView: AccessibleView | undefined;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IKeybindingService private readonly _keybindingService: IKeybindingService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -259,4 +275,12 @@ export class AccessibleViewService extends Disposable implements IAccessibleView
|
||||
previous(): void {
|
||||
this._accessibleView?.previous();
|
||||
}
|
||||
getOpenAriaHint(verbositySettingKey: AccessibilityVerbositySettingId): string {
|
||||
let hint = '';
|
||||
const keybinding = this._keybindingService.lookupKeybinding(AccessibleViewAction.id)?.getAriaLabel();
|
||||
if (this._configurationService.getValue(verbositySettingKey)) {
|
||||
hint = keybinding ? localize('chatAccessibleViewHint', "Inspect the response in the accessible view with {0}", keybinding) : localize('chatAccessibleViewHintNoKb', "Inspect the response in the accessible view via the command Open Accessible View which is currently not triggerable via keybinding");
|
||||
}
|
||||
return hint;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
import { IChatWidgetService } from 'vs/workbench/contrib/chat/browser/chat';
|
||||
import { InlineChatController } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
|
||||
import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
|
||||
export function getAccessibilityHelpText(accessor: ServicesAccessor, type: 'panelChat' | 'inlineChat'): string {
|
||||
const keybindingService = accessor.get(IKeybindingService);
|
||||
@@ -70,7 +71,7 @@ export async function runAccessibilityHelpAction(accessor: ServicesAccessor, edi
|
||||
inputEditor.getSupportedActions();
|
||||
const helpText = getAccessibilityHelpText(accessor, type);
|
||||
accessibleViewService.show({
|
||||
verbositySettingKey: type,
|
||||
verbositySettingKey: type as AccessibilityVerbositySettingId,
|
||||
provideContent: () => helpText,
|
||||
onClose: () => {
|
||||
if (type === 'panelChat' && cachedPosition) {
|
||||
|
||||
@@ -37,7 +37,7 @@ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle
|
||||
import '../common/chatColors';
|
||||
import { registerMoveActions } from 'vs/workbench/contrib/chat/browser/actions/chatMoveActions';
|
||||
import { registerClearActions } from 'vs/workbench/contrib/chat/browser/actions/chatClearActions';
|
||||
import { AccessibleViewAction } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
import { AccessibilityVerbositySettingId, AccessibleViewAction } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||
import { isResponseVM } from 'vs/workbench/contrib/chat/common/chatViewModel';
|
||||
import { CONTEXT_IN_CHAT_SESSION } from 'vs/workbench/contrib/chat/common/chatContextKeys';
|
||||
@@ -135,48 +135,61 @@ class ChatAccessibleViewContribution extends Disposable {
|
||||
const accessibleViewService = accessor.get(IAccessibleViewService);
|
||||
const widgetService = accessor.get(IChatWidgetService);
|
||||
const codeEditorService = accessor.get(ICodeEditorService);
|
||||
return renderAccessibleView(accessibleViewService, widgetService, codeEditorService, true);
|
||||
function renderAccessibleView(accessibleViewService: IAccessibleViewService, widgetService: IChatWidgetService, codeEditorService: ICodeEditorService, initialRender?: boolean): boolean {
|
||||
let widget = widgetService.lastFocusedWidget;
|
||||
if (!widget) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let widget = widgetService.lastFocusedWidget;
|
||||
if (!widget) {
|
||||
return false;
|
||||
const chatInputFocused = initialRender && !!(codeEditorService.getActiveCodeEditor() || codeEditorService.getFocusedCodeEditor());
|
||||
|
||||
if (chatInputFocused) {
|
||||
widget.focusLastMessage();
|
||||
widget = widgetService.lastFocusedWidget;
|
||||
}
|
||||
|
||||
if (!widget) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const verifiedWidget: IChatWidget = widget;
|
||||
const focusedItem = verifiedWidget.getFocus();
|
||||
|
||||
if (!focusedItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
widget.focus(focusedItem);
|
||||
|
||||
const responseContent = isResponseVM(focusedItem) ? focusedItem.response.value : undefined;
|
||||
if (!responseContent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
accessibleViewService.show({
|
||||
verbositySettingKey: AccessibilityVerbositySettingId.Chat,
|
||||
provideContent(): string { return responseContent; },
|
||||
onClose() {
|
||||
if (chatInputFocused) {
|
||||
verifiedWidget.focusInput();
|
||||
} else {
|
||||
verifiedWidget.reveal(focusedItem);
|
||||
verifiedWidget.focus(focusedItem);
|
||||
}
|
||||
},
|
||||
next() {
|
||||
verifiedWidget.moveFocus(focusedItem, 'next');
|
||||
renderAccessibleView(accessibleViewService, widgetService, codeEditorService);
|
||||
},
|
||||
previous() {
|
||||
verifiedWidget.moveFocus(focusedItem, 'previous');
|
||||
renderAccessibleView(accessibleViewService, widgetService, codeEditorService);
|
||||
},
|
||||
options: { ariaLabel: nls.localize('chatAccessibleView', "Chat Accessible View"), language: 'typescript', type: AccessibleViewType.View }
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
const chatInputFocused = !!(codeEditorService.getActiveCodeEditor() || codeEditorService.getFocusedCodeEditor());
|
||||
|
||||
if (chatInputFocused) {
|
||||
widget.focusLastMessage();
|
||||
widget = widgetService.lastFocusedWidget;
|
||||
}
|
||||
|
||||
if (!widget) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const verifiedWidget: IChatWidget = widget;
|
||||
const focusedItem = verifiedWidget.getFocus();
|
||||
|
||||
if (!focusedItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const responseContent = isResponseVM(focusedItem) ? focusedItem.response.value : undefined;
|
||||
if (!responseContent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
accessibleViewService.show({
|
||||
verbositySettingKey: 'panelChat',
|
||||
provideContent(): string { return responseContent; },
|
||||
onClose() {
|
||||
if (chatInputFocused) {
|
||||
verifiedWidget.focusInput();
|
||||
} else {
|
||||
verifiedWidget.focus(focusedItem);
|
||||
}
|
||||
},
|
||||
options: { ariaLabel: nls.localize('chatAccessibleView', "Chat Accessible View"), language: 'typescript', type: AccessibleViewType.View }
|
||||
});
|
||||
return true;
|
||||
}, CONTEXT_IN_CHAT_SESSION));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ export interface IChatWidget {
|
||||
|
||||
reveal(item: ChatTreeItem): void;
|
||||
focus(item: ChatTreeItem): void;
|
||||
moveFocus(item: ChatTreeItem, type: 'next' | 'previous'): void;
|
||||
getFocus(): ChatTreeItem | undefined;
|
||||
acceptInput(query?: string): void;
|
||||
focusLastMessage(): void;
|
||||
|
||||
@@ -50,6 +50,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles';
|
||||
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
import { IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||
import { IChatCodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/actions/chatCodeblockActions';
|
||||
import { ChatTreeItem, IChatCodeBlockInfo } from 'vs/workbench/contrib/chat/browser/chat';
|
||||
import { ChatFollowups } from 'vs/workbench/contrib/chat/browser/chatFollowups';
|
||||
@@ -517,6 +518,12 @@ export class ChatListDelegate implements IListVirtualDelegate<ChatTreeItem> {
|
||||
}
|
||||
|
||||
export class ChatAccessibilityProvider implements IListAccessibilityProvider<ChatTreeItem> {
|
||||
|
||||
constructor(
|
||||
@IAccessibleViewService private readonly _accessibleViewService: IAccessibleViewService
|
||||
) {
|
||||
|
||||
}
|
||||
getWidgetRole(): AriaRole {
|
||||
return 'list';
|
||||
}
|
||||
@@ -546,15 +553,21 @@ export class ChatAccessibilityProvider implements IListAccessibilityProvider<Cha
|
||||
}
|
||||
|
||||
private _getLabelWithCodeBlockCount(element: IChatResponseViewModel): string {
|
||||
const accessibleViewHint = this._accessibleViewService.getOpenAriaHint(AccessibilityVerbositySettingId.Chat).trim();
|
||||
let label: string = '';
|
||||
const codeBlockCount = marked.lexer(element.response.value).filter(token => token.type === 'code')?.length ?? 0;
|
||||
switch (codeBlockCount) {
|
||||
case 0:
|
||||
return element.response.value;
|
||||
label = localize('noCodeBlocks', "{0} {1}", element.response.value, accessibleViewHint);
|
||||
break;
|
||||
case 1:
|
||||
return localize('singleCodeBlock', "1 code block: {0}", element.response.value);
|
||||
label = localize('singleCodeBlock', "1 code block: {0} {1}", element.response.value, accessibleViewHint);
|
||||
break;
|
||||
default:
|
||||
return localize('multiCodeBlock', "{0} code blocks: {1}", codeBlockCount, element.response.value);
|
||||
label = localize('multiCodeBlock', "{0} code blocks: {1}", codeBlockCount, element.response.value, accessibleViewHint);
|
||||
break;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,8 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||
@IChatService private readonly chatService: IChatService,
|
||||
@IChatWidgetService chatWidgetService: IChatWidgetService,
|
||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||
@IChatAccessibilityService private readonly _chatAccessibilityService: IChatAccessibilityService
|
||||
@IChatAccessibilityService private readonly _chatAccessibilityService: IChatAccessibilityService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
CONTEXT_IN_CHAT_SESSION.bindTo(contextKeyService).set(true);
|
||||
@@ -177,6 +178,23 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||
this.inputPart.focus();
|
||||
}
|
||||
|
||||
moveFocus(item: ChatTreeItem, type: 'next' | 'previous'): void {
|
||||
const items = this.viewModel?.getItems();
|
||||
if (!items) {
|
||||
return;
|
||||
}
|
||||
const responseItems = items.filter(i => isResponseVM(i));
|
||||
const targetIndex = responseItems.indexOf(item);
|
||||
if (targetIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
const indexToFocus = type === 'next' ? targetIndex + 1 : targetIndex - 1;
|
||||
if (indexToFocus < 0 || indexToFocus === responseItems.length - 1) {
|
||||
return;
|
||||
}
|
||||
this.focus(responseItems[indexToFocus]);
|
||||
}
|
||||
|
||||
private onDidChangeItems() {
|
||||
if (this.tree && this.visible) {
|
||||
const treeItems = (this.viewModel?.getItems() ?? [])
|
||||
@@ -288,7 +306,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
|
||||
horizontalScrolling: false,
|
||||
supportDynamicHeights: true,
|
||||
hideTwistiesOfChildlessElements: true,
|
||||
accessibilityProvider: new ChatAccessibilityProvider(),
|
||||
accessibilityProvider: this._instantiationService.createInstance(ChatAccessibilityProvider),
|
||||
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: ChatTreeItem) => isRequestVM(e) ? e.message : isResponseVM(e) ? e.response.value : '' }, // TODO
|
||||
setRowLineHeight: false,
|
||||
overrideStyles: {
|
||||
|
||||
@@ -17,7 +17,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { FloatingClickWidget } from 'vs/workbench/browser/codeeditor';
|
||||
import { AccessibilityHelpAction } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
import { AccessibilityHelpAction, AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||
import { localize } from 'vs/nls';
|
||||
@@ -101,7 +101,7 @@ function createScreenReaderHelp(): IDisposable {
|
||||
const keys = ['audioCues.diffLineDeleted', 'audioCues.diffLineInserted', 'audioCues.diffLineModified'];
|
||||
|
||||
accessibleViewService.show({
|
||||
verbositySettingKey: 'diffEditor',
|
||||
verbositySettingKey: AccessibilityVerbositySettingId.DiffEditor,
|
||||
provideContent: () => [
|
||||
localize('msg1', "You are in a diff editor."),
|
||||
localize('msg2', "Press {0} or {1} to view the next or previous diff in the diff review mode that is optimized for screen readers.", next, previous),
|
||||
|
||||
@@ -9,6 +9,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||
import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
|
||||
export function getAccessibilityHelpText(accessor: ServicesAccessor): string {
|
||||
const keybindingService = accessor.get(IKeybindingService);
|
||||
@@ -46,7 +47,7 @@ export async function runAccessibilityHelpAction(accessor: ServicesAccessor, edi
|
||||
const accessibleViewService = accessor.get(IAccessibleViewService);
|
||||
const helpText = getAccessibilityHelpText(accessor);
|
||||
accessibleViewService.show({
|
||||
verbositySettingKey: 'notebook',
|
||||
verbositySettingKey: AccessibilityVerbositySettingId.Notebook,
|
||||
provideContent: () => helpText,
|
||||
onClose: () => {
|
||||
editor.focus();
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ import { IAccessibilityService } from 'vs/platform/accessibility/common/accessib
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ShellIntegrationStatus, WindowsShellType } from 'vs/platform/terminal/common/terminal';
|
||||
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
|
||||
import { AccessibleViewType, IAccessibleContentProvider, IAccessibleViewOptions } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
|
||||
import { ITerminalInstance, IXtermTerminal } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
@@ -34,7 +35,7 @@ export class TerminalAccessibleContentProvider extends Disposable implements IAc
|
||||
ariaLabel: localize('terminal-help-label', "terminal accessibility help"),
|
||||
readMoreUrl: 'https://code.visualstudio.com/docs/editor/accessibility#_terminal-accessibility'
|
||||
};
|
||||
verbositySettingKey: string = 'terminal';
|
||||
verbositySettingKey = AccessibilityVerbositySettingId.Terminal;
|
||||
|
||||
constructor(
|
||||
private readonly _instance: Pick<ITerminalInstance, 'shellType' | 'capabilities' | 'onDidRequestFocus' | 'resource' | 'focus'>,
|
||||
|
||||
Reference in New Issue
Block a user