Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resolve accessibility help dialog kbs in accessibleViewService #213107

Merged
merged 5 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/vs/editor/common/standaloneStrings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,14 @@ export namespace AccessibilityHelpNLS {
export const auto_off = nls.localize("auto_off", "The application is configured to never be optimized for usage with a Screen Reader.");
export const screenReaderModeEnabled = nls.localize("screenReaderModeEnabled", "Screen Reader Optimized Mode enabled.");
export const screenReaderModeDisabled = nls.localize("screenReaderModeDisabled", "Screen Reader Optimized Mode disabled.");
export const tabFocusModeOnMsg = nls.localize("tabFocusModeOnMsg", "Pressing Tab in the current editor will move focus to the next focusable element. Toggle this behavior {0}.");
export const tabFocusModeOnMsgNoKb = nls.localize("tabFocusModeOnMsgNoKb", "Pressing Tab in the current editor will move focus to the next focusable element. The command {0} is currently not triggerable by a keybinding.");
export const stickScrollKb = nls.localize("stickScrollKb", "Focus Sticky Scroll ({0}) to focus the currently nested scopes.");
export const stickScrollNoKb = nls.localize("stickScrollNoKb", "Focus Sticky Scroll to focus the currently nested scopes. It is currently not triggerable by a keybinding.");
export const tabFocusModeOffMsg = nls.localize("tabFocusModeOffMsg", "Pressing Tab in the current editor will insert the tab character. Toggle this behavior {0}.");
export const tabFocusModeOffMsgNoKb = nls.localize("tabFocusModeOffMsgNoKb", "Pressing Tab in the current editor will insert the tab character. The command {0} is currently not triggerable by a keybinding.");
export const tabFocusModeOnMsg = nls.localize("tabFocusModeOnMsg", "Pressing Tab in the current editor will move focus to the next focusable element. Toggle this behavior<keybinding:editor.action.toggleTabFocusMode>");
export const tabFocusModeOffMsg = nls.localize("tabFocusModeOffMsg", "Pressing Tab in the current editor will insert the tab character. Toggle this behavior<keybinding:editor.action.toggleTabFocusMode>");
export const stickScroll = nls.localize("stickScrollKb", "Focus Sticky Scroll<keybinding:editor.action.focusStickyScroll> to focus the currently nested scopes.");
export const showAccessibilityHelpAction = nls.localize("showAccessibilityHelpAction", "Show Accessibility Help");
export const listSignalSounds = nls.localize("listSignalSoundsCommand", "Run the command: List Signal Sounds for an overview of all sounds and their current status.");
export const listAlerts = nls.localize("listAnnouncementsCommand", "Run the command: List Signal Announcements for an overview of announcements and their current status.");
export const quickChat = nls.localize("quickChatCommand", "Toggle quick chat ({0}) to open or close a chat session.");
export const quickChatNoKb = nls.localize("quickChatCommandNoKb", "Toggle quick chat is not currently triggerable by a keybinding.");
export const startInlineChat = nls.localize("startInlineChatCommand", "Start inline chat ({0}) to create an in editor chat session.");
export const startInlineChatNoKb = nls.localize("startInlineChatCommandNoKb", "The command: Start inline chat is not currentlyt riggerable by a keybinding.");
export const quickChat = nls.localize("quickChatCommand", "Toggle quick chat<keybinding:workbench.action.quickchat.toggle> to open or close a chat session.",);
export const startInlineChat = nls.localize("startInlineChatCommand", "Start inline chat<keybinding:inlineChat.start> to create an in editor chat session.");
}

