提交 abe753dd 编写于 作者: D Daniel Imms

Clean up old process and handle listeners better

Fixes #18377
上级 dbceda7d
...@@ -271,5 +271,5 @@ export interface ITerminalInstance { ...@@ -271,5 +271,5 @@ export interface ITerminalInstance {
* *
* @param shell The new launch configuration. * @param shell The new launch configuration.
*/ */
reuseTerminal(shell: IShellLaunchConfig): void; reuseTerminal(shell?: IShellLaunchConfig): void;
} }
...@@ -45,7 +45,8 @@ export class TerminalInstance implements ITerminalInstance { ...@@ -45,7 +45,8 @@ export class TerminalInstance implements ITerminalInstance {
private _processId: number; private _processId: number;
private _skipTerminalCommands: string[]; private _skipTerminalCommands: string[];
private _title: string; private _title: string;
private _toDispose: lifecycle.IDisposable[]; private _instanceDisposables: lifecycle.IDisposable[];
private _processDisposables: lifecycle.IDisposable[];
private _wrapperElement: HTMLDivElement; private _wrapperElement: HTMLDivElement;
private _xterm: any; private _xterm: any;
private _xtermElement: HTMLDivElement; private _xtermElement: HTMLDivElement;
...@@ -71,7 +72,8 @@ export class TerminalInstance implements ITerminalInstance { ...@@ -71,7 +72,8 @@ export class TerminalInstance implements ITerminalInstance {
@IPanelService private _panelService: IPanelService, @IPanelService private _panelService: IPanelService,
@IWorkspaceContextService private _contextService: IWorkspaceContextService @IWorkspaceContextService private _contextService: IWorkspaceContextService
) { ) {
this._toDispose = []; this._instanceDisposables = [];
this._processDisposables = [];
this._skipTerminalCommands = []; this._skipTerminalCommands = [];
this._isExiting = false; this._isExiting = false;
this._hadFocusOnExit = false; this._hadFocusOnExit = false;
...@@ -92,7 +94,7 @@ export class TerminalInstance implements ITerminalInstance { ...@@ -92,7 +94,7 @@ export class TerminalInstance implements ITerminalInstance {
} }
public addDisposable(disposable: lifecycle.IDisposable): void { public addDisposable(disposable: lifecycle.IDisposable): void {
this._toDispose.push(disposable); this._instanceDisposables.push(disposable);
} }
public attachToElement(container: HTMLElement): void { public attachToElement(container: HTMLElement): void {
...@@ -112,10 +114,12 @@ export class TerminalInstance implements ITerminalInstance { ...@@ -112,10 +114,12 @@ export class TerminalInstance implements ITerminalInstance {
this._process.on('message', (message) => this._sendPtyDataToXterm(message)); this._process.on('message', (message) => this._sendPtyDataToXterm(message));
this._xterm.on('data', (data) => { this._xterm.on('data', (data) => {
this._process.send({ if (this._process) {
event: 'input', this._process.send({
data: this._sanitizeInput(data) event: 'input',
}); data: this._sanitizeInput(data)
});
}
return false; return false;
}); });
this._xterm.attachCustomKeydownHandler((event: KeyboardEvent) => { this._xterm.attachCustomKeydownHandler((event: KeyboardEvent) => {
...@@ -139,48 +143,48 @@ export class TerminalInstance implements ITerminalInstance { ...@@ -139,48 +143,48 @@ export class TerminalInstance implements ITerminalInstance {
return false; return false;
} }
}); });
(<HTMLElement>this._xterm.element).addEventListener('mouseup', event => { this._instanceDisposables.push(DOM.addDisposableListener(this._xterm.element, 'mouseup', (event: KeyboardEvent) => {
// Wait until mouseup has propogated through the DOM before evaluating the new selection // Wait until mouseup has propogated through the DOM before evaluating the new selection
// state. // state.
setTimeout(() => { setTimeout(() => {
this._refreshSelectionContextKey(); this._refreshSelectionContextKey();
}, 0); }, 0);
}); }));
// xterm.js currently drops selection on keyup as we need to handle this case. // xterm.js currently drops selection on keyup as we need to handle this case.
(<HTMLElement>this._xterm.element).addEventListener('keyup', event => { this._instanceDisposables.push(DOM.addDisposableListener(this._xterm.element, 'keyup', (event: KeyboardEvent) => {
// Wait until keyup has propogated through the DOM before evaluating the new selection // Wait until keyup has propogated through the DOM before evaluating the new selection
// state. // state.
setTimeout(() => { setTimeout(() => {
this._refreshSelectionContextKey(); this._refreshSelectionContextKey();
}, 0); }, 0);
}); }));
const xtermHelper: HTMLElement = this._xterm.element.querySelector('.xterm-helpers'); const xtermHelper: HTMLElement = this._xterm.element.querySelector('.xterm-helpers');
const focusTrap: HTMLElement = document.createElement('div'); const focusTrap: HTMLElement = document.createElement('div');
focusTrap.setAttribute('tabindex', '0'); focusTrap.setAttribute('tabindex', '0');
DOM.addClass(focusTrap, 'focus-trap'); DOM.addClass(focusTrap, 'focus-trap');
focusTrap.addEventListener('focus', function (event: FocusEvent) { this._instanceDisposables.push(DOM.addDisposableListener(focusTrap, 'focus', (event: FocusEvent) => {
let currentElement = focusTrap; let currentElement = focusTrap;
while (!DOM.hasClass(currentElement, 'part')) { while (!DOM.hasClass(currentElement, 'part')) {
currentElement = currentElement.parentElement; currentElement = currentElement.parentElement;
} }
const hidePanelElement = <HTMLElement>currentElement.querySelector('.hide-panel-action'); const hidePanelElement = <HTMLElement>currentElement.querySelector('.hide-panel-action');
hidePanelElement.focus(); hidePanelElement.focus();
}); }));
xtermHelper.insertBefore(focusTrap, this._xterm.textarea); xtermHelper.insertBefore(focusTrap, this._xterm.textarea);
this._toDispose.push(DOM.addDisposableListener(this._xterm.textarea, 'focus', (event: KeyboardEvent) => { this._instanceDisposables.push(DOM.addDisposableListener(this._xterm.textarea, 'focus', (event: KeyboardEvent) => {
this._terminalFocusContextKey.set(true); this._terminalFocusContextKey.set(true);
})); }));
this._toDispose.push(DOM.addDisposableListener(this._xterm.textarea, 'blur', (event: KeyboardEvent) => { this._instanceDisposables.push(DOM.addDisposableListener(this._xterm.textarea, 'blur', (event: KeyboardEvent) => {
this._terminalFocusContextKey.reset(); this._terminalFocusContextKey.reset();
this._refreshSelectionContextKey(); this._refreshSelectionContextKey();
})); }));
this._toDispose.push(DOM.addDisposableListener(this._xterm.element, 'focus', (event: KeyboardEvent) => { this._instanceDisposables.push(DOM.addDisposableListener(this._xterm.element, 'focus', (event: KeyboardEvent) => {
this._terminalFocusContextKey.set(true); this._terminalFocusContextKey.set(true);
})); }));
this._toDispose.push(DOM.addDisposableListener(this._xterm.element, 'blur', (event: KeyboardEvent) => { this._instanceDisposables.push(DOM.addDisposableListener(this._xterm.element, 'blur', (event: KeyboardEvent) => {
this._terminalFocusContextKey.reset(); this._terminalFocusContextKey.reset();
this._refreshSelectionContextKey(); this._refreshSelectionContextKey();
})); }));
...@@ -231,7 +235,8 @@ export class TerminalInstance implements ITerminalInstance { ...@@ -231,7 +235,8 @@ export class TerminalInstance implements ITerminalInstance {
this._process = null; this._process = null;
} }
this._onDisposed.fire(this); this._onDisposed.fire(this);
this._toDispose = lifecycle.dispose(this._toDispose); this._processDisposables = lifecycle.dispose(this._processDisposables);
this._instanceDisposables = lifecycle.dispose(this._instanceDisposables);
} }
public focus(force?: boolean): void { public focus(force?: boolean): void {
...@@ -396,9 +401,9 @@ export class TerminalInstance implements ITerminalInstance { ...@@ -396,9 +401,9 @@ export class TerminalInstance implements ITerminalInstance {
this._xterm.writeln(nls.localize('terminal.integrated.waitOnExit', 'Press any key to close the terminal')); this._xterm.writeln(nls.localize('terminal.integrated.waitOnExit', 'Press any key to close the terminal'));
// Disable all input if the terminal is exiting and listen for next keypress // Disable all input if the terminal is exiting and listen for next keypress
this._xterm.setOption('disableStdin', true); this._xterm.setOption('disableStdin', true);
(<HTMLElement>this._xterm.textarea).addEventListener('keypress', (data) => { this._processDisposables.push(DOM.addDisposableListener(this._xterm.textarea, 'keypress', () => {
this.dispose(); this.dispose();
}); }));
} else { } else {
this.dispose(); this.dispose();
if (exitCode) { if (exitCode) {
...@@ -420,7 +425,8 @@ export class TerminalInstance implements ITerminalInstance { ...@@ -420,7 +425,8 @@ export class TerminalInstance implements ITerminalInstance {
} }
} }
public reuseTerminal(shell: IShellLaunchConfig): void { public reuseTerminal(shell?: IShellLaunchConfig): void {
// Kill and clean up old process
if (this._process) { if (this._process) {
this._process.removeAllListeners('exit'); this._process.removeAllListeners('exit');
if (this._process.connected) { if (this._process.connected) {
...@@ -428,14 +434,22 @@ export class TerminalInstance implements ITerminalInstance { ...@@ -428,14 +434,22 @@ export class TerminalInstance implements ITerminalInstance {
} }
this._process = null; this._process = null;
} }
lifecycle.dispose(this._processDisposables);
this._processDisposables = [];
// Ensure new processes' output starts at start of new line // Ensure new processes' output starts at start of new line
this._xterm.write('\n\x1b[G'); this._xterm.write('\n\x1b[G');
// Initialize new process
this._createProcess(this._contextService.getWorkspace(), shell.name, shell); this._createProcess(this._contextService.getWorkspace(), shell.name, shell);
this._process.on('message', (message) => this._sendPtyDataToXterm(message)); this._process.on('message', (message) => this._sendPtyDataToXterm(message));
// TODO: Get rid of wait for any key listeners and any other listeners that are no longer valid
// Clean up waitOnExit state
if (this._isExiting && this._shellLaunchConfig.waitOnExit) { if (this._isExiting && this._shellLaunchConfig.waitOnExit) {
this._xterm.setOption('disableStdin', false); this._xterm.setOption('disableStdin', false);
this._isExiting = false;
} }
// Set the new shell launch config // Set the new shell launch config
this._shellLaunchConfig = shell; this._shellLaunchConfig = shell;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册