From d34d715248d5b107af6d2f98fc560a46637a89cf Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 22 Aug 2023 11:57:36 -0700 Subject: [PATCH 1/8] wip --- .../terminal.accessibility.contribution.ts | 2 +- .../browser/textAreaSyncAddon.ts | 43 +++++++++++++++---- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts index b69943c18de..3594567f2b1 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts @@ -40,7 +40,7 @@ class TextAreaSyncContribution extends DisposableStore implements ITerminalContr super(); } xtermReady(xterm: IXtermTerminal & { raw: Terminal }): void { - const addon = this._instantiationService.createInstance(TextAreaSyncAddon, this._instance.capabilities); + const addon = this._instantiationService.createInstance(TextAreaSyncAddon, this._instance.capabilities, this._instance.onDidFocus); xterm.raw.loadAddon(addon); addon.activate(xterm.raw); } diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts index 8ed986db3cf..9a52fc9c00a 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts @@ -8,6 +8,8 @@ import { IAccessibilityService } from 'vs/platform/accessibility/common/accessib import { ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { ITerminalLogService } from 'vs/platform/terminal/common/terminal'; import type { Terminal, ITerminalAddon } from 'xterm'; +import { Event } from 'vs/base/common/event'; +import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; export interface ITextAreaData { content: string; @@ -17,30 +19,47 @@ export interface ITextAreaData { export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { private _terminal: Terminal | undefined; private _onCursorMoveListener = this._register(new MutableDisposable()); + private _onDidFocusListener = this._register(new MutableDisposable()); + private _onKeyListener = this._register(new MutableDisposable()); activate(terminal: Terminal): void { this._terminal = terminal; if (this._accessibilityService.isScreenReaderOptimized()) { - this._onCursorMoveListener.value = this._terminal.onCursorMove(() => this._refreshTextArea()); + this._setListeners(); } } constructor( private readonly _capabilities: ITerminalCapabilityStore, + private readonly _onDidFocus: Event, @IAccessibilityService private readonly _accessibilityService: IAccessibilityService, @ITerminalLogService private readonly _logService: ITerminalLogService ) { super(); this._register(this._accessibilityService.onDidChangeScreenReaderOptimized(() => { - if (this._accessibilityService.isScreenReaderOptimized() && this._terminal) { + if (this._accessibilityService.isScreenReaderOptimized()) { this._refreshTextArea(); - this._onCursorMoveListener.value = this._terminal.onCursorMove(() => this._refreshTextArea()); + this._setListeners(); } else { this._onCursorMoveListener.clear(); + this._onDidFocusListener.clear(); + this._onKeyListener.clear(); } })); } - private _refreshTextArea(focusChanged?: boolean): void { + private _setListeners(): void { + if (this._accessibilityService.isScreenReaderOptimized() && this._terminal) { + this._onCursorMoveListener.value = this._terminal.onCursorMove(() => this._refreshTextArea()); + this._onDidFocusListener.value = this._onDidFocus(() => this._refreshTextArea()); + this._onKeyListener.value = this._terminal.onKey((e) => { + if (e.domEvent.key === 'UpArrow') { + this._refreshTextArea(); + } + }); + } + } + + private _refreshTextArea(): void { if (!this._terminal) { return; } @@ -59,18 +78,24 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { return; } let content: string | undefined; - if (currentCommand.commandStartX) { + if (currentCommand.commandStartX !== undefined) { // Left prompt content = line.substring(currentCommand.commandStartX); commandStartX = currentCommand.commandStartX; - } else if (currentCommand.commandRightPromptStartX) { + } else if (currentCommand.commandRightPromptStartX !== undefined) { // Right prompt content = line.substring(0, currentCommand.commandRightPromptStartX); commandStartX = 0; + } else { + this._logService.debug(`TextAreaSyncAddon#refreshTextArea: no commandStartX or commandRightPromptStartX`); } if (!content) { this._logService.debug(`TextAreaSyncAddon#refreshTextArea: no content`); + const textArea = this._terminal.textarea; + if (textArea) { + textArea.textContent = ''; + } return; } @@ -87,15 +112,15 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { this._logService.debug(`TextAreaSyncAddon#refreshTextArea: content is "${content}"`); this._logService.debug(`TextAreaSyncAddon#refreshTextArea: textContent is "${textArea.textContent}"`); - if (focusChanged || content !== textArea.textContent) { - textArea.textContent = content; + if (content !== textArea.textContent) { + textArea.textContent = content.trim(); this._logService.debug(`TextAreaSyncAddon#refreshTextArea: textContent changed to "${content}"`); } const cursorX = buffer.cursorX - commandStartX; this._logService.debug(`TextAreaSyncAddon#refreshTextArea: cursorX is ${cursorX}`); this._logService.debug(`TextAreaSyncAddon#refreshTextArea: selectionStart is ${textArea.selectionStart}`); - if (focusChanged || cursorX !== textArea.selectionStart) { + if (cursorX !== textArea.selectionStart) { textArea.selectionStart = cursorX; textArea.selectionEnd = cursorX; this._logService.debug(`TextAreaSyncAddon#refreshTextArea: selectionStart changed to ${cursorX}`); From f09b5e1c3a14e3b0a57ceffb6d42ee85993789b8 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 22 Aug 2023 13:06:01 -0700 Subject: [PATCH 2/8] use store --- .../browser/textAreaSyncAddon.ts | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts index 9a52fc9c00a..54599032dc5 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { ITerminalLogService } from 'vs/platform/terminal/common/terminal'; @@ -18,9 +18,7 @@ export interface ITextAreaData { export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { private _terminal: Terminal | undefined; - private _onCursorMoveListener = this._register(new MutableDisposable()); - private _onDidFocusListener = this._register(new MutableDisposable()); - private _onKeyListener = this._register(new MutableDisposable()); + private _listeners = this._register(new MutableDisposable()); activate(terminal: Terminal): void { this._terminal = terminal; if (this._accessibilityService.isScreenReaderOptimized()) { @@ -40,22 +38,20 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { this._refreshTextArea(); this._setListeners(); } else { - this._onCursorMoveListener.clear(); - this._onDidFocusListener.clear(); - this._onKeyListener.clear(); + this._listeners.clear(); } })); } private _setListeners(): void { if (this._accessibilityService.isScreenReaderOptimized() && this._terminal) { - this._onCursorMoveListener.value = this._terminal.onCursorMove(() => this._refreshTextArea()); - this._onDidFocusListener.value = this._onDidFocus(() => this._refreshTextArea()); - this._onKeyListener.value = this._terminal.onKey((e) => { + this._listeners.value?.add(this._terminal.onCursorMove(() => this._refreshTextArea())); + this._listeners.value?.add(this._onDidFocus(() => this._refreshTextArea())); + this._listeners.value?.add(this._terminal.onKey((e) => { if (e.domEvent.key === 'UpArrow') { this._refreshTextArea(); } - }); + })); } } @@ -113,7 +109,7 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { this._logService.debug(`TextAreaSyncAddon#refreshTextArea: content is "${content}"`); this._logService.debug(`TextAreaSyncAddon#refreshTextArea: textContent is "${textArea.textContent}"`); if (content !== textArea.textContent) { - textArea.textContent = content.trim(); + textArea.textContent = content; this._logService.debug(`TextAreaSyncAddon#refreshTextArea: textContent changed to "${content}"`); } From c71d140106897d0225487c85d9e215d3fd8a06b3 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 22 Aug 2023 13:13:34 -0700 Subject: [PATCH 3/8] create store --- .../accessibility/browser/textAreaSyncAddon.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts index 54599032dc5..22df31960fd 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts @@ -10,6 +10,7 @@ import { ITerminalLogService } from 'vs/platform/terminal/common/terminal'; import type { Terminal, ITerminalAddon } from 'xterm'; import { Event } from 'vs/base/common/event'; import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { debounce } from 'vs/base/common/decorators'; export interface ITextAreaData { content: string; @@ -45,9 +46,10 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { private _setListeners(): void { if (this._accessibilityService.isScreenReaderOptimized() && this._terminal) { - this._listeners.value?.add(this._terminal.onCursorMove(() => this._refreshTextArea())); - this._listeners.value?.add(this._onDidFocus(() => this._refreshTextArea())); - this._listeners.value?.add(this._terminal.onKey((e) => { + this._listeners.value = new DisposableStore(); + this._listeners.value.add(this._terminal.onCursorMove(() => this._refreshTextArea())); + this._listeners.value.add(this._onDidFocus(() => this._refreshTextArea())); + this._listeners.value.add(this._terminal.onKey((e) => { if (e.domEvent.key === 'UpArrow') { this._refreshTextArea(); } @@ -55,6 +57,7 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { } } + @debounce(50) private _refreshTextArea(): void { if (!this._terminal) { return; From da896a565443d795eb4cfd99708206af0461af16 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 22 Aug 2023 13:17:23 -0700 Subject: [PATCH 4/8] add listener to textarea directly --- .../browser/terminal.accessibility.contribution.ts | 2 +- .../accessibility/browser/textAreaSyncAddon.ts | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts index 3594567f2b1..b69943c18de 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution.ts @@ -40,7 +40,7 @@ class TextAreaSyncContribution extends DisposableStore implements ITerminalContr super(); } xtermReady(xterm: IXtermTerminal & { raw: Terminal }): void { - const addon = this._instantiationService.createInstance(TextAreaSyncAddon, this._instance.capabilities, this._instance.onDidFocus); + const addon = this._instantiationService.createInstance(TextAreaSyncAddon, this._instance.capabilities); xterm.raw.loadAddon(addon); addon.activate(xterm.raw); } diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts index 22df31960fd..454820589ba 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts @@ -8,9 +8,8 @@ import { IAccessibilityService } from 'vs/platform/accessibility/common/accessib import { ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; import { ITerminalLogService } from 'vs/platform/terminal/common/terminal'; import type { Terminal, ITerminalAddon } from 'xterm'; -import { Event } from 'vs/base/common/event'; -import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal'; import { debounce } from 'vs/base/common/decorators'; +import { addDisposableListener } from 'vs/base/browser/dom'; export interface ITextAreaData { content: string; @@ -29,7 +28,6 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { constructor( private readonly _capabilities: ITerminalCapabilityStore, - private readonly _onDidFocus: Event, @IAccessibilityService private readonly _accessibilityService: IAccessibilityService, @ITerminalLogService private readonly _logService: ITerminalLogService ) { @@ -45,10 +43,10 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { } private _setListeners(): void { - if (this._accessibilityService.isScreenReaderOptimized() && this._terminal) { + if (this._accessibilityService.isScreenReaderOptimized() && this._terminal?.textarea) { this._listeners.value = new DisposableStore(); this._listeners.value.add(this._terminal.onCursorMove(() => this._refreshTextArea())); - this._listeners.value.add(this._onDidFocus(() => this._refreshTextArea())); + this._listeners.value.add(addDisposableListener(this._terminal.textarea, 'focus', () => this._refreshTextArea())); this._listeners.value.add(this._terminal.onKey((e) => { if (e.domEvent.key === 'UpArrow') { this._refreshTextArea(); From 7f459649e4ed959cc067374aefca6f10172c45c6 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 22 Aug 2023 13:56:58 -0700 Subject: [PATCH 5/8] get it to work via value instead of textContent --- .../accessibility/browser/textAreaSyncAddon.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts index 454820589ba..3251695238b 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts @@ -91,7 +91,7 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { this._logService.debug(`TextAreaSyncAddon#refreshTextArea: no content`); const textArea = this._terminal.textarea; if (textArea) { - textArea.textContent = ''; + textArea.value = ''; } return; } @@ -110,7 +110,7 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { this._logService.debug(`TextAreaSyncAddon#refreshTextArea: content is "${content}"`); this._logService.debug(`TextAreaSyncAddon#refreshTextArea: textContent is "${textArea.textContent}"`); if (content !== textArea.textContent) { - textArea.textContent = content; + textArea.value = content; this._logService.debug(`TextAreaSyncAddon#refreshTextArea: textContent changed to "${content}"`); } @@ -122,6 +122,5 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { textArea.selectionEnd = cursorX; this._logService.debug(`TextAreaSyncAddon#refreshTextArea: selectionStart changed to ${cursorX}`); } - // TODO: cursorY? } } From cbc1cba21b6e288c3d5e976853cc34c6335581fb Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 22 Aug 2023 14:09:11 -0700 Subject: [PATCH 6/8] use better event, fix bug --- .../accessibility/browser/textAreaSyncAddon.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts index 3251695238b..b914a3e65d9 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts @@ -47,11 +47,7 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { this._listeners.value = new DisposableStore(); this._listeners.value.add(this._terminal.onCursorMove(() => this._refreshTextArea())); this._listeners.value.add(addDisposableListener(this._terminal.textarea, 'focus', () => this._refreshTextArea())); - this._listeners.value.add(this._terminal.onKey((e) => { - if (e.domEvent.key === 'UpArrow') { - this._refreshTextArea(); - } - })); + this._listeners.value.add(this._terminal.onData((e) => this._refreshTextArea())); } } From b9e61998f8ead7f934491b0d844cc18f8693f71c Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 22 Aug 2023 14:36:20 -0700 Subject: [PATCH 7/8] clean up --- .../browser/textAreaSyncAddon.ts | 113 ++++++++---------- 1 file changed, 52 insertions(+), 61 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts index b914a3e65d9..c4171b11aa2 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts @@ -19,6 +19,9 @@ export interface ITextAreaData { export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { private _terminal: Terminal | undefined; private _listeners = this._register(new MutableDisposable()); + private _currentCommand: string | undefined; + private _cursorX: number | undefined; + activate(terminal: Terminal): void { this._terminal = terminal; if (this._accessibilityService.isScreenReaderOptimized()) { @@ -34,7 +37,7 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { super(); this._register(this._accessibilityService.onDidChangeScreenReaderOptimized(() => { if (this._accessibilityService.isScreenReaderOptimized()) { - this._refreshTextArea(); + this._syncTextArea(); this._setListeners(); } else { this._listeners.clear(); @@ -45,78 +48,66 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { private _setListeners(): void { if (this._accessibilityService.isScreenReaderOptimized() && this._terminal?.textarea) { this._listeners.value = new DisposableStore(); - this._listeners.value.add(this._terminal.onCursorMove(() => this._refreshTextArea())); - this._listeners.value.add(addDisposableListener(this._terminal.textarea, 'focus', () => this._refreshTextArea())); - this._listeners.value.add(this._terminal.onData((e) => this._refreshTextArea())); + this._listeners.value.add(this._terminal.onCursorMove(() => this._syncTextArea())); + this._listeners.value.add(addDisposableListener(this._terminal.textarea, 'focus', () => this._syncTextArea())); + this._listeners.value.add(this._terminal.onData((e) => this._syncTextArea())); } } @debounce(50) - private _refreshTextArea(): void { - if (!this._terminal) { - return; - } + private _syncTextArea(): void { this._logService.debug('TextAreaSyncAddon#refreshTextArea'); - const commandCapability = this._capabilities.get(TerminalCapability.CommandDetection); - const currentCommand = commandCapability?.currentCommand; - if (!currentCommand) { - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: no currentCommand`); - return; - } - const buffer = this._terminal.buffer.active; - const line = buffer.getLine(buffer.cursorY)?.translateToString(true); - let commandStartX: number | undefined; - if (!line) { - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: no line`); - return; - } - let content: string | undefined; - if (currentCommand.commandStartX !== undefined) { - // Left prompt - content = line.substring(currentCommand.commandStartX); - commandStartX = currentCommand.commandStartX; - } else if (currentCommand.commandRightPromptStartX !== undefined) { - // Right prompt - content = line.substring(0, currentCommand.commandRightPromptStartX); - commandStartX = 0; - } else { - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: no commandStartX or commandRightPromptStartX`); - } - - if (!content) { - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: no content`); - const textArea = this._terminal.textarea; - if (textArea) { - textArea.value = ''; - } - return; - } - - if (commandStartX === undefined) { - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: no commandStartX`); - return; - } - - const textArea = this._terminal.textarea; + const textArea = this._terminal?.textarea; if (!textArea) { this._logService.debug(`TextAreaSyncAddon#refreshTextArea: no textarea`); return; } - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: content is "${content}"`); - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: textContent is "${textArea.textContent}"`); - if (content !== textArea.textContent) { - textArea.value = content; - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: textContent changed to "${content}"`); + this._updateCommandAndCursor(); + + if (this._currentCommand !== textArea.value) { + textArea.value = this._currentCommand || ''; + this._logService.debug(`TextAreaSyncAddon#refreshTextArea: text changed to "${this._currentCommand}"`); + } else if (!this._currentCommand) { + textArea.value = ''; + this._logService.debug(`TextAreaSyncAddon#refreshTextArea: text cleared`); } - const cursorX = buffer.cursorX - commandStartX; - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: cursorX is ${cursorX}`); - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: selectionStart is ${textArea.selectionStart}`); - if (cursorX !== textArea.selectionStart) { - textArea.selectionStart = cursorX; - textArea.selectionEnd = cursorX; - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: selectionStart changed to ${cursorX}`); + if (this._cursorX !== textArea.selectionStart) { + textArea.selectionStart = this._cursorX ?? 0; + textArea.selectionEnd = this._cursorX ?? 0; + this._logService.debug(`TextAreaSyncAddon#refreshTextArea: selection start/end changed to ${this._cursorX}`); + } + } + + private _updateCommandAndCursor(): void { + if (!this._terminal) { + return; + } + const commandCapability = this._capabilities.get(TerminalCapability.CommandDetection); + const currentCommand = commandCapability?.currentCommand; + if (!currentCommand) { + this._logService.debug(`TextAreaSyncAddon#updateCommandAndCursor: no current command`); + return; + } + const buffer = this._terminal.buffer.active; + const line = buffer.getLine(buffer.cursorY)?.translateToString(true); + if (!line) { + this._logService.debug(`TextAreaSyncAddon#updateCommandAndCursor: no line`); + return; + } + if (currentCommand.commandStartX !== undefined) { + // Left prompt + this._currentCommand = line.substring(currentCommand.commandStartX); + this._cursorX = buffer.cursorX - currentCommand.commandStartX; + } else if (currentCommand.commandRightPromptStartX !== undefined) { + // Right prompt + this._currentCommand = line.substring(0, currentCommand.commandRightPromptStartX); + this._cursorX = buffer.cursorX; + } else { + this._currentCommand = undefined; + this._cursorX = undefined; + this._logService.debug(`TextAreaSyncAddon#updateCommandAndCursor: neither commandStartX nor commandRightPromptStartX`); } } } From bb2964c3be29ab03734ff649ef30dd6fe7430752 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Tue, 22 Aug 2023 14:38:45 -0700 Subject: [PATCH 8/8] change names --- .../accessibility/browser/textAreaSyncAddon.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts index c4171b11aa2..666f27389d9 100644 --- a/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts @@ -25,7 +25,7 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { activate(terminal: Terminal): void { this._terminal = terminal; if (this._accessibilityService.isScreenReaderOptimized()) { - this._setListeners(); + this._registerSyncListeners(); } } @@ -38,28 +38,28 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { this._register(this._accessibilityService.onDidChangeScreenReaderOptimized(() => { if (this._accessibilityService.isScreenReaderOptimized()) { this._syncTextArea(); - this._setListeners(); + this._registerSyncListeners(); } else { this._listeners.clear(); } })); } - private _setListeners(): void { + private _registerSyncListeners(): void { if (this._accessibilityService.isScreenReaderOptimized() && this._terminal?.textarea) { this._listeners.value = new DisposableStore(); this._listeners.value.add(this._terminal.onCursorMove(() => this._syncTextArea())); + this._listeners.value.add(this._terminal.onData(() => this._syncTextArea())); this._listeners.value.add(addDisposableListener(this._terminal.textarea, 'focus', () => this._syncTextArea())); - this._listeners.value.add(this._terminal.onData((e) => this._syncTextArea())); } } @debounce(50) private _syncTextArea(): void { - this._logService.debug('TextAreaSyncAddon#refreshTextArea'); + this._logService.debug('TextAreaSyncAddon#syncTextArea'); const textArea = this._terminal?.textarea; if (!textArea) { - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: no textarea`); + this._logService.debug(`TextAreaSyncAddon#syncTextArea: no textarea`); return; } @@ -67,16 +67,16 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon { if (this._currentCommand !== textArea.value) { textArea.value = this._currentCommand || ''; - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: text changed to "${this._currentCommand}"`); + this._logService.debug(`TextAreaSyncAddon#syncTextArea: text changed to "${this._currentCommand}"`); } else if (!this._currentCommand) { textArea.value = ''; - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: text cleared`); + this._logService.debug(`TextAreaSyncAddon#syncTextArea: text cleared`); } if (this._cursorX !== textArea.selectionStart) { textArea.selectionStart = this._cursorX ?? 0; textArea.selectionEnd = this._cursorX ?? 0; - this._logService.debug(`TextAreaSyncAddon#refreshTextArea: selection start/end changed to ${this._cursorX}`); + this._logService.debug(`TextAreaSyncAddon#syncTextArea: selection start/end changed to ${this._cursorX}`); } }