Initial terminal API onData impl

Part of #23177
This commit is contained in:
Daniel Imms
2017-03-24 14:09:41 -07:00
parent daf6df1e83
commit 804562ed46
8 changed files with 94 additions and 0 deletions
+49
View File
@@ -809,4 +809,53 @@ declare module 'vscode' {
*/
export function registerDiffInformationCommand(command: string, callback: (diff: LineChange[], ...args: any[]) => any, thisArg?: any): Disposable;
}
export interface Terminal {
/**
* The name of the terminal.
*/
readonly name: string;
/**
* The process ID of the shell process.
*/
readonly processId: Thenable<number>;
/**
* Send text to the terminal. The text is written to the stdin of the underlying pty process
* (shell) of the terminal.
*
* @param text The text to send.
* @param addNewLine Whether to add a new line to the text being sent, this is normally
* required to run a command in the terminal. The character(s) added are \n or \r\n
* depending on the platform. This defaults to `true`.
*/
sendText(text: string, addNewLine?: boolean): void;
/**
* Show the terminal panel and reveal this terminal in the UI.
*
* @param preserveFocus When `true` the terminal will not take focus.
*/
show(preserveFocus?: boolean): void;
/**
* Hide the terminal panel if this terminal is currently showing.
*/
hide(): void;
/**
* Dispose and free associated resources.
*/
dispose(): void;
/**
* Experimental API that allows listening to the raw data stream coming from the terminal's
* pty process (including ANSI escape sequences).
*
* @param callback The callback that is triggered when data is sent to the terminal.
*/
onData(callback: (data: string) => any): void;
}
}
@@ -204,6 +204,7 @@ export abstract class MainThreadTerminalServiceShape {
$hide(terminalId: number): void { throw ni(); }
$sendText(terminalId: number, text: string, addNewLine: boolean): void { throw ni(); }
$show(terminalId: number, preserveFocus: boolean): void { throw ni(); }
$registerOnData(terminalId: number): void { throw ni(); }
}
export interface MyQuickPickItems extends IPickOpenEntry {
@@ -413,6 +414,7 @@ export abstract class ExtHostQuickOpenShape {
export abstract class ExtHostTerminalServiceShape {
$acceptTerminalClosed(id: number): void { throw ni(); }
$acceptTerminalProcessId(id: number, processId: number): void { throw ni(); }
$acceptTerminalData(id: number, data: string): void { throw ni(); }
}
export abstract class ExtHostSCMShape {
@@ -20,6 +20,8 @@ export class ExtHostTerminal implements vscode.Terminal {
private _pidPromise: TPromise<number>;
private _pidPromiseComplete: TValueCallback<number>;
private _onDataCallback: (data: string) => any;
constructor(
proxy: MainThreadTerminalServiceShape,
name?: string,
@@ -67,6 +69,11 @@ export class ExtHostTerminal implements vscode.Terminal {
this._queueApiRequest(this._proxy.$hide, []);
}
public onData(callback: (data: string) => any): void {
this._onDataCallback = callback;
this._queueApiRequest(this._proxy.$registerOnData, []);
}
public dispose(): void {
if (!this._disposed) {
this._disposed = true;
@@ -79,6 +86,10 @@ export class ExtHostTerminal implements vscode.Terminal {
this._pidPromiseComplete = null;
}
public _onData(data: string): void {
this._onDataCallback(data);
}
private _queueApiRequest(callback: (...args: any[]) => void, args: any[]) {
let request: ApiRequest = new ApiRequest(callback, args);
if (!this._id) {
@@ -138,6 +149,11 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
terminal._setProcessId(processId);
}
public $acceptTerminalData(id: number, data: string): void {
let terminal = this._getTerminalById(id);
terminal._onData(data);
}
private _getTerminalById(id: number): ExtHostTerminal {
let index = this._getTerminalIndexById(id);
return index !== null ? this._terminals[index] : null;
@@ -24,6 +24,7 @@ export class MainThreadTerminalService extends MainThreadTerminalServiceShape {
this._toDispose = [];
this._toDispose.push(terminalService.onInstanceDisposed((terminalInstance) => this._onTerminalDisposed(terminalInstance)));
this._toDispose.push(terminalService.onInstanceProcessIdReady((terminalInstance) => this._onTerminalProcessIdReady(terminalInstance)));
this._toDispose.push(terminalService.onInstanceData(event => this._onTerminalData(event.instance, event.data)));
}
public dispose(): void {
@@ -55,6 +56,13 @@ export class MainThreadTerminalService extends MainThreadTerminalServiceShape {
}
}
public $registerOnData(terminalId: number): void {
let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance) {
terminalInstance.enableApiOnData();
}
}
public $dispose(terminalId: number): void {
let terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance) {
@@ -76,4 +84,8 @@ export class MainThreadTerminalService extends MainThreadTerminalServiceShape {
private _onTerminalProcessIdReady(terminalInstance: ITerminalInstance): void {
this._proxy.$acceptTerminalProcessId(terminalInstance.id, terminalInstance.processId);
}
private _onTerminalData(terminalInstance: ITerminalInstance, data: string): void {
this._proxy.$acceptTerminalData(terminalInstance.id, data);
}
}
@@ -126,6 +126,7 @@ export interface ITerminalService {
onActiveInstanceChanged: Event<string>;
onInstanceDisposed: Event<ITerminalInstance>;
onInstanceProcessIdReady: Event<ITerminalInstance>;
onInstanceData: Event<{ instance: ITerminalInstance, data: string }>;
onInstancesChanged: Event<string>;
onInstanceTitleChanged: Event<string>;
terminalInstances: ITerminalInstance[];
@@ -314,4 +315,6 @@ export interface ITerminalInstance {
* @param shell The new launch configuration.
*/
reuseTerminal(shell?: IShellLaunchConfig): void;
enableApiOnData(): void;
}
@@ -21,6 +21,7 @@ export abstract class TerminalService implements ITerminalService {
protected _onInstancesChanged: Emitter<string>;
protected _onInstanceDisposed: Emitter<ITerminalInstance>;
protected _onInstanceProcessIdReady: Emitter<ITerminalInstance>;
protected _onInstanceData: Emitter<{ instance: ITerminalInstance, data: string }>;
protected _onInstanceTitleChanged: Emitter<string>;
protected _terminalInstances: ITerminalInstance[];
@@ -31,6 +32,7 @@ export abstract class TerminalService implements ITerminalService {
public get onActiveInstanceChanged(): Event<string> { return this._onActiveInstanceChanged.event; }
public get onInstanceDisposed(): Event<ITerminalInstance> { return this._onInstanceDisposed.event; }
public get onInstanceProcessIdReady(): Event<ITerminalInstance> { return this._onInstanceProcessIdReady.event; }
public get onInstanceData(): Event<{ instance: ITerminalInstance, data: string }> { return this._onInstanceData.event; }
public get onInstanceTitleChanged(): Event<string> { return this._onInstanceTitleChanged.event; }
public get onInstancesChanged(): Event<string> { return this._onInstancesChanged.event; }
public get terminalInstances(): ITerminalInstance[] { return this._terminalInstances; }
@@ -50,6 +52,7 @@ export abstract class TerminalService implements ITerminalService {
this._onActiveInstanceChanged = new Emitter<string>();
this._onInstanceDisposed = new Emitter<ITerminalInstance>();
this._onInstanceProcessIdReady = new Emitter<ITerminalInstance>();
this._onInstanceData = new Emitter<{ instance: ITerminalInstance, data: string }>();
this._onInstanceTitleChanged = new Emitter<string>();
this._onInstancesChanged = new Emitter<string>();
@@ -56,6 +56,7 @@ export class TerminalInstance implements ITerminalInstance {
private _isVisible: boolean;
private _isDisposed: boolean;
private _onDisposed: Emitter<ITerminalInstance>;
private _onDataForApi: Emitter<{ instance: ITerminalInstance, data: string }>;
private _onProcessIdReady: Emitter<TerminalInstance>;
private _onTitleChanged: Emitter<string>;
private _process: cp.ChildProcess;
@@ -77,6 +78,7 @@ export class TerminalInstance implements ITerminalInstance {
public get id(): number { return this._id; }
public get processId(): number { return this._processId; }
public get onDisposed(): Event<ITerminalInstance> { return this._onDisposed.event; }
public get onDataForApi(): Event<{ instance: ITerminalInstance, data: string }> { return this._onDataForApi.event; }
public get onProcessIdReady(): Event<TerminalInstance> { return this._onProcessIdReady.event; }
public get onTitleChanged(): Event<string> { return this._onTitleChanged.event; }
public get title(): string { return this._title; }
@@ -107,6 +109,7 @@ export class TerminalInstance implements ITerminalInstance {
this._terminalHasTextContextKey = KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED.bindTo(this._contextKeyService);
this._onDisposed = new Emitter<TerminalInstance>();
this._onDataForApi = new Emitter<{ instance: ITerminalInstance, data: string }>();
this._onProcessIdReady = new Emitter<TerminalInstance>();
this._onTitleChanged = new Emitter<string>();
@@ -737,6 +740,11 @@ export class TerminalInstance implements ITerminalInstance {
}
}
public enableApiOnData(): void {
// Only send data through IPC if the API explicitly requests it.
this.onData(data => this._onDataForApi.fire({ instance: this, data }));
}
public static setTerminalProcessFactory(factory: ITerminalProcessFactory): void {
this._terminalProcessFactory = factory;
}
@@ -57,6 +57,7 @@ export class TerminalService extends AbstractTerminalService implements ITermina
shell);
terminalInstance.addDisposable(terminalInstance.onTitleChanged(this._onInstanceTitleChanged.fire, this._onInstanceTitleChanged));
terminalInstance.addDisposable(terminalInstance.onDisposed(this._onInstanceDisposed.fire, this._onInstanceDisposed));
terminalInstance.addDisposable(terminalInstance.onDataForApi(this._onInstanceData.fire, this._onInstanceData));
terminalInstance.addDisposable(terminalInstance.onProcessIdReady(this._onInstanceProcessIdReady.fire, this._onInstanceProcessIdReady));
this.terminalInstances.push(terminalInstance);
if (this.terminalInstances.length === 1) {