export namespace InspectTokensNLS {
Expand Down
13 changes: 12 additions & 1 deletion src/vs/workbench/contrib/accessibility/browser/accessibleView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IQuickInputService, IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { AccessibilityVerbositySettingId, AccessibilityWorkbenchSettingId, accessibilityHelpIsShown, accessibleViewContainsCodeBlocks, accessibleViewCurrentProviderId, accessibleViewGoToSymbolSupported, accessibleViewInCodeBlock, accessibleViewIsShown, accessibleViewOnLastLine, accessibleViewSupportsNavigation, accessibleViewVerbosityEnabled } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
import { resolveContentAndKeybindingItems } from 'vs/workbench/contrib/accessibility/browser/accessibleViewKeybindingResolver';
import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands';
import { IChatCodeBlockContextProviderService } from 'vs/workbench/contrib/chat/browser/chat';
import { ICodeBlockActionContext } from 'vs/workbench/contrib/chat/browser/codeBlockPart';
Expand Down Expand Up @@ -491,7 +492,17 @@ export class AccessibleView extends Disposable {
}
}
const exitThisDialogHint = verbose && !provider.options.position ? localize('exit', '\n\nExit this dialog (Escape).') : '';
const newContent = message + provider.provideContent() + readMoreLink + disableHelpHint + exitThisDialogHint;
let content = provider.provideContent();
if (provider.options.type === AccessibleViewType.Help) {
const resolvedContent = resolveContentAndKeybindingItems(this._keybindingService, content);
if (resolvedContent) {
content = resolvedContent.content.value;
if (resolvedContent.configureKeybindingItems) {
provider.options.configureKeybindingItems = resolvedContent.configureKeybindingItems;
}
}
}
const newContent = message + content + readMoreLink + disableHelpHint + exitThisDialogHint;
this.calculateCodeBlocks(newContent);
this._currentContent = newContent;
this._updateContextKeys(provider, true);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { MarkdownString } from 'vs/base/common/htmlContent';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IPickerQuickAccessItem } from 'vs/platform/quickinput/browser/pickerQuickAccess';
import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands';

export function resolveContentAndKeybindingItems(keybindingService: IKeybindingService, value?: string): { content: MarkdownString; configureKeybindingItems: IPickerQuickAccessItem[] | undefined } | undefined {
if (!value) {
return;
}
const configureKeybindingItems: IPickerQuickAccessItem[] = [];
const matches = value.matchAll(/\<keybinding:(?<commandId>.*)\>/gm);
for (const match of [...matches]) {
const commandId = match?.groups?.commandId;
let kbLabel;
if (match?.length && commandId) {
const keybinding = keybindingService.lookupKeybinding(commandId)?.getAriaLabel();
if (!keybinding) {
const configureKb = keybindingService.lookupKeybinding(AccessibilityCommandId.AccessibilityHelpConfigureKeybindings)?.getAriaLabel();
const keybindingToConfigureQuickPick = configureKb ? '(' + configureKb + ')' : 'by assigning a keybinding to the command Accessibility Help Configure Keybindings.';
kbLabel = `, configure a keybinding ` + keybindingToConfigureQuickPick;
configureKeybindingItems.push({
label: commandId,
id: commandId
});
} else {
kbLabel = ' (' + keybinding + ')';
}
value = value.replace(match[0], kbLabel);
}
}
const content = new MarkdownString(value);
content.isTrusted = true;
return { content, configureKeybindingItems: configureKeybindingItems.length ? configureKeybindingItems : undefined };
}

Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { AccessibilityHelpNLS } from 'vs/editor/common/standaloneStrings';
import { ToggleTabFocusModeAction } from 'vs/editor/contrib/toggleTabFocusMode/browser/toggleTabFocusMode';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { descriptionForCommand } from 'vs/workbench/contrib/accessibility/browser/accessibleViewContributions';
import { AccessibilityHelpAction } from 'vs/workbench/contrib/accessibility/browser/accessibleViewActions';
import { CONTEXT_CHAT_ENABLED } from 'vs/workbench/contrib/chat/common/chatContextKeys';
import { CommentAccessibilityHelpNLS } from 'vs/workbench/contrib/comments/browser/commentsAccessibility';
import { CommentCommandId } from 'vs/workbench/contrib/comments/common/commentCommandIds';
import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys';
import { NEW_UNTITLED_FILE_COMMAND_ID } from 'vs/workbench/contrib/files/browser/fileConstants';
import { IAccessibleViewService, IAccessibleViewContentProvider, AccessibleViewProviderId, IAccessibleViewOptions, AccessibleViewType } from 'vs/platform/accessibility/browser/accessibleView';
Expand Down Expand Up @@ -88,13 +85,13 @@ class EditorAccessibilityHelpProvider implements IAccessibleViewContentProvider
}

