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

notebook accessibility help #186229

Merged
merged 4 commits into from
Jun 26, 2023
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
18 changes: 18 additions & 0 deletions src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ import { NotebookKernelHistoryService } from 'vs/workbench/contrib/notebook/brow
import { INotebookLoggingService } from 'vs/workbench/contrib/notebook/common/notebookLoggingService';
import { NotebookLoggingService } from 'vs/workbench/contrib/notebook/browser/services/notebookLoggingServiceImpl';
import product from 'vs/platform/product/common/product';
import { AccessibilityHelpAction } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
import { NOTEBOOK_IS_ACTIVE_EDITOR } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
import { runAccessibilityHelpAction } from 'vs/workbench/contrib/notebook/browser/notebookAccessibilityHelp';

/*--------------------------------------------------------------------------------------------- */

Expand Down Expand Up @@ -672,6 +675,20 @@ class NotebookLanguageSelectorScoreRefine {
}
}

class NotebookAccessibilityHelpContribution extends Disposable {
static ID: 'chatAccessibilityHelpContribution';
constructor() {
super();
this._register(AccessibilityHelpAction.addImplementation(105, 'notebook', async accessor => {
const codeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor() || accessor.get(ICodeEditorService).getFocusedCodeEditor();
if (!codeEditor) {
return;
}
runAccessibilityHelpAction(accessor, codeEditor);
}, NOTEBOOK_IS_ACTIVE_EDITOR));
}
}

const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookContribution, LifecyclePhase.Starting);
workbenchContributionsRegistry.registerWorkbenchContribution(CellContentProvider, LifecyclePhase.Starting);
Expand All @@ -680,6 +697,7 @@ workbenchContributionsRegistry.registerWorkbenchContribution(RegisterSchemasCont
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookEditorManager, LifecyclePhase.Ready);
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookLanguageSelectorScoreRefine, LifecyclePhase.Ready);
workbenchContributionsRegistry.registerWorkbenchContribution(SimpleNotebookWorkingCopyEditorHandler, LifecyclePhase.Ready);
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookAccessibilityHelpContribution, LifecyclePhase.Eventually);

registerSingleton(INotebookService, NotebookService, InstantiationType.Delayed);
registerSingleton(INotebookEditorWorkerService, NotebookEditorWorkerServiceImpl, InstantiationType.Delayed);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { localize } from 'vs/nls';
import { format } from 'vs/base/common/strings';
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';

export function getAccessibilityHelpText(accessor: ServicesAccessor): string {
const keybindingService = accessor.get(IKeybindingService);
const content = [];
content.push(localize('notebook.overview', 'The notebook view is a collection of code and markdown cells. Code cells can be executed and will produce output directly below the cell.'));
content.push(descriptionForCommand('notebook.cell.edit',
localize('notebook.cell.edit', 'The Edit Cell command ({0}) will focus on the cell input.'),
localize('notebook.cell.editNoKb', 'The Edit Cell command will focus on the cell input and is currently not triggerable by a keybinding.'), keybindingService));
content.push(descriptionForCommand('notebook.cell.quitEdit',
localize('notebook.cell.quitEdit', 'The Quit Edit command ({0}) will set focus on the cell container. The default (Escape) key may need to be pressed twice first exit the virtual cursor if active.'),
localize('notebook.cell.quitEditNoKb', 'The Quit Edit command will set focus on the cell container and is currently not triggerable by a keybinding.'), keybindingService));
content.push(descriptionForCommand('notebook.cell.focusInOutput',
localize('notebook.cell.focusInOutput', 'The Focus Output command ({0}) will set focus in the cell\'s output.'),
localize('notebook.cell.focusInOutputNoKb', 'The Quit Edit command will set focus in the cell\'s output and is currently not triggerable by a keybinding.'), keybindingService));
content.push(localize('notebook.cellNavigation', 'The up and down arrows will move focus between cells while focused on the outer cell container'));
content.push(descriptionForCommand('notebook.cell.executeAndFocusContainer',
localize('notebook.cell.executeAndFocusContainer', 'The Execute Cell command ({0}) executes the cell that currently has focus.',),
localize('notebook.cell.executeAndFocusContainerNoKb', 'The Execute Cell command executes the cell that currently has focus and is currently not triggerable by a keybinding.'), keybindingService));
content.push(localize('notebook.cell.insertCodeCellBelowAndFocusContainer', 'The Insert Cell Above/Below commands will create new empty code cells'));
content.push(localize('notebook.changeCellType', 'The Change Cell to Code/Markdown commands are used to switch between cell types.'));


return content.join('\n');
}

