Add global event window.onDidWriteTerminalData

Fixes #78502
This commit is contained in:
Daniel Imms
2019-08-06 09:51:03 -07:00
parent 21a4e91688
commit dc6b475be7
7 changed files with 200 additions and 36 deletions

View File

@@ -457,8 +457,13 @@ export function createApiFactory(
return extHostTerminalService.onDidChangeActiveTerminal(listener, thisArg, disposables);
},
onDidChangeTerminalDimensions(listener, thisArg?, disposables?) {
checkProposedApiEnabled(extension);
return extHostTerminalService.onDidChangeTerminalDimensions(listener, thisArg, disposables);
},
onDidWriteTerminalData(listener, thisArg?, disposables?) {
checkProposedApiEnabled(extension);
return extHostTerminalService.onDidWriteTerminalData(listener, thisArg, disposables);
},
get state() {
return extHostWindow.state;
},

View File

@@ -588,7 +588,7 @@ export class ExtHostTask implements ExtHostTaskShape {
// Clone the custom execution to keep the original untouched. This is important for multiple runs of the same task.
this._activeCustomExecutions2.set(execution.id, execution2);
await this._terminalService.attachPtyToTerminal(terminalId, await execution2.callback());
this._terminalService.attachPtyToTerminal(terminalId, await execution2.callback());
}
// Once a terminal is spun up for the custom execution task this event will be fired.

View File