if (options.get(EditorOption.stickyScroll).enabled) {
content.push(descriptionForCommand('editor.action.focusStickyScroll', AccessibilityHelpNLS.stickScrollKb, AccessibilityHelpNLS.stickScrollNoKb, this._keybindingService));
content.push(AccessibilityHelpNLS.stickScroll);
}

if (options.get(EditorOption.tabFocusMode)) {
content.push(descriptionForCommand(ToggleTabFocusModeAction.ID, AccessibilityHelpNLS.tabFocusModeOnMsg, AccessibilityHelpNLS.tabFocusModeOnMsgNoKb, this._keybindingService));
content.push(AccessibilityHelpNLS.tabFocusModeOnMsg);
} else {
content.push(descriptionForCommand(ToggleTabFocusModeAction.ID, AccessibilityHelpNLS.tabFocusModeOffMsg, AccessibilityHelpNLS.tabFocusModeOffMsgNoKb, this._keybindingService));
content.push(AccessibilityHelpNLS.tabFocusModeOffMsg);
}
return content.join('\n\n');
}
Expand All @@ -103,24 +100,14 @@ class EditorAccessibilityHelpProvider implements IAccessibleViewContentProvider
export function getCommentCommandInfo(keybindingService: IKeybindingService, contextKeyService: IContextKeyService, editor: ICodeEditor): string | undefined {
const editorContext = contextKeyService.getContext(editor.getDomNode()!);
if (editorContext.getValue<boolean>(CommentContextKeys.activeEditorHasCommentingRange.key)) {
const commentCommandInfo: string[] = [];
commentCommandInfo.push(CommentAccessibilityHelpNLS.intro);
commentCommandInfo.push(descriptionForCommand(CommentCommandId.Add, CommentAccessibilityHelpNLS.addComment, CommentAccessibilityHelpNLS.addCommentNoKb, keybindingService));
commentCommandInfo.push(descriptionForCommand(CommentCommandId.NextThread, CommentAccessibilityHelpNLS.nextCommentThreadKb, CommentAccessibilityHelpNLS.nextCommentThreadNoKb, keybindingService));
commentCommandInfo.push(descriptionForCommand(CommentCommandId.PreviousThread, CommentAccessibilityHelpNLS.previousCommentThreadKb, CommentAccessibilityHelpNLS.previousCommentThreadNoKb, keybindingService));
commentCommandInfo.push(descriptionForCommand(CommentCommandId.NextRange, CommentAccessibilityHelpNLS.nextRange, CommentAccessibilityHelpNLS.nextRangeNoKb, keybindingService));
commentCommandInfo.push(descriptionForCommand(CommentCommandId.PreviousRange, CommentAccessibilityHelpNLS.previousRange, CommentAccessibilityHelpNLS.previousRangeNoKb, keybindingService));
return commentCommandInfo.join('\n');
return [CommentAccessibilityHelpNLS.intro, CommentAccessibilityHelpNLS.addComment, CommentAccessibilityHelpNLS.nextCommentThread, CommentAccessibilityHelpNLS.previousCommentThread, CommentAccessibilityHelpNLS.nextRange, CommentAccessibilityHelpNLS.previousRange].join('\n');
}
return;
}