function descriptionForCommand(commandId: string, msg: string, noKbMsg: string, keybindingService: IKeybindingService): string {
const kb = keybindingService.lookupKeybinding(commandId);
if (kb) {
return format(msg, kb.getAriaLabel());
}
return format(noKbMsg, commandId);
}

export async function runAccessibilityHelpAction(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
const accessibleViewService = accessor.get(IAccessibleViewService);
const helpText = getAccessibilityHelpText(accessor);
const provider = accessibleViewService.registerProvider({
id: 'notebook',
provideContent: () => helpText,
onClose: () => {
editor.focus();
provider.dispose();
},
options: { type: AccessibleViewType.HelpMenu, ariaLabel: 'Notebook accessibility help' }
});
accessibleViewService.show('notebook');
}
27 changes: 0 additions & 27 deletions src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import 'vs/css!./media/notebookCellOutput';
import { PixelRatio } from 'vs/base/browser/browser';
import * as DOM from 'vs/base/browser/dom';
import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import * as aria from 'vs/base/browser/ui/aria/aria';
import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
import { DeferredPromise, runWhenIdle, SequencerByKey } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
Expand Down Expand Up @@ -91,7 +90,6 @@ import { INotebookLoggingService } from 'vs/workbench/contrib/notebook/common/no
import { Schemas } from 'vs/base/common/network';
import { DropIntoEditorController } from 'vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorController';
import { CopyPasteController } from 'vs/editor/contrib/dropOrPasteInto/browser/copyPasteController';
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';

const $ = DOM.$;

Expand Down Expand Up @@ -2239,28 +2237,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
return undefined;
}

private _cellFocusAria(cell: ICellViewModel, focusItem: 'editor' | 'container' | 'output') {
const index = this._notebookViewModel?.getCellIndex(cell);
const verboseLabel = this.configurationService.getValue(AccessibilityVerbositySettingId.Notebook);
if (index !== undefined && index >= 0) {
let position = '';
switch (focusItem) {
case 'editor':
position = `the inner ${cell.cellKind === CellKind.Markup ? 'markdown' : 'code'} editor is focused` + (verboseLabel ? `, press escape to focus the cell container` : '');
break;
case 'output':
position = `the cell output is focused` + (verboseLabel ? `, press escape to focus the cell container` : '');
break;
case 'container':
position = `the ${cell.cellKind === CellKind.Markup ? 'markdown preview' : 'cell container'} is focused` + (verboseLabel ? `, press enter to focus the inner ${cell.cellKind === CellKind.Markup ? 'markdown' : 'code'} editor` : '');
break;
default:
break;
}
aria.alert(`Cell ${this._notebookViewModel?.getCellIndex(cell)}, ${position} `);
}
}

private _toggleNotebookCellSelection(selectedCell: ICellViewModel, selectFromPrevious: boolean): void {
const currentSelections = this._list.getSelectedElements();
const isSelected = currentSelections.includes(selectedCell);
Expand Down Expand Up @@ -2300,7 +2276,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD

if (focusItem === 'editor') {
this.focusElement(cell);
this._cellFocusAria(cell, focusItem);
this._list.focusView();

cell.updateEditState(CellEditState.Editing, 'focusNotebookCell');
Expand Down Expand Up @@ -2330,7 +2305,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
}
} else if (focusItem === 'output') {
this.focusElement(cell);
this._cellFocusAria(cell, focusItem);

if (!this.hasEditorFocus()) {
this._list.focusView();
Expand Down Expand Up @@ -2359,7 +2333,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
cell.focusMode = CellFocusMode.Container;

this.focusElement(cell);
this._cellFocusAria(cell, focusItem);
if (!options?.skipReveal) {
if (typeof options?.focusEditorLine === 'number') {
this._cursorNavMode.set(true);
Expand Down