Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate terminal instance from terminal process #47987

Merged
merged 34 commits into from
Apr 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b9a0aee
Introduce TerminalProcessManager
Tyriar Apr 14, 2018
429801e
Move ProcessState over to process manager
Tyriar Apr 14, 2018
e505941
Move process over
Tyriar Apr 14, 2018
87f5065
Move processReady over
Tyriar Apr 14, 2018
c2fcb64
Move processId over
Tyriar Apr 14, 2018
2864027
Move prelaunchinputqueue over
Tyriar Apr 14, 2018
724107e
Move onProcessReady over
Tyriar Apr 14, 2018
c9e02ff
Fire process ready event
Tyriar Apr 14, 2018
394b7ec
Move more create process over, remove node dep on terminal instance
Tyriar Apr 14, 2018
6816041
Clean up
Tyriar Apr 14, 2018
b7cb0d0
Move emitter init
Tyriar Apr 14, 2018
ade7f5e
Allow process not to be created
Tyriar Apr 14, 2018
7da6791
Give cols/rows to createProcess
Tyriar Apr 14, 2018
8ab5a00
Merge remote-tracking branch 'origin/master' into tyriar/terminal_pro…
Tyriar Apr 16, 2018
4005faf
Move process state to manager
Tyriar Apr 16, 2018
3ece733
Clear event arg
Tyriar Apr 16, 2018
6514c14
Move data event to manager
Tyriar Apr 16, 2018
497cc70
Move process title handling into manager
Tyriar Apr 16, 2018
bf4ebe3
Clean up terminal dispose and reuse
Tyriar Apr 16, 2018
aa56915
Move resize to manager
Tyriar Apr 16, 2018
8e14bfb
Make processState readonly, send via write
Tyriar Apr 16, 2018
f2640da
Make the child process provide to manager
Tyriar Apr 16, 2018
e049990
Mark manager props readonly
Tyriar Apr 16, 2018
66c6bab
Clean up
Tyriar Apr 16, 2018
0b1b44d
Merge remote-tracking branch 'origin/master' into tyriar/terminal_pro…
Tyriar Apr 16, 2018
036a087
Move environment helper functions into own module
Tyriar Apr 16, 2018
8697d1b
Add back terminal env/cwd tests
Tyriar Apr 16, 2018
29a45be
Remove use strict in terminal
Tyriar Apr 16, 2018
6d29f14
Move preparePathForTerminal to terminalEnvironment
Tyriar Apr 16, 2018
f9721fd
Move term env and cmd tracker to node layer
Tyriar Apr 16, 2018
1655a6a
Use paths
Tyriar Apr 16, 2018
a6f0ec3
Improve terminal layering
Tyriar Apr 16, 2018
321cb28
Remove terminalTab dependency on electron-browser
Tyriar Apr 16, 2018
aa85bbb
Move terminalTab to browser layer
Tyriar Apr 16, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
ignoreConfigurationCwd: true,
env
};
return TPromise.as(this.terminalService.createInstance(shellLaunchConfig).id);
return TPromise.as(this.terminalService.createTerminal(shellLaunchConfig).id);
}