export function getChatCommandInfo(keybindingService: IKeybindingService, contextKeyService: IContextKeyService): string | undefined {
if (CONTEXT_CHAT_ENABLED.getValue(contextKeyService)) {
const commentCommandInfo: string[] = [];
commentCommandInfo.push(descriptionForCommand('workbench.action.quickchat.toggle', AccessibilityHelpNLS.quickChat, AccessibilityHelpNLS.quickChatNoKb, keybindingService));
commentCommandInfo.push(descriptionForCommand('inlineChat.start', AccessibilityHelpNLS.startInlineChat, AccessibilityHelpNLS.startInlineChatNoKb, keybindingService));
return commentCommandInfo.join('\n');
return [AccessibilityHelpNLS.quickChat, AccessibilityHelpNLS.startInlineChat].join('\n');
}
return;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { MarkdownString } from 'vs/base/common/htmlContent';
import { DisposableMap, IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { AccessibleViewType, ExtensionContentProvider } from 'vs/platform/accessibility/browser/accessibleView';
import { AccessibleViewRegistry } from 'vs/platform/accessibility/browser/accessibleViewRegistry';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IPickerQuickAccessItem } from 'vs/platform/quickinput/browser/pickerQuickAccess';
import { Registry } from 'vs/platform/registry/common/platform';
import { FocusedViewContext } from 'vs/workbench/common/contextkeys';
import { IViewsRegistry, Extensions, IViewDescriptor } from 'vs/workbench/common/views';
import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands';
import { IViewsService } from 'vs/workbench/services/views/common/viewsService';

export class ExtensionAccessibilityHelpDialogContribution extends Disposable {
Expand Down Expand Up @@ -42,9 +39,9 @@ export class ExtensionAccessibilityHelpDialogContribution extends Disposable {

function registerAccessibilityHelpAction(keybindingService: IKeybindingService, viewDescriptor: IViewDescriptor): IDisposable {
const disposableStore = new DisposableStore();
const helpContent = resolveExtensionHelpContent(keybindingService, viewDescriptor.accessibilityHelpContent);
if (!helpContent) {
throw new Error('No help content for view');
const content = viewDescriptor.accessibilityHelpContent?.value;
if (!content) {
throw new Error('No content provided for the accessibility help dialog');
}
disposableStore.add(AccessibleViewRegistry.register({
priority: 95,
Expand All @@ -55,8 +52,8 @@ function registerAccessibilityHelpAction(keybindingService: IKeybindingService,
const viewsService = accessor.get(IViewsService);
return new ExtensionContentProvider(
viewDescriptor.id,
{ type: AccessibleViewType.Help, configureKeybindingItems: helpContent.configureKeybindingItems },
() => helpContent.value.value,
{ type: AccessibleViewType.Help },
() => content,
() => viewsService.openView(viewDescriptor.id, true),
);
}
Expand All @@ -68,35 +65,3 @@ function registerAccessibilityHelpAction(keybindingService: IKeybindingService,
}));
return disposableStore;
}

function resolveExtensionHelpContent(keybindingService: IKeybindingService, content?: MarkdownString): { value: MarkdownString; configureKeybindingItems: IPickerQuickAccessItem[] | undefined } | undefined {
if (!content) {
return;
}
const configureKeybindingItems: IPickerQuickAccessItem[] = [];
let resolvedContent = typeof content === 'string' ? content : content.value;
const matches = resolvedContent.matchAll(/\<keybinding:(?<commandId>.*)\>/gm);
for (const match of [...matches]) {
const commandId = match?.groups?.commandId;
let kbLabel;
if (match?.length && commandId) {
const keybinding = keybindingService.lookupKeybinding(commandId)?.getAriaLabel();
if (!keybinding) {
const configureKb = keybindingService.lookupKeybinding(AccessibilityCommandId.AccessibilityHelpConfigureKeybindings)?.getAriaLabel();
const keybindingToConfigureQuickPick = configureKb ? '(' + configureKb + ')' : 'by assigning a keybinding to the command accessibility.openQuickPick.';
kbLabel = `, configure a keybinding ` + keybindingToConfigureQuickPick;
configureKeybindingItems.push({
label: commandId,
id: commandId
});
} else {
kbLabel = ' (' + keybinding + ')';
}
resolvedContent = resolvedContent.replace(match[0], kbLabel);
}
}
const value = new MarkdownString(resolvedContent);
value.isTrusted = true;
return { value, configureKeybindingItems: configureKeybindingItems.length ? configureKeybindingItems : undefined };
}

Loading
Loading