parent
7b11e6519e
commit
d5cf4ac0eb
|
@ -155,6 +155,7 @@ export interface IPtyService {
|
|||
getCwd(id: number): Promise<string>;
|
||||
getLatency(id: number): Promise<number>;
|
||||
acknowledgeDataEvent(id: number, charCount: number): Promise<void>;
|
||||
processBinary(id: number, data: string): void;
|
||||
/** Confirm the process is _not_ an orphan. */
|
||||
orphanQuestionReply(id: number): Promise<void>;
|
||||
|
||||
|
@ -346,6 +347,7 @@ export interface ITerminalChildProcess {
|
|||
*/
|
||||
shutdown(immediate: boolean): void;
|
||||
input(data: string): void;
|
||||
processBinary(data: string): void;
|
||||
resize(cols: number, rows: number): void;
|
||||
|
||||
/**
|
||||
|
|
|
@ -188,6 +188,9 @@ export class PtyHostService extends Disposable implements IPtyService {
|
|||
setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise<void> {
|
||||
return this._proxy.setTerminalLayoutInfo(args);
|
||||
}
|
||||
processBinary(id: number, data: string): void {
|
||||
this._proxy.processBinary(id, data);
|
||||
}
|
||||
async getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise<ITerminalsLayoutInfo | undefined> {
|
||||
return await this._proxy.getTerminalLayoutInfo(args);
|
||||
}
|
||||
|
|
|
@ -157,6 +157,10 @@ export class PtyService extends Disposable implements IPtyService {
|
|||
return this._throwIfNoPty(id).orphanQuestionReply();
|
||||
}
|
||||
|
||||
processBinary(id: number, data: string): void {
|
||||
return this._throwIfNoPty(id).writeBinary(data);
|
||||
}
|
||||
|
||||
async setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise<void> {
|
||||
this._workspaceLayoutInfos.set(args.workspaceId, args);
|
||||
}
|
||||
|
@ -337,6 +341,9 @@ export class PersistentTerminalProcess extends Disposable {
|
|||
}
|
||||
return this._terminalProcess.input(data);
|
||||
}
|
||||
writeBinary(data: string): void {
|
||||
return this._terminalProcess.processBinary(data);
|
||||
}
|
||||
resize(cols: number, rows: number): void {
|
||||
if (this._inReplay) {
|
||||
return;
|
||||
|
|
|
@ -311,23 +311,27 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
|
|||
}
|
||||
}
|
||||
|
||||
public input(data: string): void {
|
||||
public input(data: string, isBinary?: boolean): void {
|
||||
if (this._isDisposed || !this._ptyProcess) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i <= Math.floor(data.length / WRITE_MAX_CHUNK_SIZE); i++) {
|
||||
this._writeQueue.push(data.substr(i * WRITE_MAX_CHUNK_SIZE, WRITE_MAX_CHUNK_SIZE));
|
||||
}
|
||||
this._startWrite();
|
||||
this._startWrite(isBinary);
|
||||
}
|
||||
|
||||
private _startWrite(): void {
|
||||
public processBinary(data: string): void {
|
||||
this.input(data, true);
|
||||
}
|
||||
|
||||
private _startWrite(isBinary?: boolean): void {
|
||||
// Don't write if it's already queued of is there is nothing to write
|
||||
if (this._writeTimeout !== undefined || this._writeQueue.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._doWrite();
|
||||
this._doWrite(isBinary);
|
||||
|
||||
// Don't queue more writes if the queue is empty
|
||||
if (this._writeQueue.length === 0) {
|
||||
|
@ -342,10 +346,16 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
|
|||
}, WRITE_INTERVAL_MS);
|
||||
}
|
||||
|
||||
private _doWrite(): void {
|
||||
private _doWrite(isBinary?: boolean): void {
|
||||
console.info('writing binary', isBinary);
|
||||
const data = this._writeQueue.shift()!;
|
||||
this._logService.trace('IPty#write', `${data.length} characters`);
|
||||
this._ptyProcess!.write(data);
|
||||
if (isBinary) {
|
||||
this._logService.info('IPty#write (binary)', `${data.length} characters`);
|
||||
this._ptyProcess!.write(Buffer.from(data, 'binary') as any);
|
||||
} else {
|
||||
this._logService.info('IPty#write', `${data.length} characters`);
|
||||
this._ptyProcess!.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
public resize(cols: number, rows: number): void {
|
||||
|
|
|
@ -225,6 +225,10 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
|
|||
}
|
||||
}
|
||||
|
||||
processBinary(data: string) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
acknowledgeDataEvent(charCount: number): void {
|
||||
// No-op, flow control is not supported in extension owned terminals. If this is ever
|
||||
// implemented it will need new pause and resume VS Code APIs.
|
||||
|
|
|
@ -17,6 +17,8 @@ export class RemotePty extends Disposable implements ITerminalChildProcess {
|
|||
|
||||
public readonly _onProcessData = this._register(new Emitter<string | IProcessDataEvent>());
|
||||
public readonly onProcessData: Event<string | IProcessDataEvent> = this._onProcessData.event;
|
||||
public readonly _onProcessBinary = this._register(new Emitter<string>());
|
||||
public readonly onProcessBinary: Event<string> = this._onProcessBinary.event;
|
||||
private readonly _onProcessExit = this._register(new Emitter<number | undefined>());
|
||||
public readonly onProcessExit: Event<number | undefined> = this._onProcessExit.event;
|
||||
public readonly _onProcessReady = this._register(new Emitter<{ pid: number, cwd: string }>());
|
||||
|
@ -118,6 +120,9 @@ export class RemotePty extends Disposable implements ITerminalChildProcess {
|
|||
handleData(e: string | IProcessDataEvent) {
|
||||
this._onProcessData.fire(e);
|
||||
}
|
||||
processBinary(e: string) {
|
||||
this._onProcessBinary.fire(e);
|
||||
}
|
||||
handleExit(e: number | undefined) {
|
||||
this._onProcessExit.fire(e);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ export class RemoteTerminalService extends Disposable implements IRemoteTerminal
|
|||
this._remoteTerminalChannel = channel;
|
||||
|
||||
channel.onProcessData(e => this._ptys.get(e.id)?.handleData(e.event));
|
||||
channel.onProcessBinary(e => this._ptys.get(e.id)?.processBinary(e.event));
|
||||
channel.onProcessExit(e => {
|
||||
const pty = this._ptys.get(e.id);
|
||||
if (pty) {
|
||||
|
|
|
@ -292,6 +292,11 @@ export interface ITerminalInstance {
|
|||
*/
|
||||
onData: Event<string>;
|
||||
|
||||
/**
|
||||
* Attach a listener to the binary data stream coming from xterm and going to pty
|
||||
*/
|
||||
onBinary: Event<string>;
|
||||
|
||||
/**
|
||||
* Attach a listener to listen for new lines added to this terminal instance.
|
||||
*
|
||||
|
|
|
@ -184,6 +184,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
|||
public get onTitleChanged(): Event<ITerminalInstance> { return this._onTitleChanged.event; }
|
||||
private readonly _onData = new Emitter<string>();
|
||||
public get onData(): Event<string> { return this._onData.event; }
|
||||
private readonly _onBinary = new Emitter<string>();
|
||||
public get onBinary(): Event<string> { return this._onBinary.event; }
|
||||
private readonly _onLineData = new Emitter<string>();
|
||||
public get onLineData(): Event<string> { return this._onLineData.event; }
|
||||
private readonly _onRequestExtHostProcess = new Emitter<ITerminalInstance>();
|
||||
|
@ -468,6 +470,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
|||
|
||||
this._processManager.onProcessData(e => this._onProcessData(e));
|
||||
this._xterm.onData(data => this._processManager.write(data));
|
||||
this._xterm.onBinary(data => this._processManager.processBinary(data));
|
||||
this.processReady.then(async () => {
|
||||
if (this._linkManager) {
|
||||
this._linkManager.processCwd = await this._processManager.getInitialCwd();
|
||||
|
|
|
@ -102,6 +102,10 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal
|
|||
}
|
||||
}
|
||||
|
||||
processBinary(data: string): void {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
public async start(): Promise<ITerminalLaunchError | undefined> {
|
||||
if (!this._shellLaunchConfig.isExtensionCustomPtyTerminal) {
|
||||
throw new Error('Attempt to start an ext host process that is not an extension terminal');
|
||||
|
|
|
@ -499,6 +499,10 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
|
|||
}
|
||||
}
|
||||
|
||||
public processBinary(data: string): void {
|
||||
this._process?.processBinary(data);
|
||||
}
|
||||
|
||||
public getInitialCwd(): Promise<string> {
|
||||
return Promise.resolve(this._initialCwd ? this._initialCwd : '');
|
||||
}
|
||||
|
|
|
@ -95,6 +95,9 @@ export class RemoteTerminalChannelClient {
|
|||
public get onProcessData(): Event<{ id: number, event: IProcessDataEvent | string }> {
|
||||
return this._channel.listen<{ id: number, event: IProcessDataEvent | string }>('$onProcessDataEvent');
|
||||
}
|
||||
public get onProcessBinary(): Event<{ id: number, event: string }> {
|
||||
return this._channel.listen<{ id: number, event: string }>('$onProcessBinaryEvent');
|
||||
}
|
||||
public get onProcessExit(): Event<{ id: number, event: number | undefined }> {
|
||||
return this._channel.listen<{ id: number, event: number | undefined }>('$onProcessExitEvent');
|
||||
}
|
||||
|
|
|
@ -306,6 +306,7 @@ export interface ITerminalProcessManager extends IDisposable {
|
|||
setDimensions(cols: number, rows: number, sync: false): Promise<void>;
|
||||
setDimensions(cols: number, rows: number, sync: true): void;
|
||||
acknowledgeDataEvent(charCount: number): void;
|
||||
processBinary(data: string): void;
|
||||
|
||||
getInitialCwd(): Promise<string>;
|
||||
getCwd(): Promise<string>;
|
||||
|
|
|
@ -50,6 +50,12 @@ export class LocalPty extends Disposable implements ITerminalChildProcess {
|
|||
shutdown(immediate: boolean): void {
|
||||
this._localPtyService.shutdown(this.id, immediate);
|
||||
}
|
||||
processBinary(data: string): void {
|
||||
if (this._inReplay) {
|
||||
return;
|
||||
}
|
||||
this._localPtyService.processBinary(this.id, data);
|
||||
}
|
||||
input(data: string): void {
|
||||
if (this._inReplay) {
|
||||
return;
|
||||
|
|
|
@ -136,6 +136,10 @@ export class LocalTerminalService extends Disposable implements ILocalTerminalSe
|
|||
return result;
|
||||
}
|
||||
|
||||
public processBinary(id: number, data: string): void {
|
||||
this._localPtyService.processBinary(id, data);
|
||||
}
|
||||
|
||||
private _getWorkspaceId(): string {
|
||||
return this._workspaceContextService.getWorkspace().id;
|
||||
}
|
||||
|
|
|
@ -1521,6 +1521,9 @@ export class TestLocalTerminalService implements ILocalTerminalService {
|
|||
async listProcesses(reduceGraceTime: boolean): Promise<IProcessDetails[]> { throw new Error('Method not implemented.'); }
|
||||
async setTerminalLayoutInfo(argsOrLayout?: ISetTerminalLayoutInfoArgs | ITerminalsLayoutInfoById) { throw new Error('Method not implemented.'); }
|
||||
async getTerminalLayoutInfo(): Promise<ITerminalsLayoutInfo | undefined> { throw new Error('Method not implemented.'); }
|
||||
processBinary(id: number, data: string): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
class TestTerminalChildProcess implements ITerminalChildProcess {
|
||||
|
@ -1544,6 +1547,9 @@ class TestTerminalChildProcess implements ITerminalChildProcess {
|
|||
async getInitialCwd(): Promise<string> { return ''; }
|
||||
async getCwd(): Promise<string> { return ''; }
|
||||
async getLatency(): Promise<number> { return 0; }
|
||||
processBinary(data: string): void {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
export class TestQuickInputService implements IQuickInputService {
|
||||
|
|
Loading…
Reference in a new issue