Skip to content

Commit a9d5a65

Browse files
authored
Merge pull request microsoft#210688 from microsoft/tyriar/210663
Adopt PromptInputModel in TextAreaSyncAddon
2 parents 3be6cd6 + a062004 commit a9d5a65

File tree

1 file changed

+32
-82
lines changed

1 file changed

+32
-82
lines changed

src/vs/workbench/contrib/terminalContrib/accessibility/browser/textAreaSyncAddon.ts

Lines changed: 32 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,22 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
6+
import type { ITerminalAddon, Terminal } from '@xterm/xterm';
7+
import { debounce } from 'vs/base/common/decorators';
8+
import { Event } from 'vs/base/common/event';
9+
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
710
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
11+
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
812
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
913
import { ITerminalLogService, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
10-
import type { Terminal, ITerminalAddon } from '@xterm/xterm';
11-
import { debounce } from 'vs/base/common/decorators';
12-
import { addDisposableListener } from 'vs/base/browser/dom';
13-
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
14-
15-
export interface ITextAreaData {
16-
content: string;
17-
cursorX: number;
18-
}
1914

2015
export class TextAreaSyncAddon extends Disposable implements ITerminalAddon {
2116
private _terminal: Terminal | undefined;
22-
private readonly _listeners = this._register(new MutableDisposable<DisposableStore>());
23-
private _currentCommand: string | undefined;
24-
private _cursorX: number | undefined;
17+
private readonly _listeners = this._register(new MutableDisposable());
2518

2619
activate(terminal: Terminal): void {
2720
this._terminal = terminal;
28-
if (this._shouldBeActive()) {
29-
this._registerSyncListeners();
30-
}
21+
this._refreshListeners();
3122
}
3223

3324
constructor(
@@ -37,22 +28,27 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon {
3728
@ITerminalLogService private readonly _logService: ITerminalLogService
3829
) {
3930
super();
40-
this._register(this._accessibilityService.onDidChangeScreenReaderOptimized(() => {
41-
if (this._shouldBeActive()) {
42-
this._syncTextArea();
43-
this._registerSyncListeners();
44-
} else {
45-
this._listeners.clear();
46-
}
31+
32+
this._register(Event.runAndSubscribe(Event.any(
33+
this._capabilities.onDidAddCapability,
34+
this._capabilities.onDidRemoveCapability,
35+
this._accessibilityService.onDidChangeScreenReaderOptimized,
36+
), () => {
37+
this._refreshListeners();
4738
}));
4839
}
4940

50-
private _registerSyncListeners(): void {
51-
if (this._shouldBeActive() && this._terminal?.textarea) {
52-
this._listeners.value = new DisposableStore();
53-
this._listeners.value.add(this._terminal.onCursorMove(() => this._syncTextArea()));
54-
this._listeners.value.add(this._terminal.onData(() => this._syncTextArea()));
55-
this._listeners.value.add(addDisposableListener(this._terminal.textarea, 'focus', () => this._syncTextArea()));
41+
private _refreshListeners(): void {
42+
const commandDetection = this._capabilities.get(TerminalCapability.CommandDetection);
43+
if (this._shouldBeActive() && commandDetection) {
44+
if (!this._listeners.value) {
45+
const textarea = this._terminal?.textarea;
46+
if (textarea) {
47+
this._listeners.value = Event.runAndSubscribe(commandDetection.promptInputModel.onDidChangeInput, () => this._sync(textarea));
48+
}
49+
}
50+
} else {
51+
this._listeners.clear();
5652
}
5753
}
5854

@@ -61,62 +57,16 @@ export class TextAreaSyncAddon extends Disposable implements ITerminalAddon {
6157
}
6258

6359
@debounce(50)
64-
private _syncTextArea(): void {
65-
this._logService.debug('TextAreaSyncAddon#syncTextArea');
66-
const textArea = this._terminal?.textarea;
67-
if (!textArea) {
68-
this._logService.debug(`TextAreaSyncAddon#syncTextArea: no textarea`);
60+
private _sync(textArea: HTMLTextAreaElement): void {
61+
const commandCapability = this._capabilities.get(TerminalCapability.CommandDetection);
62+
if (!commandCapability) {
6963
return;
7064
}
7165

72-
this._updateCommandAndCursor();
73-
74-
if (this._currentCommand !== textArea.value) {
75-
textArea.value = this._currentCommand || '';
76-
this._logService.debug(`TextAreaSyncAddon#syncTextArea: text changed to "${this._currentCommand}"`);
77-
} else if (!this._currentCommand) {
78-
textArea.value = '';
79-
this._logService.debug(`TextAreaSyncAddon#syncTextArea: text cleared`);
80-
}
81-
82-
if (this._cursorX !== textArea.selectionStart) {
83-
const selection = !this._cursorX || this._cursorX < 0 ? 0 : this._cursorX;
84-
textArea.selectionStart = selection;
85-
textArea.selectionEnd = selection;
86-
this._logService.debug(`TextAreaSyncAddon#syncTextArea: selection start/end changed to ${selection}`);
87-
}
88-
}
66+
textArea.value = commandCapability.promptInputModel.value;
67+
textArea.selectionStart = commandCapability.promptInputModel.cursorIndex;
68+
textArea.selectionEnd = commandCapability.promptInputModel.cursorIndex;
8969

90-
private _updateCommandAndCursor(): void {
91-
if (!this._terminal) {
92-
return;
93-
}
94-
const commandCapability = this._capabilities.get(TerminalCapability.CommandDetection);
95-
const currentCommand = commandCapability?.currentCommand;
96-
if (!currentCommand) {
97-
this._logService.debug(`TextAreaSyncAddon#updateCommandAndCursor: no current command`);
98-
return;
99-
}
100-
const buffer = this._terminal.buffer.active;
101-
const lineNumber = currentCommand.commandStartMarker?.line;
102-
this._logService.debug('line number?', lineNumber);
103-
if (!lineNumber) {
104-
return;
105-
}
106-
const commandLine = buffer.getLine(lineNumber)?.translateToString(true);
107-
if (!commandLine) {
108-
this._logService.debug(`TextAreaSyncAddon#updateCommandAndCursor: no line`);
109-
return;
110-
}
111-
// TODO: Support multi-line prompts
112-
if (currentCommand.commandStartX !== undefined) {
113-
this._currentCommand = commandLine.substring(currentCommand.commandStartX);
114-
const cursorPosition = buffer.cursorX - currentCommand.commandStartX;
115-
this._cursorX = cursorPosition >= 0 ? cursorPosition : 0;
116-
} else {
117-
this._currentCommand = undefined;
118-
this._cursorX = undefined;
119-
this._logService.debug(`TextAreaSyncAddon#updateCommandAndCursor: no commandStartX`);
120-
}
70+
this._logService.debug(`TextAreaSyncAddon#sync: text changed to "${textArea.value}"`);
12171
}
12272
}

0 commit comments

Comments
 (0)