public $show(terminalId: number, preserveFocus: boolean): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class TerminalLauncher implements ITerminalLauncher {

let t = this.integratedTerminalInstance;
if ((t && this.isBusy(t)) || !t) {
t = this.terminalService.createInstance({ name: args.title || nls.localize('debug.terminal.title', "debuggee") });
t = this.terminalService.createTerminal({ name: args.title || nls.localize('debug.terminal.title', "debuggee") });
this.integratedTerminalInstance = t;
}
this.terminalService.setActiveInstance(t);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ CommandsRegistry.registerCommand({
const directoriesToOpen = distinct(stats.map(({ stat }) => stat.isDirectory ? stat.resource.fsPath : paths.dirname(stat.resource.fsPath)));
return directoriesToOpen.map(dir => {
if (configurationService.getValue<ITerminalConfiguration>().terminal.explorerKind === 'integrated') {
const instance = integratedTerminalService.createInstance({ cwd: dir }, true);
const instance = integratedTerminalService.createTerminal({ cwd: dir }, true);
if (instance && (resources.length === 1 || !resource || dir === resource.fsPath || dir === paths.dirname(resource.fsPath))) {
integratedTerminalService.setActiveInstance(instance);
integratedTerminalService.showPanel(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ export class TerminalTaskSystem implements ITaskSystem {
return [terminalToReuse.terminal, commandExecutable];
}

const result = this.terminalService.createInstance(shellLaunchConfig);
const result = this.terminalService.createTerminal(shellLaunchConfig);
const terminalKey = result.id.toString();
result.onDisposed((terminal) => {
let terminalData = this.terminals[terminalKey];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';

import * as nls from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { ITerminalInstance, IShellLaunchConfig, ITerminalTab, Direction, ITerminalService } from 'vs/workbench/parts/terminal/common/terminal';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper';
import { ITerminalInstance, IShellLaunchConfig, ITerminalTab, Direction, ITerminalService, ITerminalConfigHelper } from 'vs/workbench/parts/terminal/common/terminal';
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { TerminalInstance } from 'vs/workbench/parts/terminal/electron-browser/terminalInstance';
import { Event, Emitter, anyEvent } from 'vs/base/common/event';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { SplitView, Orientation, IView } from 'vs/base/browser/ui/splitview/splitview';
Expand Down Expand Up @@ -255,22 +252,22 @@ export class TerminalTab extends Disposable implements ITerminalTab {

constructor(
terminalFocusContextKey: IContextKey<boolean>,
configHelper: TerminalConfigHelper,
configHelper: ITerminalConfigHelper,
private _container: HTMLElement,
shellLaunchConfig: IShellLaunchConfig,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ITerminalService private readonly _terminalService: ITerminalService,
@IPartService private readonly _partService: IPartService
) {
super();
this._onDisposed = new Emitter<ITerminalTab>();
this._onInstancesChanged = new Emitter<void>();

const instance = this._instantiationService.createInstance(TerminalInstance,
const instance = this._terminalService.createInstance(
terminalFocusContextKey,
configHelper,
undefined,
shellLaunchConfig);
shellLaunchConfig,
true);
this._terminalInstances.push(instance);
this._initInstanceListeners(instance);
this._activeInstanceIndex = 0;
Expand Down Expand Up @@ -392,14 +389,15 @@ export class TerminalTab extends Disposable implements ITerminalTab {

public split(
terminalFocusContextKey: IContextKey<boolean>,
configHelper: TerminalConfigHelper,
configHelper: ITerminalConfigHelper,
shellLaunchConfig: IShellLaunchConfig
): ITerminalInstance {
const instance = this._instantiationService.createInstance(TerminalInstance,
const instance = this._terminalService.createInstance(
terminalFocusContextKey,
configHelper,
undefined,
shellLaunchConfig);
shellLaunchConfig,
true);
this._terminalInstances.splice(this._activeInstanceIndex + 1, 0, instance);
this._initInstanceListeners(instance);
this._setActiveInstance(instance);
Expand Down
54 changes: 52 additions & 2 deletions src/vs/workbench/parts/terminal/common/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';

import { Event } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
Expand Down Expand Up @@ -157,7 +156,17 @@ export interface ITerminalService {
terminalInstances: ITerminalInstance[];
terminalTabs: ITerminalTab[];

createInstance(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
/**
* Creates a terminal.
* @param shell The shell launch configuration to use.
* @param wasNewTerminalAction Whether this was triggered by a new terminal action, if so a
* default shell selection dialog may display.
*/
createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
/**
* Creates a raw terminal instance, this should not be used outside of the terminal part.
*/
createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance;
getInstanceFromId(terminalId: number): ITerminalInstance;
getInstanceFromIndex(terminalIndex: number): ITerminalInstance;
getTabLabels(): string[];
Expand Down Expand Up @@ -456,3 +465,44 @@ export interface ITerminalCommandTracker {
selectToPreviousCommand(): void;
selectToNextCommand(): void;
}

export interface ITerminalProcessMessage {
type: 'pid' | 'data' | 'title';
content: number | string;
}

export interface ITerminalProcessManager extends IDisposable {
readonly processState: ProcessState;
readonly ptyProcessReady: TPromise<void>;
readonly shellProcessId: number;
readonly initialCwd: string;

readonly onProcessReady: Event<void>;
readonly onProcessData: Event<string>;
readonly onProcessTitle: Event<string>;
readonly onProcessExit: Event<number>;

addDisposable(disposable: IDisposable);
createProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number);
write(data: string): void;
setDimensions(cols: number, rows: number): void;
}

export enum ProcessState {
// The process has not been initialized yet.
UNINITIALIZED,
// The process is currently launching, the process is marked as launching
// for a short duration after being created and is helpful to indicate
// whether the process died as a result of bad shell and args.
LAUNCHING,
// The process is running normally.
RUNNING,
// The process was killed during launch, likely as a result of bad shell and
// args.
KILLED_DURING_LAUNCH,
// The process was killed by the user (the event originated from VS Code).
KILLED_BY_USER,
// The process was killed by itself, for example the shell crashed or `exit`
// was run.
KILLED_BY_PROCESS
}
5 changes: 3 additions & 2 deletions src/vs/workbench/parts/terminal/common/terminalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ export abstract class TerminalService implements ITerminalService {
}

protected abstract _showTerminalCloseConfirmation(): TPromise<boolean>;
public abstract createInstance(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance;
public abstract createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance;
public abstract getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance;
public abstract selectDefaultWindowsShell(): TPromise<string>;
public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
Expand All @@ -96,7 +97,7 @@ export abstract class TerminalService implements ITerminalService {
}

tabConfigs.forEach(tabConfig => {
const instance = this.createInstance(tabConfig.instances[0]);
const instance = this.createTerminal(tabConfig.instances[0]);
for (let i = 1; i < tabConfig.instances.length; i++) {
this.splitInstance(instance, tabConfig.instances[i]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as debugActions from 'vs/workbench/parts/debug/browser/debugActions';
import * as nls from 'vs/nls';
import * as panel from 'vs/workbench/browser/panel';
import * as platform from 'vs/base/common/platform';
import * as terminalCommands from 'vs/workbench/parts/terminal/electron-browser/terminalCommands';
import * as terminalCommands from 'vs/workbench/parts/terminal/common/terminalCommands';
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { ITerminalService, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TerminalCursorStyle, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE } from 'vs/workbench/parts/terminal/common/terminal';
import { getTerminalDefaultShellUnixLike, getTerminalDefaultShellWindows } from 'vs/workbench/parts/terminal/electron-browser/terminal';
Expand All @@ -28,7 +28,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { OpenNextRecentlyUsedEditorInGroupAction, OpenPreviousRecentlyUsedEditorInGroupAction, FocusActiveGroupAction, FocusFirstGroupAction, FocusSecondGroupAction, FocusThirdGroupAction } from 'vs/workbench/browser/parts/editor/editorActions';
import { EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions';
import { registerColors } from './terminalColorRegistry';
import { registerColors } from 'vs/workbench/parts/terminal/common/terminalColorRegistry';
import { NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction } from 'vs/workbench/electron-browser/actions';
import { QUICKOPEN_ACTION_ID, getQuickNavigateHandler, QUICKOPEN_FOCUS_SECONDARY_ACTION_ID } from 'vs/workbench/browser/parts/quickopen/quickopen';
import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';

import * as os from 'os';
import * as platform from 'vs/base/common/platform';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class ToggleTerminalAction extends TogglePanelAction {
if (this.terminalService.terminalInstances.length === 0) {
// If there is not yet an instance attempt to create it here so that we can suggest a
// new shell on Windows (and not do so when the panel is restored on reload).
const newTerminalInstance = this.terminalService.createInstance(undefined, true);
const newTerminalInstance = this.terminalService.createTerminal(undefined, true);
const toDispose = newTerminalInstance.onProcessIdReady(() => {
newTerminalInstance.focus();
toDispose.dispose();
Expand Down Expand Up @@ -258,7 +258,7 @@ export class CreateNewTerminalAction extends Action {
if (folders.length <= 1) {
// Allow terminal service to handle the path when there is only a
// single root
instancePromise = TPromise.as(this.terminalService.createInstance(undefined, true));
instancePromise = TPromise.as(this.terminalService.createTerminal(undefined, true));
} else {
const options: IPickOptions = {
placeHolder: nls.localize('workbench.action.terminal.newWorkspacePlaceholder', "Select current working directory for new terminal")
Expand All @@ -268,7 +268,7 @@ export class CreateNewTerminalAction extends Action {
// Don't create the instance if the workspace picker was canceled
return null;
}
return this.terminalService.createInstance({ cwd: workspace.uri.fsPath }, true);
return this.terminalService.createTerminal({ cwd: workspace.uri.fsPath }, true);
});
}

Expand All @@ -295,7 +295,7 @@ export class CreateNewInActiveWorkspaceTerminalAction extends Action {
}

public run(event?: any): TPromise<any> {
const instance = this.terminalService.createInstance(undefined, true);
const instance = this.terminalService.createTerminal(undefined, true);
if (!instance) {
return TPromise.as(void 0);
}
Expand Down