From bb9d98b82e310d368971430291ea5bf796ae2f35 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Fri, 11 Aug 2023 15:05:46 -0700 Subject: [PATCH] check if screen reader optimized, support for right prompts --- .../commandDetectionCapability.ts | 28 +++++++++++++------ .../common/xterm/shellIntegrationAddon.ts | 3 +- src/vs/platform/terminal/node/ptyService.ts | 2 +- .../terminal/browser/terminalInstance.ts | 4 +-- .../terminal/browser/xterm/xtermTerminal.ts | 4 ++- .../commandDetectionCapability.test.ts | 2 +- .../browser/xterm/decorationAddon.test.ts | 2 +- .../xterm/shellIntegrationAddon.test.ts | 2 +- .../test/browser/terminalLinkOpeners.test.ts | 2 +- .../test/browser/quickFixAddon.test.ts | 2 +- 10 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index d79ebc5718b..64947a3769e 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -115,6 +115,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe constructor( private readonly _terminal: Terminal, + private readonly _isScreenReaderOptimized: boolean, private readonly _logService: ILogService ) { super(); @@ -137,6 +138,24 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe @debounce(500) private _handleCursorMove() { + // Sync the textarea with the terminal contents so screen readers can read it + if (this._isScreenReaderOptimized) { + const buffer = this._terminal.buffer.active; + const line = buffer.getLine(buffer.cursorY)?.translateToString(true); + let commandText: string | undefined; + if (line) { + if (this._currentCommand.commandStartX) { + // Left prompt + commandText = line.substring(this._currentCommand.commandStartX); + } else if (this._currentCommand.commandRightPromptStartX) { + // Right prompt + commandText = line.substring(0, this._currentCommand.commandRightPromptStartX).trimStart(); + } + if (commandText?.length) { + this._onRequestWriteToTextArea.fire(commandText); + } + } + } // Early versions of conpty do not have real support for an alt buffer, in addition certain // commands such as tsc watch will write to the top of the normal buffer. The following // checks when the cursor has moved while the normal buffer is empty and if it is above the @@ -147,14 +166,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe // // This is mostly a workaround for Windows but applies to all OS' because of the tsc watch // case. - let line = this._terminal.buffer.active.getLine(this._terminal.buffer.active.cursorY)?.translateToString(true); - if (this._currentCommand.commandStartX) { - line = line?.substring(this._currentCommand.commandStartX).trimEnd(); - } - if (line) { - console.log(line); - this._onRequestWriteToTextArea.fire(line); - } + if (this._terminal.buffer.active === this._terminal.buffer.normal && this._currentCommand.commandStartMarker) { if (this._terminal.buffer.active.baseY + this._terminal.buffer.active.cursorY < this._currentCommand.commandStartMarker.line) { this._clearCommandsInViewport(); diff --git a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts index dd97f30b522..409b5714060 100644 --- a/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts +++ b/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts @@ -207,6 +207,7 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati constructor( private _nonce: string, + private readonly _isScreenReaderOptimized: boolean, private readonly _disableTelemetry: boolean | undefined, private readonly _telemetryService: ITelemetryService | undefined, private readonly _logService: ILogService @@ -513,7 +514,7 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati protected _createOrGetCommandDetection(terminal: Terminal): ICommandDetectionCapability { let commandDetection = this.capabilities.get(TerminalCapability.CommandDetection); if (!commandDetection) { - commandDetection = this._register(new CommandDetectionCapability(terminal, this._logService)); + commandDetection = this._register(new CommandDetectionCapability(terminal, this._isScreenReaderOptimized, this._logService)); this.capabilities.add(TerminalCapability.CommandDetection, commandDetection); } return commandDetection; diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index 7e017ab5ccd..ffcafa82d80 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -1000,7 +1000,7 @@ class XtermSerializer implements ITerminalSerializer { this._xterm.writeln(reviveBufferWithRestoreMessage); } this.setUnicodeVersion(unicodeVersion); - this._shellIntegrationAddon = new ShellIntegrationAddon(shellIntegrationNonce, true, undefined, logService); + this._shellIntegrationAddon = new ShellIntegrationAddon(shellIntegrationNonce, false, true, undefined, logService); this._xterm.loadAddon(this._shellIntegrationAddon); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index fb875038aab..71e04e17147 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -425,9 +425,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { commandCapability?.onRequestWriteToTextArea(text => { const textArea = this.xterm?.raw.textarea; if (textArea) { + // Sync the textarea using shell integration so screen + // readers can read the command textArea.textContent = text; - console.log('content is'); - console.log(textArea.textContent); } }); commandCapability?.onCommandFinished(e => { diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index f3776f4eab8..c757e0b4281 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -43,6 +43,7 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService import { debounce } from 'vs/base/common/decorators'; import { MouseWheelClassifier } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { IMouseWheelEvent, StandardWheelEvent } from 'vs/base/browser/mouseEvent'; +import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; const enum RenderConstants { /** @@ -202,6 +203,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID @ITelemetryService private readonly _telemetryService: ITelemetryService, @IClipboardService private readonly _clipboardService: IClipboardService, @IContextKeyService contextKeyService: IContextKeyService, + @IAccessibilityService private readonly _accessiblityService: IAccessibilityService ) { super(); const font = this._configHelper.getFont(undefined, true); @@ -272,7 +274,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, ID this._decorationAddon = this._instantiationService.createInstance(DecorationAddon, this._capabilities); this._decorationAddon.onDidRequestRunCommand(e => this._onDidRequestRunCommand.fire(e)); this.raw.loadAddon(this._decorationAddon); - this._shellIntegrationAddon = new ShellIntegrationAddon(shellIntegrationNonce, disableShellIntegrationReporting, this._telemetryService, this._logService); + this._shellIntegrationAddon = new ShellIntegrationAddon(shellIntegrationNonce, this._accessiblityService.isScreenReaderOptimized(), disableShellIntegrationReporting, this._telemetryService, this._logService); this.raw.loadAddon(this._shellIntegrationAddon); this._anyTerminalFocusContextKey = TerminalContextKeys.focusInAny.bindTo(contextKeyService); diff --git a/src/vs/workbench/contrib/terminal/test/browser/capabilities/commandDetectionCapability.test.ts b/src/vs/workbench/contrib/terminal/test/browser/capabilities/commandDetectionCapability.test.ts index 8ce2b64a810..1b68224fd18 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/capabilities/commandDetectionCapability.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/capabilities/commandDetectionCapability.test.ts @@ -62,7 +62,7 @@ suite('CommandDetectionCapability', () => { xterm = new TerminalCtor({ allowProposedApi: true, cols: 80 }); instantiationService = new TestInstantiationService(); instantiationService.stub(IContextMenuService, { showContextMenu(delegate: IContextMenuDelegate): void { } } as Partial); - capability = new TestCommandDetectionCapability(xterm, new NullLogService()); + capability = new TestCommandDetectionCapability(xterm, false, new NullLogService()); addEvents = []; capability.onCommandFinished(e => addEvents.push(e)); assertCommands([]); diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts index b9306c6c0a7..0800708f9f7 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts @@ -61,7 +61,7 @@ suite('DecorationAddon', () => { instantiationService.stub(IContextMenuService, instantiationService.createInstance(ContextMenuService)); instantiationService.stub(ILogService, NullLogService); const capabilities = new TerminalCapabilityStore(); - capabilities.add(TerminalCapability.CommandDetection, instantiationService.createInstance(CommandDetectionCapability, xterm)); + capabilities.add(TerminalCapability.CommandDetection, instantiationService.createInstance(CommandDetectionCapability, xterm, false)); instantiationService.stub(ILifecycleService, new TestLifecycleService()); decorationAddon = instantiationService.createInstance(DecorationAddon, capabilities); xterm.loadAddon(decorationAddon); diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts index 5cba5252508..6b85f891774 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/shellIntegrationAddon.test.ts @@ -34,7 +34,7 @@ suite('ShellIntegrationAddon', () => { const TerminalCtor = (await importAMDNodeModule('xterm', 'lib/xterm.js')).Terminal; xterm = new TerminalCtor({ allowProposedApi: true, cols: 80, rows: 30 }); - shellIntegrationAddon = new TestShellIntegrationAddon('', true, undefined, new NullLogService()); + shellIntegrationAddon = new TestShellIntegrationAddon('', false, true, undefined, new NullLogService()); xterm.loadAddon(shellIntegrationAddon); capabilities = shellIntegrationAddon.capabilities; }); diff --git a/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkOpeners.test.ts b/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkOpeners.test.ts index e9193758069..d355dbe5ed7 100644 --- a/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkOpeners.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkOpeners.test.ts @@ -125,7 +125,7 @@ suite('Workbench - TerminalLinkOpeners', () => { setup(() => { capabilities = new TerminalCapabilityStore(); - commandDetection = instantiationService.createInstance(TestCommandDetectionCapability, xterm); + commandDetection = instantiationService.createInstance(TestCommandDetectionCapability, xterm, false); capabilities.add(TerminalCapability.CommandDetection, commandDetection); }); diff --git a/src/vs/workbench/contrib/terminalContrib/quickFix/test/browser/quickFixAddon.test.ts b/src/vs/workbench/contrib/terminalContrib/quickFix/test/browser/quickFixAddon.test.ts index 107304e632c..4b4e867c43b 100644 --- a/src/vs/workbench/contrib/terminalContrib/quickFix/test/browser/quickFixAddon.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/quickFix/test/browser/quickFixAddon.test.ts @@ -58,7 +58,7 @@ suite('QuickFixAddon', () => { instantiationService.stub(ILabelService, {} as Partial); const capabilities = new TerminalCapabilityStore(); instantiationService.stub(ILogService, new NullLogService()); - commandDetection = instantiationService.createInstance(CommandDetectionCapability, terminal); + commandDetection = instantiationService.createInstance(CommandDetectionCapability, terminal, false); capabilities.add(TerminalCapability.CommandDetection, commandDetection); instantiationService.stub(IContextMenuService, instantiationService.createInstance(ContextMenuService)); instantiationService.stub(IOpenerService, {} as Partial);