put cell output content into a11y view

This commit is contained in:
aamunger
2023-07-19 11:23:24 -07:00
parent 94db5c44c3
commit cc6ee0efd5
15 changed files with 93 additions and 26 deletions
@@ -47,7 +47,7 @@ export class ContributedStatusBarItemController extends Disposable implements IN
added: ICellViewModel[];
removed: { handle: number }[];
}): void {
const vm = this._notebookEditor._getViewModel();
const vm = this._notebookEditor.getViewModel();
if (!vm) {
return;
}
@@ -58,7 +58,7 @@ export class NotebookStatusBarController extends Disposable {
}
private _updateVisibleCells(e: ICellVisibilityChangeEvent): void {
const vm = this._notebookEditor._getViewModel();
const vm = this._notebookEditor.getViewModel();
if (!vm) {
return;
}
@@ -125,7 +125,7 @@ export class FindModel extends Disposable {
// we only update cell state if users are using the hybrid mode (both input and preview are enabled)
const updateEditingState = () => {
const viewModel = this._notebookEditor._getViewModel() as NotebookViewModel | undefined;
const viewModel = this._notebookEditor.getViewModel() as NotebookViewModel | undefined;
if (!viewModel) {
return;
}
@@ -164,7 +164,7 @@ export class FindModel extends Disposable {
if (e.isReplaceRevealed && !this._state.isReplaceRevealed) {
// replace is hidden, we need to switch all markdown cells to preview mode
const viewModel = this._notebookEditor._getViewModel() as NotebookViewModel | undefined;
const viewModel = this._notebookEditor.getViewModel() as NotebookViewModel | undefined;
if (!viewModel) {
return;
}
@@ -187,7 +187,7 @@ class NotebookFindWidget extends SimpleFindReplaceWidget implements INotebookEdi
const replacePattern = this.replacePattern;
const replaceString = replacePattern.buildReplaceString(match.matches, this._state.preserveCase);
const viewModel = this._notebookEditor._getViewModel();
const viewModel = this._notebookEditor.getViewModel();
viewModel.replaceOne(cell, match.range, replaceString).then(() => {
this._progressBar.stop();
});
@@ -215,7 +215,7 @@ class NotebookFindWidget extends SimpleFindReplaceWidget implements INotebookEdi
});
});
const viewModel = this._notebookEditor._getViewModel();
const viewModel = this._notebookEditor.getViewModel();
viewModel.replaceAll(this._findModel.findMatches, replaceStrings).then(() => {
this._progressBar.stop();
});
@@ -431,7 +431,7 @@ registerAction2(class extends NotebookCellAction {
function getPageSize(context: INotebookCellActionContext) {
const editor = context.notebookEditor;
const layoutInfo = editor._getViewModel().layoutInfo;
const layoutInfo = editor.getViewModel().layoutInfo;
const lineHeight = layoutInfo?.fontInfo.lineHeight || 17;
return Math.max(1, Math.floor((layoutInfo?.height || 0) / lineHeight) - 2);
}
@@ -82,7 +82,7 @@ export class TroubleshootController extends Disposable implements INotebookEdito
});
}));
const vm = this._notebookEditor._getViewModel();
const vm = this._notebookEditor.getViewModel();
let items: INotebookDeltaCellStatusBarItems[] = [];
if (this._enabled) {
@@ -21,7 +21,7 @@ class NotebookUndoRedoContribution extends Disposable {
const PRIORITY = 105;
this._register(UndoCommand.addImplementation(PRIORITY, 'notebook-undo-redo', () => {
const editor = getNotebookEditorFromEditorPane(this._editorService.activeEditorPane);
const viewModel = editor?._getViewModel() as NotebookViewModel | undefined;
const viewModel = editor?.getViewModel() as NotebookViewModel | undefined;
if (editor && editor.hasModel() && viewModel) {
return viewModel.undo().then(cellResources => {
if (cellResources?.length) {
@@ -42,7 +42,7 @@ class NotebookUndoRedoContribution extends Disposable {
this._register(RedoCommand.addImplementation(PRIORITY, 'notebook-undo-redo', () => {
const editor = getNotebookEditorFromEditorPane(this._editorService.activeEditorPane);
const viewModel = editor?._getViewModel() as NotebookViewModel | undefined;
const viewModel = editor?.getViewModel() as NotebookViewModel | undefined;
if (editor && editor.hasModel() && viewModel) {
return viewModel.redo().then(cellResources => {
@@ -498,7 +498,7 @@ export async function joinNotebookCells(editor: IActiveNotebookEditor, range: IC
export async function joinCellsWithSurrounds(bulkEditService: IBulkEditService, context: INotebookCellActionContext, direction: 'above' | 'below'): Promise<void> {
const editor = context.notebookEditor;
const textModel = editor.textModel;
const viewModel = editor._getViewModel() as NotebookViewModel;
const viewModel = editor.getViewModel() as NotebookViewModel;
let ret: {
edits: ResourceEdit[];
cell: ICellViewModel;
@@ -656,7 +656,7 @@ export function insertCell(
initialText: string = '',
ui: boolean = false
) {
const viewModel = editor._getViewModel() as NotebookViewModel;
const viewModel = editor.getViewModel() as NotebookViewModel;
const activeKernel = editor.activeKernel;
if (viewModel.options.isReadOnly) {
return null;
@@ -49,7 +49,7 @@ export class FoldingController extends Disposable implements INotebookEditorCont
this._foldingModel = new FoldingModel();
this._localStore.add(this._foldingModel);
this._foldingModel.attachViewModel(this._notebookEditor._getViewModel());
this._foldingModel.attachViewModel(this._notebookEditor.getViewModel());
this._localStore.add(this._foldingModel.onDidFoldingRegionChanged(() => {
this._updateEditorFoldingRanges();
@@ -103,7 +103,7 @@ export class FoldingController extends Disposable implements INotebookEditorCont
return;
}
const vm = this._notebookEditor._getViewModel() as NotebookViewModel;
const vm = this._notebookEditor.getViewModel() as NotebookViewModel;
vm.updateFoldingRanges(this._foldingModel.regions);
const hiddenRanges = vm.getHiddenRanges();
@@ -119,7 +119,7 @@ export class FoldingController extends Disposable implements INotebookEditorCont
return;
}
const viewModel = this._notebookEditor._getViewModel() as NotebookViewModel;
const viewModel = this._notebookEditor.getViewModel() as NotebookViewModel;
const target = e.event.target as HTMLElement;
if (target.classList.contains('codicon-notebook-collapsed') || target.classList.contains('codicon-notebook-expanded')) {
@@ -243,7 +243,7 @@ registerAction2(class extends Action2 {
controller.setFoldingStateDown(index, CellFoldingState.Collapsed, levels);
}
const viewIndex = editor._getViewModel().getNearestVisibleCellIndexUpwards(index);
const viewIndex = editor.getViewModel().getNearestVisibleCellIndexUpwards(index);
editor.focusElement(editor.cellAt(viewIndex));
}
}
@@ -57,6 +57,7 @@ import { ILabelService } from 'vs/platform/label/common/label';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { NotebookRendererMessagingService } from 'vs/workbench/contrib/notebook/browser/services/notebookRendererMessagingServiceImpl';
import { INotebookRendererMessagingService } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService';
import { getNotebookEditorFromEditorPane } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
// Editor Controller
import 'vs/workbench/contrib/notebook/browser/controller/coreActions';
@@ -112,9 +113,10 @@ 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 { AccessibilityHelpAction, AccessibleViewAction } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
import { NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
import { runAccessibilityHelpAction } from 'vs/workbench/contrib/notebook/browser/notebookAccessibilityHelp';
import { AccessibleViewType, IAccessibleViewService } from 'vs/workbench/contrib/accessibility/browser/accessibleView';
/*--------------------------------------------------------------------------------------------- */
@@ -689,6 +691,70 @@ class NotebookAccessibilityHelpContribution extends Disposable {
}
}
class NotebookAccessibleViewContribution extends Disposable {
static ID: 'chatAccessibleViewContribution';
constructor() {
super();
this._register(AccessibleViewAction.addImplementation(100, 'notebook', accessor => {
const accessibleViewService = accessor.get(IAccessibleViewService);
const activePane = accessor.get(IEditorService).activeEditorPane;
const notebookEditor = getNotebookEditorFromEditorPane(activePane);
const notebookViewModel = notebookEditor?.getViewModel();
const selections = notebookViewModel?.getSelections();
notebookViewModel?.getCellIndex;
const notebookDocument = notebookViewModel?.notebookDocument;
if (!selections || !notebookDocument || !notebookEditor?.textModel) {
return false;
}
const viewCell = notebookViewModel.viewCells[selections[0].start];
let outputContent = '';
const decoder = new TextDecoder();
for (let i = 0; i < viewCell.outputsViewModels.length; i++) {
const outputViewModel = viewCell.outputsViewModels[i];
const outputTextModel = viewCell.model.outputs[i];
const [mimeTypes, pick] = outputViewModel.resolveMimeTypes(notebookEditor.textModel, undefined);
const mimeType = mimeTypes[pick].mimeType;
const pickedBuffer = outputTextModel.outputs.find(output => output.mime === mimeType)?.data.buffer;
let text = `${mimeType}\n`;
if (!pickedBuffer || mimeType.startsWith('image')) {
const altBuffer = outputTextModel.outputs.find(output => !output.mime.startsWith('image'))?.data.buffer;
if (altBuffer) {
text = decoder.decode(altBuffer);
}
} else {
text = decoder.decode(pickedBuffer);
}
outputContent = outputContent.concat(`${text}\n`);
}
if (!outputContent) {
return false;
}
accessibleViewService.show({
verbositySettingKey: 'notebook',
provideContent(): string { return outputContent; },
onClose() {
notebookEditor?.setFocus(selections[0]);
activePane?.focus();
},
options: {
ariaLabel: nls.localize('NotebookCellOutputAccessibleView', "Notebook Cell Output Accessible View"),
language: 'plaintext',
type: AccessibleViewType.View
}
});
return true;
}, NOTEBOOK_OUTPUT_FOCUSED));
}
}
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookContribution, LifecyclePhase.Starting);
workbenchContributionsRegistry.registerWorkbenchContribution(CellContentProvider, LifecyclePhase.Starting);
@@ -698,6 +764,7 @@ workbenchContributionsRegistry.registerWorkbenchContribution(NotebookEditorManag
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookLanguageSelectorScoreRefine, LifecyclePhase.Ready);
workbenchContributionsRegistry.registerWorkbenchContribution(SimpleNotebookWorkingCopyEditorHandler, LifecyclePhase.Ready);
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookAccessibilityHelpContribution, LifecyclePhase.Eventually);
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookAccessibleViewContribution, LifecyclePhase.Eventually);
registerSingleton(INotebookService, NotebookService, InstantiationType.Delayed);
registerSingleton(INotebookEditorWorkerService, NotebookEditorWorkerServiceImpl, InstantiationType.Delayed);
@@ -476,7 +476,7 @@ export interface INotebookEditor {
setFocus(focus: ICellRange): void;
getId(): string;
_getViewModel(): INotebookViewModel | undefined;
getViewModel(): INotebookViewModel | undefined;
hasModel(): this is IActiveNotebookEditor;
dispose(): void;
getDomNode(): HTMLElement;
@@ -684,7 +684,7 @@ export interface INotebookEditor {
}
export interface IActiveNotebookEditor extends INotebookEditor {
_getViewModel(): INotebookViewModel;
getViewModel(): INotebookViewModel;
textModel: NotebookTextModel;
getFocus(): ICellRange;
cellAt(index: number): ICellViewModel;
@@ -730,7 +730,7 @@ export interface INotebookEditorDelegate extends INotebookEditor {
}
export interface IActiveNotebookEditorDelegate extends INotebookEditorDelegate {
_getViewModel(): INotebookViewModel;
getViewModel(): INotebookViewModel;
textModel: NotebookTextModel;
getFocus(): ICellRange;
cellAt(index: number): ICellViewModel;
@@ -442,7 +442,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
return this._uuid;
}
_getViewModel(): NotebookViewModel | undefined {
getViewModel(): NotebookViewModel | undefined {
return this.viewModel;
}
@@ -33,8 +33,8 @@ export class FoldedCellHint extends CellContentPart {
if (element.isInputCollapsed || element.getEditState() === CellEditState.Editing) {
DOM.hide(this._container);
} else if (element.foldingState === CellFoldingState.Collapsed) {
const idx = this._notebookEditor._getViewModel().getCellIndex(element);
const length = this._notebookEditor._getViewModel().getFoldedLength(idx);
const idx = this._notebookEditor.getViewModel().getCellIndex(element);
const length = this._notebookEditor.getViewModel().getFoldedLength(idx);
DOM.reset(this._container, this.getHiddenCellsLabel(length), this.getHiddenCellHintButton(element));
DOM.show(this._container);
@@ -46,7 +46,7 @@ export class NotebookOverviewRuler extends Themable {
}
private _render(ctx: CanvasRenderingContext2D, width: number, height: number, scrollHeight: number, ratio: number) {
const viewModel = this.notebookEditor._getViewModel();
const viewModel = this.notebookEditor.getViewModel();
const fontInfo = this.notebookEditor.getLayoutInfo().fontInfo;
const laneWidth = width / this._lanes;
@@ -221,7 +221,7 @@ function _createTestNotebookEditor(instantiationService: TestInstantiationServic
override notebookOptions = notebookOptions;
override onDidChangeModel: Event<NotebookTextModel | undefined> = new Emitter<NotebookTextModel | undefined>().event;
override onDidChangeCellState: Event<NotebookCellStateChangedEvent> = new Emitter<NotebookCellStateChangedEvent>().event;
override _getViewModel(): NotebookViewModel {
override getViewModel(): NotebookViewModel {
return viewModel;
}
override textModel = viewModel.notebookDocument;