Skip to content

Commit

Permalink
Move terminalProcess to run in renderer process
Browse files Browse the repository at this point in the history
Part of #53974
  • Loading branch information
Tyriar committed Jul 10, 2018
1 parent c3bc031 commit 35cee02
Show file tree
Hide file tree
Showing 2 changed files with 276 additions and 209 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as cp from 'child_process';
// import * as cp from 'child_process';
import * as platform from 'vs/base/common/platform';
import * as terminalEnvironment from 'vs/workbench/parts/terminal/node/terminalEnvironment';
import Uri from 'vs/base/common/uri';
Expand All @@ -15,9 +15,10 @@ import { Emitter, Event } from 'vs/base/common/event';
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { ITerminalChildProcess, IMessageFromTerminalProcess } from 'vs/workbench/parts/terminal/node/terminal';
import { TerminalProcessExtHostProxy } from 'vs/workbench/parts/terminal/node/terminalProcessExtHostProxy';
// import { ITerminalChildProcess, IMessageFromTerminalProcess } from 'vs/workbench/parts/terminal/node/terminal';
// import { TerminalProcessExtHostProxy } from 'vs/workbench/parts/terminal/node/terminalProcessExtHostProxy';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TerminalProcess } from 'vs/workbench/parts/terminal/node/terminalProcess';

/** The amount of time to consider terminal errors to be related to the launch */
const LAUNCHING_DURATION = 500;
Expand All @@ -36,7 +37,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
public shellProcessId: number;
public initialCwd: string;

private _process: ITerminalChildProcess;
private _process: TerminalProcess;
private _preLaunchInputQueue: string[] = [];
private _disposables: IDisposable[] = [];

Expand All @@ -58,6 +59,7 @@ export class TerminalProcessManager implements ITerminalProcessManager {
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ILogService private _logService: ILogService
) {
console.log(this._terminalId, this._instantiationService);
this.ptyProcessReady = new TPromise<void>(c => {
this.onProcessReady(() => {
this._logService.debug(`Terminal process ready (shellProcessId: ${this.shellProcessId})`);
Expand All @@ -68,12 +70,13 @@ export class TerminalProcessManager implements ITerminalProcessManager {

public dispose(): void {
if (this._process) {
if (this._process.connected) {
if (this._process.isConnected) {
// If the process was still connected this dispose came from
// within VS Code, not the process, so mark the process as
// killed by the user.
this.processState = ProcessState.KILLED_BY_USER;
this._process.send({ event: 'shutdown' });
this._process.shutdown();
// this._process.send({ event: 'shutdown' });
}
this._process = null;
}
Expand All @@ -90,42 +93,60 @@ export class TerminalProcessManager implements ITerminalProcessManager {
cols: number,
rows: number
): void {
const extensionHostOwned = (<any>this._configHelper.config).extHostProcess;
if (extensionHostOwned) {
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, cols, rows);
} else {
const locale = this._configHelper.config.setLocaleVariables ? platform.locale : undefined;
if (!shellLaunchConfig.executable) {
this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig);
}

const lastActiveWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot('file');
this.initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, lastActiveWorkspaceRootUri, this._configHelper);
// const extensionHostOwned = (<any>this._configHelper.config).extHostProcess;
// if (extensionHostOwned) {
// this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, cols, rows);
// } else {
const locale = this._configHelper.config.setLocaleVariables ? platform.locale : undefined;
if (!shellLaunchConfig.executable) {
this._configHelper.mergeDefaultShellPathAndArgs(shellLaunchConfig);
}

// Resolve env vars from config and shell
const lastActiveWorkspaceRoot = this._workspaceContextService.getWorkspaceFolder(lastActiveWorkspaceRootUri);
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
const envFromConfig = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...this._configHelper.config.env[platformKey] }, lastActiveWorkspaceRoot);
const envFromShell = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...shellLaunchConfig.env }, lastActiveWorkspaceRoot);
shellLaunchConfig.env = envFromShell;
const lastActiveWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot('file');
this.initialCwd = terminalEnvironment.getCwd(shellLaunchConfig, lastActiveWorkspaceRootUri, this._configHelper);

// Resolve env vars from config and shell
const lastActiveWorkspaceRoot = this._workspaceContextService.getWorkspaceFolder(lastActiveWorkspaceRootUri);
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
const envFromConfig = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...this._configHelper.config.env[platformKey] }, lastActiveWorkspaceRoot);
const envFromShell = terminalEnvironment.resolveConfigurationVariables(this._configurationResolverService, { ...shellLaunchConfig.env }, lastActiveWorkspaceRoot);
shellLaunchConfig.env = envFromShell;

// Merge process env with the env from config
const parentEnv = { ...process.env };
terminalEnvironment.mergeEnvironments(parentEnv, envFromConfig);

// Continue env initialization, merging in the env from the launch
// config and adding keys that are needed to create the process
const env = terminalEnvironment.createTerminalEnv(parentEnv, shellLaunchConfig, this.initialCwd, locale, cols, rows);
const cwd = Uri.parse(require.toUrl('../node')).fsPath;
const options = { env, cwd };
this._logService.debug(`Terminal process launching`, options);

// this._process = cp.fork(Uri.parse(require.toUrl('bootstrap')).fsPath, ['--type=terminal'], options);
this._process = new TerminalProcess(env['PTYSHELL'], [], env['PTYCWD'], cols, rows);
// }
this.processState = ProcessState.LAUNCHING;

// Merge process env with the env from config
const parentEnv = { ...process.env };
terminalEnvironment.mergeEnvironments(parentEnv, envFromConfig);
this._process.onData(data => {
this._onProcessData.fire(data);
});

// Continue env initialization, merging in the env from the launch
// config and adding keys that are needed to create the process
const env = terminalEnvironment.createTerminalEnv(parentEnv, shellLaunchConfig, this.initialCwd, locale, cols, rows);
const cwd = Uri.parse(require.toUrl('../node')).fsPath;
const options = { env, cwd };
this._logService.debug(`Terminal process launching`, options);
this._process.onProcessIdReady(pid => {
this.shellProcessId = pid;
this._onProcessReady.fire();

this._process = cp.fork(Uri.parse(require.toUrl('bootstrap')).fsPath, ['--type=terminal'], options);
}
this.processState = ProcessState.LAUNCHING;
// Send any queued data that's waiting
if (this._preLaunchInputQueue.length > 0) {
this._process.input(this._preLaunchInputQueue.join(''));
this._preLaunchInputQueue.length = 0;
}
});