@@ -88,7 +88,9 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
private _pidPromiseComplete: ((value: number | undefined) => any) | undefined;
private _rows: number | undefined;
/** @deprecated */
private readonly _onData = new Emitter<string>();
/** @deprecated */
public get onDidWriteData(): Event<string> {
// Tell the main side to start sending data if it's not already
this._idPromise.then(id => {
@@ -97,6 +99,8 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
return this._onData.event;
}
public isOpen: boolean = false;
constructor(
proxy: MainThreadTerminalServiceShape,
private _name?: string,
@@ -305,6 +309,8 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
public get onDidChangeActiveTerminal(): Event<vscode.Terminal | undefined> { return this._onDidChangeActiveTerminal && this._onDidChangeActiveTerminal.event; }
private readonly _onDidChangeTerminalDimensions: Emitter<vscode.TerminalDimensionsChangeEvent> = new Emitter<vscode.TerminalDimensionsChangeEvent>();
public get onDidChangeTerminalDimensions(): Event<vscode.TerminalDimensionsChangeEvent> { return this._onDidChangeTerminalDimensions && this._onDidChangeTerminalDimensions.event; }
private readonly _onDidWriteTerminalData: Emitter<vscode.TerminalDataWriteEvent>;
public get onDidWriteTerminalData(): Event<vscode.TerminalDataWriteEvent> { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; }
constructor(
mainContext: IMainContext,
@@ -314,6 +320,10 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
private _logService: ILogService
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadTerminalService);
this._onDidWriteTerminalData = new Emitter<vscode.TerminalDataWriteEvent>({
onFirstListenerAdd: () => this._proxy.$startSendingDataEvents(),
onLastListenerRemove: () => this._proxy.$stopSendingDataEvents()
});
this._updateLastActiveWorkspace();
this._updateVariableResolver();
this._registerListeners();
@@ -341,7 +351,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
return terminal;
}
public async attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): Promise<void> {
public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void {
const terminal = this._getTerminalByIdEventually(id);
if (!terminal) {
throw new Error(`Cannot resolve terminal with id ${id} for virtual process`);
@@ -409,7 +419,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
return renderer;
}
public $acceptActiveTerminalChanged(id: number | null): void {
public async $acceptActiveTerminalChanged(id: number | null): Promise<void> {
const original = this._activeTerminal;
if (id === null) {
this._activeTerminal = undefined;
@@ -418,38 +428,45 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
}
return;
}
this.performTerminalIdAction(id, terminal => {
if (terminal) {
this._activeTerminal = terminal;
if (original !== this._activeTerminal) {
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
}
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
this._activeTerminal = terminal;
if (original !== this._activeTerminal) {
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
}
});
}
}
public $acceptTerminalProcessData(id: number, data: string): void {
this._getTerminalByIdEventually(id).then(terminal => {
if (terminal) {
terminal._fireOnData(data);
}
});
/** @deprecated */
public async $acceptTerminalProcessData(id: number, data: string): Promise<void> {
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
terminal._fireOnData(data);
}
}
public $acceptTerminalDimensions(id: number, cols: number, rows: number): void {
this._getTerminalByIdEventually(id).then(terminal => {
if (terminal) {
if (terminal.setDimensions(cols, rows)) {
this._onDidChangeTerminalDimensions.fire({
terminal: terminal,
dimensions: terminal.dimensions as vscode.TerminalDimensions
});
}
}
});
public async $acceptTerminalProcessData2(id: number, data: string): Promise<void> {
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
this._onDidWriteTerminalData.fire({ terminal, data });
}
}
public $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void {
public async $acceptTerminalDimensions(id: number, cols: number, rows: number): Promise<void> {
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
if (terminal.setDimensions(cols, rows)) {
this._onDidChangeTerminalDimensions.fire({
terminal: terminal,
dimensions: terminal.dimensions as vscode.TerminalDimensions
});
}
}
}
public async $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): Promise<void> {
await this._getTerminalByIdEventually(id);
if (this._terminalProcesses[id]) {
// Virtual processes only - when virtual process resize fires it means that the
// terminal's maximum dimensions changed
@@ -473,14 +490,16 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
}
}
public $acceptTerminalTitleChange(id: number, name: string): void {
public async $acceptTerminalTitleChange(id: number, name: string): Promise<void> {
await this._getTerminalByIdEventually(id);
const extHostTerminal = this._getTerminalObjectById(this.terminals, id);
if (extHostTerminal) {
extHostTerminal.name = name;
}
}
public $acceptTerminalClosed(id: number): void {
public async $acceptTerminalClosed(id: number): Promise<void> {
await this._getTerminalByIdEventually(id);
const index = this._getTerminalObjectIndexById(this.terminals, id);
if (index !== null) {
const terminal = this._terminals.splice(index, 1)[0];
@@ -493,6 +512,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
if (index !== null) {
// The terminal has already been created (via createTerminal*), only fire the event
this._onDidOpenTerminal.fire(this.terminals[index]);
this.terminals[index].isOpen = true;
return;
}
@@ -500,13 +520,18 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
const terminal = new ExtHostTerminal(this._proxy, name, id, renderer ? RENDERER_NO_PROCESS_ID : undefined);
this._terminals.push(terminal);
this._onDidOpenTerminal.fire(terminal);
terminal.isOpen = true;
}
public $acceptTerminalProcessId(id: number, processId: number): void {
this.performTerminalIdAction(id, terminal => terminal._setProcessId(processId));
public async $acceptTerminalProcessId(id: number, processId: number): Promise<void> {
const terminal = await this._getTerminalByIdEventually(id);
if (terminal) {
terminal._setProcessId(processId);
}
}
public performTerminalIdAction(id: number, callback: (terminal: ExtHostTerminal) => void): void {
// TODO: Use await this._getTerminalByIdEventually(id);
let terminal = this._getTerminalById(id);
if (terminal) {
callback(terminal);
@@ -629,7 +654,27 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<void> {
// Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call
// Pseudoterminal.start
await this._getTerminalByIdEventually(id);
const terminal = await this._getTerminalByIdEventually(id);
if (!terminal) {
return;
}
// Wait for onDidOpenTerminal to fire
let openPromise: Promise<void>;
if (terminal.isOpen) {
openPromise = Promise.resolve();
} else {
openPromise = new Promise<void>(r => {
// Ensure open is called after onDidOpenTerminal
const listener = this.onDidOpenTerminal(async e => {
if (e === terminal) {
listener.dispose();
r();
}
});
});
}
await openPromise;
// Processes should be initialized here for normal virtual process terminals, however for
// tasks they are responsible for attaching the virtual process to a terminal so this
@@ -706,7 +751,8 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
this._proxy.$sendProcessExit(id, exitCode);
}
private _getTerminalByIdEventually(id: number, retries: number = 5): Promise<ExtHostTerminal> {
// TODO: This could be improved by using a single promise and resolve it when the terminal is ready
private _getTerminalByIdEventually(id: number, retries: number = 5): Promise<ExtHostTerminal | undefined> {
if (!this._getTerminalPromises[id]) {
this._getTerminalPromises[id] = this._createGetTerminalPromise(id, retries);
} else {