Skip to content

Commit 59e9653

Browse files
committed
Fixes #48513 - updated from review comments
1 parent 8b2a15d commit 59e9653

File tree

5 files changed

+272
-66
lines changed

5 files changed

+272
-66
lines changed

src/vs/workbench/api/browser/mainThreadTerminalService.ts

+11-16
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { DisposableStore, Disposable } from 'vs/base/common/lifecycle';
7-
import { IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest, getTerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminal';
7+
import { IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal';
88
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, IShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
99
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
1010
import { URI } from 'vs/base/common/uri';
1111
import { StopWatch } from 'vs/base/common/stopwatch';
1212
import { ITerminalInstanceService, ITerminalService, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
1313
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
1414
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
15+
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
1516

1617
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
1718
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
@@ -327,29 +328,23 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
327328
* listeners are removed.
328329
*/
329330
class TerminalDataEventTracker extends Disposable {
331+
private readonly _bufferer: TerminalDataBufferer;
332+
330333
constructor(
331334
private readonly _callback: (id: number, data: string) => void,
332-
@ITerminalService private readonly _terminalService: ITerminalService
335+
@ITerminalService private readonly _terminalService: ITerminalService,
333336
) {
334337
super();
338+
339+
this._register(this._bufferer = new TerminalDataBufferer());
340+
335341
this._terminalService.terminalInstances.forEach(instance => this._registerInstance(instance));
336342
this._register(this._terminalService.onInstanceCreated(instance => this._registerInstance(instance)));
343+
this._register(this._terminalService.onInstanceDisposed(instance => this._bufferer.stopBuffering(instance.id)));
337344
}
338345

339346
private _registerInstance(instance: ITerminalInstance): void {
340-
const bufferer = getTerminalDataBufferer(instance.id, this._callback);
341-
const disposables = [bufferer, instance.onData(bufferer.onData)];
342-
343-
for (const d of disposables) {
344-
this._register(d);
345-
}
346-
347-
this._register(this._terminalService.onInstanceDisposed(i => {
348-
if (i.id === instance.id) {
349-
for (const d of disposables) {
350-
d.dispose();
351-
}
352-
}
353-
}));
347+
// Buffer data events to reduce the amount of messages going to the extension host
348+
this._register(this._bufferer.startBuffering(instance.id, instance.onData, this._callback));
354349
}
355350
}

src/vs/workbench/api/common/extHostTerminalService.ts

+11-10
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as vscode from 'vscode';
7-
import { IDisposable } from 'vs/base/common/lifecycle';
87
import { Event, Emitter } from 'vs/base/common/event';
98
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
109
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
1110
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
1211
import { URI, UriComponents } from 'vs/base/common/uri';
13-
import { EXT_HOST_CREATION_DELAY, ITerminalChildProcess, ITerminalDimensions, getTerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminal';
12+
import { EXT_HOST_CREATION_DELAY, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal';
1413
import { timeout } from 'vs/base/common/async';
1514
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
15+
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
1616

1717
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
1818

@@ -287,9 +287,13 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
287287
protected readonly _onDidWriteTerminalData: Emitter<vscode.TerminalDataWriteEvent>;
288288
public get onDidWriteTerminalData(): Event<vscode.TerminalDataWriteEvent> { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; }
289289

290+
private readonly _bufferer: TerminalDataBufferer;
291+
290292
constructor(
291293
@IExtHostRpcService extHostRpc: IExtHostRpcService
292294
) {
295+
this._bufferer = new TerminalDataBufferer();
296+
293297
this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService);
294298
this._onDidWriteTerminalData = new Emitter<vscode.TerminalDataWriteEvent>({
295299
onFirstListenerAdd: () => this._proxy.$startSendingDataEvents(),
@@ -466,10 +470,9 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
466470
p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd));
467471
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
468472

469-
const bufferer = getTerminalDataBufferer(id, this._proxy.$sendProcessData);
470-
const disposables = [bufferer, p.onProcessData(bufferer.onData)];
471-
472-
p.onProcessExit(exitCode => this._onProcessExit(id, exitCode, disposables));
473+
// Buffer data events to reduce the amount of messages going to the renderer
474+
this._bufferer.startBuffering(id, p.onProcessData, this._proxy.$sendProcessData);
475+
p.onProcessExit(exitCode => this._onProcessExit(id, exitCode));
473476

474477
if (p.onProcessOverrideDimensions) {
475478
p.onProcessOverrideDimensions(e => this._proxy.$sendOverrideDimensions(id, e));
@@ -508,10 +511,8 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
508511
return id;
509512
}
510513

511-
private _onProcessExit(id: number, exitCode: number, disposables: IDisposable[]): void {
512-
for (const d of disposables) {
513-
d.dispose();
514-
}
514+
private _onProcessExit(id: number, exitCode: number): void {
515+
this._bufferer.stopBuffering(id);
515516

516517
// Remove process reference
517518
delete this._terminalProcesses[id];

src/vs/workbench/contrib/terminal/common/terminal.ts

-40
Original file line numberDiff line numberDiff line change
@@ -475,43 +475,3 @@ export const enum TERMINAL_COMMAND_ID {
475475
NAVIGATION_MODE_FOCUS_NEXT = 'workbench.action.terminal.navigationModeFocusNext',
476476
NAVIGATION_MODE_FOCUS_PREVIOUS = 'workbench.action.terminal.navigationModeFocusPrevious'
477477
}
478-
479-
interface TerminalDataBuffer {
480-
timeoutId: any;
481-
data: string[];
482-
}
483-
484-
export interface TerminalDataBufferer extends IDisposable {
485-
onData: (e: string) => void;
486-
}
487-
488-
const terminalBufferMap = new Map<number, TerminalDataBuffer>();
489-
490-
export function getTerminalDataBufferer(id: number, callback: (id: number, data: string) => void): TerminalDataBufferer {
491-
return {
492-
dispose: () => {
493-
const buffer = terminalBufferMap.get(id);
494-
if (buffer) {
495-
clearTimeout(buffer.timeoutId);
496-
terminalBufferMap.delete(id);
497-
}
498-
},
499-
onData: (e: string) => {
500-
let buffer = terminalBufferMap.get(id);
501-
if (buffer) {
502-
buffer.data.push(e);
503-
504-
return;
505-
}
506-
507-
buffer = {
508-
data: [e],
509-
timeoutId: setTimeout(() => {
510-
terminalBufferMap.delete(id);
511-
callback(id, buffer!.data.join(''));
512-
}, 5)
513-
};
514-
terminalBufferMap.set(id, buffer);
515-
}
516-
};
517-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { Event } from 'vs/base/common/event';
7+
import { IDisposable } from 'vs/base/common/lifecycle';
8+
9+
interface TerminalDataBuffer extends IDisposable {
10+
data: string[];
11+
timeoutId: any;
12+
}
13+
14+
export class TerminalDataBufferer implements IDisposable {
15+
private readonly _terminalBufferMap = new Map<number, TerminalDataBuffer>();
16+
17+
dispose() {
18+
for (const buffer of this._terminalBufferMap.values()) {
19+
buffer.dispose();
20+
}
21+
}
22+
23+
startBuffering(id: number, event: Event<string>, callback: (id: number, data: string) => void, throttleBy: number = 5): IDisposable {
24+
let disposable: IDisposable;
25+
disposable = event((e: string) => {
26+
let buffer = this._terminalBufferMap.get(id);
27+
if (buffer) {
28+
buffer.data.push(e);
29+
30+
return;
31+
}
32+
33+
const timeoutId = setTimeout(() => {
34+
this._terminalBufferMap.delete(id);
35+
callback(id, buffer!.data.join(''));
36+
}, throttleBy);
37+
buffer = {
38+
data: [e],
39+
timeoutId: timeoutId,
40+
dispose: () => {
41+
clearTimeout(timeoutId);
42+
this._terminalBufferMap.delete(id);
43+
disposable.dispose();
44+
}
45+
};
46+
this._terminalBufferMap.set(id, buffer);
47+
});
48+
return disposable;
49+
}
50+
51+
stopBuffering(id: number) {
52+
const buffer = this._terminalBufferMap.get(id);
53+
if (buffer) {
54+
buffer.dispose();
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)