Skip to content

Commit

Permalink
Create terminal auto responder concept
Browse files Browse the repository at this point in the history
Part of #133524
  • Loading branch information
Tyriar committed Dec 10, 2021
1 parent 69dcf8b commit cc94215
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/vs/platform/terminal/common/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,11 @@ export interface ITerminalChildProcess {
updateProperty<T extends ProcessPropertyType>(property: T, value: IProcessPropertyMap[T]): Promise<void>;
}

export interface ITerminalEventListener {
handleInput(data: string): void;
handleResize(cols: number, rows: number): void;
}

export interface IReconnectConstants {
graceTime: number;
shortGraceTime: number;
Expand Down
64 changes: 64 additions & 0 deletions src/vs/platform/terminal/common/terminalAutoResponder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Disposable } from 'vs/base/common/lifecycle';
import { isWindows } from 'vs/base/common/platform';
import { ITerminalChildProcess, ITerminalEventListener } from 'vs/platform/terminal/common/terminal';

/**
* Tracks a terminal process's data stream and responds immediately when a matching string is
* received. This is done in a low overhead way and is ideally run on the same process as the
* where the process is handled to minimize latency.
*/
export class TerminalAutoResponder extends Disposable implements ITerminalEventListener {
private _pointer = 0;
private _paused = false;

constructor(
proc: ITerminalChildProcess,
matchWord: string,
response: string
) {
super();

this._register(proc.onProcessData(e => {
if (this._paused) {
return;
}
console.log('data', e);
const data = typeof e === 'string' ? e : e.data;
for (let i = 0; i < data.length; i++) {
if (data[i] === matchWord[this._pointer]) {
this._pointer++;
} else {
this._reset();
}
// Auto reply and reset
if (this._pointer === matchWord.length) {
proc.input(response);
this._reset();
}
}
}));
}

private _reset() {
this._pointer = 0;
}

/**
* No auto response will happen after a resize on Windows in case the resize is a result of
* reprinting the screen.
*/
handleResize() {
if (isWindows) {
this._paused = true;
}
}

handleInput() {
this._paused = false;
}
}
20 changes: 19 additions & 1 deletion src/vs/platform/terminal/node/ptyService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { URI } from 'vs/base/common/uri';
import { getSystemShell } from 'vs/base/node/shell';
import { ILogService } from 'vs/platform/log/common/log';
import { RequestStore } from 'vs/platform/terminal/common/requestStore';
import { IProcessDataEvent, IProcessReadyEvent, IPtyService, IRawTerminalInstanceLayoutInfo, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalInstanceLayoutInfoById, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalTabLayoutInfoById, TerminalIcon, IProcessProperty, TitleEventSource, ProcessPropertyType, IProcessPropertyMap, IFixedTerminalDimensions, ProcessCapability } from 'vs/platform/terminal/common/terminal';
import { IProcessDataEvent, IProcessReadyEvent, IPtyService, IRawTerminalInstanceLayoutInfo, IReconnectConstants, IRequestResolveVariablesEvent, IShellLaunchConfig, ITerminalInstanceLayoutInfoById, ITerminalLaunchError, ITerminalsLayoutInfo, ITerminalTabLayoutInfoById, TerminalIcon, IProcessProperty, TitleEventSource, ProcessPropertyType, IProcessPropertyMap, IFixedTerminalDimensions, ProcessCapability, ITerminalEventListener } from 'vs/platform/terminal/common/terminal';
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
import { escapeNonWindowsPath } from 'vs/platform/terminal/common/terminalEnvironment';
import { Terminal as XtermTerminal } from 'xterm-headless';
Expand All @@ -23,6 +23,7 @@ import { getWindowsBuildNumber } from 'vs/platform/terminal/node/terminalEnviron
import { TerminalProcess } from 'vs/platform/terminal/node/terminalProcess';
import { localize } from 'vs/nls';
import { ignoreProcessNames } from 'vs/platform/terminal/node/childProcessMonitor';
import { TerminalAutoResponder } from 'vs/platform/terminal/common/terminalAutoResponder';

type WorkspaceId = string;

Expand Down Expand Up @@ -399,6 +400,7 @@ interface IPersistentTerminalProcessLaunchOptions {
export class PersistentTerminalProcess extends Disposable {

private readonly _bufferer: TerminalDataBufferer;
private _eventListeners: ITerminalEventListener[] = [];

private readonly _pendingCommands = new Map<number, { resolve: (data: any) => void; reject: (err: any) => void; }>();

Expand Down Expand Up @@ -561,6 +563,8 @@ export class PersistentTerminalProcess extends Disposable {
// be attached yet). https://github.com/microsoft/terminal/issues/11213
if (this._wasRevived) {
this.triggerReplay();
} else {
this._setupAutoResponder();
}
} else {
this._onProcessReady.fire({ pid: this._pid, cwd: this._cwd, capabilities: this._terminalProcess.capabilities, requiresWindowsMode: isWindows && getWindowsBuildNumber() < 21376 });
Expand All @@ -578,6 +582,9 @@ export class PersistentTerminalProcess extends Disposable {
if (this._inReplay) {
return;
}
for (const listener of this._eventListeners) {
listener.handleInput(data);
}
return this._terminalProcess.input(data);
}
writeBinary(data: string): Promise<void> {
Expand All @@ -591,6 +598,10 @@ export class PersistentTerminalProcess extends Disposable {

// Buffered events should flush when a resize occurs
this._bufferer.flushBuffer(this._persistentProcessId);

for (const listener of this._eventListeners) {
listener.handleResize(cols, rows);
}
return this._terminalProcess.resize(cols, rows);
}
setUnicodeVersion(version: '6' | '11'): void {
Expand Down Expand Up @@ -624,6 +635,13 @@ export class PersistentTerminalProcess extends Disposable {
this._logService.info(`Persistent process "${this._persistentProcessId}": Replaying ${dataLength} chars and ${ev.events.length} size events`);
this._onProcessReplay.fire(ev);
this._terminalProcess.clearUnacknowledgedChars();
this._setupAutoResponder();
}

private _setupAutoResponder() {
if (isWindows) {
this._eventListeners.push(this._register(new TerminalAutoResponder(this._terminalProcess, 'Terminate batch job (Y/N)', 'Y\r')));
}
}

sendCommandResult(reqId: number, isError: boolean, serializedPayload: any): void {
Expand Down

0 comments on commit cc94215

Please sign in to comment.