this._process.on('message', message => this._onMessage(message));
this._process.on('exit', exitCode => this._onExit(exitCode));
this._process.onTitleChanged(title => this._onProcessTitle.fire(title));
this._process.onExit(exitCode => this._onExit(exitCode));
// this._process.on('message', message => this._onMessage(message));
// this._process.on('exit', exitCode => this._onExit(exitCode));

setTimeout(() => {
if (this.processState === ProcessState.LAUNCHING) {
Expand All @@ -135,10 +156,11 @@ export class TerminalProcessManager implements ITerminalProcessManager {
}

public setDimensions(cols: number, rows: number): void {
if (this._process && this._process.connected) {
if (this._process && this._process.isConnected) {
// The child process could aready be terminated
try {
this._process.send({ event: 'resize', cols, rows });
this._process.resize(cols, rows);
// this._process.send({ event: 'resize', cols, rows });
} catch (error) {
// We tried to write to a closed pipe / channel.
if (error.code !== 'EPIPE' && error.code !== 'ERR_IPC_CHANNEL_CLOSED') {
Expand All @@ -152,41 +174,38 @@ export class TerminalProcessManager implements ITerminalProcessManager {
if (this.shellProcessId) {
if (this._process) {
// Send data if the pty is ready
this._process.send({
event: 'input',
data
});
this._process.input(data);
}
} else {
// If the pty is not ready, queue the data received to send later
this._preLaunchInputQueue.push(data);
}
}

private _onMessage(message: IMessageFromTerminalProcess): void {
this._logService.trace(`terminalProcessManager#_onMessage (shellProcessId: ${this.shellProcessId}`, message);
switch (message.type) {
case 'data':
this._onProcessData.fire(<string>message.content);
break;
case 'pid':
this.shellProcessId = <number>message.content;
this._onProcessReady.fire();

// Send any queued data that's waiting
if (this._preLaunchInputQueue.length > 0) {
this._process.send({
event: 'input',
data: this._preLaunchInputQueue.join('')
});
this._preLaunchInputQueue.length = 0;
}
break;
case 'title':
this._onProcessTitle.fire(<string>message.content);
break;
}
}
// private _onMessage(message: IMessageFromTerminalProcess): void {
// this._logService.trace(`terminalProcessManager#_onMessage (shellProcessId: ${this.shellProcessId}`, message);
// switch (message.type) {
// case 'data':
// this._onProcessData.fire(<string>message.content);
// break;
// case 'pid':
// this.shellProcessId = <number>message.content;
// this._onProcessReady.fire();

// // Send any queued data that's waiting
// if (this._preLaunchInputQueue.length > 0) {
// this._process.send({
// event: 'input',
// data: this._preLaunchInputQueue.join('')
// });
// this._preLaunchInputQueue.length = 0;
// }
// break;
// case 'title':
// this._onProcessTitle.fire(<string>message.content);
// break;
// }
// }

private _onExit(exitCode: number): void {
this._process = null;
Expand Down
Loading

0 comments on commit 35cee02

Please sign in to comment.