mirror of
https://github.com/Microsoft/vscode
synced 2024-10-02 17:32:41 +00:00
Add auto replies test
This commit is contained in:
parent
3cd011fa9f
commit
9566e299dd
|
@ -589,11 +589,6 @@ 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;
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
import { timeout } from 'vs/base/common/async';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { ITerminalChildProcess, ITerminalEventListener } from 'vs/platform/terminal/common/terminal';
|
||||
import { ITerminalChildProcess } 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 {
|
||||
export class TerminalAutoResponder extends Disposable {
|
||||
private _pointer = 0;
|
||||
private _paused = false;
|
||||
private _throttled = false;
|
||||
|
@ -30,6 +30,7 @@ export class TerminalAutoResponder extends Disposable implements ITerminalEventL
|
|||
return;
|
||||
}
|
||||
const data = typeof e === 'string' ? e : e.data;
|
||||
console.log('data ' + data);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i] === matchWord[this._pointer]) {
|
||||
this._pointer++;
|
||||
|
|
|
@ -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, ITerminalEventListener } 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 } 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';
|
||||
|
@ -426,8 +426,7 @@ interface IPersistentTerminalProcessLaunchOptions {
|
|||
export class PersistentTerminalProcess extends Disposable {
|
||||
|
||||
private readonly _bufferer: TerminalDataBufferer;
|
||||
private _eventListeners: ITerminalEventListener[] = [];
|
||||
private _autoReplies: Map<string, TerminalAutoResponder> = new Map();
|
||||
private readonly _autoReplies: Map<string, TerminalAutoResponder> = new Map();
|
||||
|
||||
private readonly _pendingCommands = new Map<number, { resolve: (data: any) => void; reject: (err: any) => void; }>();
|
||||
|
||||
|
@ -620,8 +619,8 @@ export class PersistentTerminalProcess extends Disposable {
|
|||
if (this._inReplay) {
|
||||
return;
|
||||
}
|
||||
for (const listener of this._eventListeners) {
|
||||
listener.handleInput(data);
|
||||
for (const listener of this._autoReplies.values()) {
|
||||
listener.handleInput();
|
||||
}
|
||||
return this._terminalProcess.input(data);
|
||||
}
|
||||
|
@ -637,8 +636,8 @@ 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);
|
||||
for (const listener of this._autoReplies.values()) {
|
||||
listener.handleResize();
|
||||
}
|
||||
return this._terminalProcess.resize(cols, rows);
|
||||
}
|
||||
|
|
|
@ -120,6 +120,8 @@ export class RemoteTerminalChannel extends Disposable implements IServerChannel<
|
|||
case '$processBinary': return this._ptyService.processBinary.apply(this._ptyService, args);
|
||||
|
||||
case '$sendCommandResult': return this._sendCommandResult(args[0], args[1], args[2]);
|
||||
case '$installAutoReply': return this._ptyService.installAutoReply.apply(this._ptyService, args);
|
||||
case '$uninstallAllAutoReplies': return this._ptyService.uninstallAllAutoReplies.apply(this._ptyService, args);
|
||||
case '$getDefaultSystemShell': return this._getDefaultSystemShell.apply(this, args);
|
||||
case '$getProfiles': return this._getProfiles.apply(this, args);
|
||||
case '$getEnvironment': return this._getEnvironment();
|
||||
|
|
|
@ -166,6 +166,22 @@ class RemoteTerminalBackend extends Disposable implements ITerminalBackend {
|
|||
const result = await Promise.all(resolveCalls);
|
||||
channel.acceptPtyHostResolvedVariables(e.requestId, result);
|
||||
}));
|
||||
|
||||
// Listen for config changes
|
||||
const initialConfig = this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION);
|
||||
for (const match of Object.keys(initialConfig.autoReplies)) {
|
||||
channel.installAutoReply(match, initialConfig.autoReplies[match]);
|
||||
}
|
||||
// TODO: Could simplify update to a single call
|
||||
this._register(this._configurationService.onDidChangeConfiguration(async e => {
|
||||
if (e.affectsConfiguration(TerminalSettingId.AutoReplies)) {
|
||||
channel.uninstallAllAutoReplies();
|
||||
const config = this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION);
|
||||
for (const match of Object.keys(config.autoReplies)) {
|
||||
await channel.installAutoReply(match, config.autoReplies[match]);
|
||||
}
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
this._remoteTerminalChannel = null;
|
||||
}
|
||||
|
|
|
@ -243,6 +243,12 @@ export class RemoteTerminalChannelClient {
|
|||
return this._channel.call('$sendCommandResult', [reqId, isError, payload]);
|
||||
}
|
||||
|
||||
installAutoReply(match: string, reply: string): Promise<void> {
|
||||
return this._channel.call('$installAutoReply', [match, reply]);
|
||||
}
|
||||
uninstallAllAutoReplies(): Promise<void> {
|
||||
return this._channel.call('$uninstallAllAutoReplies', []);
|
||||
}
|
||||
getDefaultSystemShell(osOverride?: OperatingSystem): Promise<string> {
|
||||
return this._channel.call('$getDefaultSystemShell', [osOverride]);
|
||||
}
|
||||
|
|
|
@ -82,9 +82,11 @@ export class Terminal {
|
|||
await this.quickinput.waitForQuickInputClosed();
|
||||
}
|
||||
|
||||
async runCommandInTerminal(commandText: string): Promise<void> {
|
||||
async runCommandInTerminal(commandText: string, skipEnter?: boolean): Promise<void> {
|
||||
await this.code.writeInTerminal(Selector.Xterm, commandText);
|
||||
await this.code.dispatchKeybinding('enter');
|
||||
if (!skipEnter) {
|
||||
await this.code.dispatchKeybinding('enter');
|
||||
}
|
||||
}
|
||||
|
||||
async assertEditorGroupCount(count: number): Promise<void> {
|
||||
|
|
41
test/smoke/src/areas/terminal/terminal-input.test.ts
Normal file
41
test/smoke/src/areas/terminal/terminal-input.test.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Application, Terminal, TerminalCommandId, SettingsEditor } from '../../../../automation';
|
||||
|
||||
export function setup() {
|
||||
describe('Terminal Input', () => {
|
||||
let terminal: Terminal;
|
||||
let settingsEditor: SettingsEditor;
|
||||
|
||||
// Acquire automation API
|
||||
before(async function () {
|
||||
const app = this.app as Application;
|
||||
terminal = app.workbench.terminal;
|
||||
settingsEditor = app.workbench.settingsEditor;
|
||||
});
|
||||
|
||||
describe('Auto replies', () => {
|
||||
async function writeTextForAutoReply(text: string): Promise<void> {
|
||||
// Put the matching word in quotes to avoid powershell coloring the first word and
|
||||
// on a new line to avoid cursor move/line switching sequences
|
||||
await terminal.runCommandInTerminal(`"\r${text}`, true);
|
||||
}
|
||||
|
||||
it('should automatically reply to default "Terminate batch job (Y/N)"', async () => {
|
||||
await terminal.runCommand(TerminalCommandId.CreateNew);
|
||||
await writeTextForAutoReply('Terminate batch job (Y/N)?');
|
||||
await terminal.waitForTerminalText(buffer => buffer.some(line => line.includes('Terminate batch job (Y/N)?Y')));
|
||||
});
|
||||
|
||||
it('should automatically reply to a custom entry', async () => {
|
||||
await settingsEditor.addUserSetting('terminal.integrated.autoReplies', '{ "foo": "bar" }');
|
||||
await terminal.runCommand(TerminalCommandId.CreateNew);
|
||||
await writeTextForAutoReply('foo');
|
||||
await terminal.waitForTerminalText(buffer => buffer.some(line => line.includes('foobar')));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
import { Application, Terminal, TerminalCommandId, Logger } from '../../../../automation';
|
||||
import { installAllHandlers } from '../../utils';
|
||||
import { setup as setupTerminalEditorsTests } from './terminal-editors.test';
|
||||
import { setup as setupTerminalInputTests } from './terminal-input.test';
|
||||
import { setup as setupTerminalPersistenceTests } from './terminal-persistence.test';
|
||||
import { setup as setupTerminalProfileTests } from './terminal-profiles.test';
|
||||
import { setup as setupTerminalTabsTests } from './terminal-tabs.test';
|
||||
|
@ -38,6 +39,7 @@ export function setup(logger: Logger) {
|
|||
});
|
||||
|
||||
setupTerminalEditorsTests();
|
||||
setupTerminalInputTests();
|
||||
setupTerminalPersistenceTests();
|
||||
setupTerminalProfileTests();
|
||||
setupTerminalTabsTests();
|
||||
|
|
Loading…
Reference in a new issue