diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index b7d219b1e5c..17b2175f78e 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -648,6 +648,7 @@ "./vs/workbench/parts/terminal/common/terminalMenu.ts", "./vs/workbench/parts/terminal/common/terminalService.ts", "./vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts", + "./vs/workbench/parts/terminal/electron-browser/terminalInstance.ts", "./vs/workbench/parts/terminal/electron-browser/terminalLinkHandler.ts", "./vs/workbench/parts/terminal/electron-browser/terminalProcessManager.ts", "./vs/workbench/parts/terminal/node/terminal.ts", diff --git a/src/vs/workbench/parts/terminal/common/terminal.ts b/src/vs/workbench/parts/terminal/common/terminal.ts index 0f276870ab5..41114e0c75b 100644 --- a/src/vs/workbench/parts/terminal/common/terminal.ts +++ b/src/vs/workbench/parts/terminal/common/terminal.ts @@ -584,7 +584,7 @@ export interface ITerminalInstance { * * @param shell The new launch configuration. */ - reuseTerminal(shell?: IShellLaunchConfig): void; + reuseTerminal(shell: IShellLaunchConfig): void; /** * Sets the title of the terminal instance. diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts index 3e8d85d2be9..2a655fa9dfc 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalInstance.ts @@ -48,7 +48,7 @@ let Terminal: typeof XTermTerminal; export class TerminalInstance implements ITerminalInstance { private static readonly EOL_REGEX = /\r?\n/g; - private static _lastKnownDimensions: dom.Dimension = null; + private static _lastKnownDimensions: dom.Dimension | null = null; private static _idCounter = 1; private _processManager: ITerminalProcessManager | undefined; @@ -189,7 +189,7 @@ export class TerminalInstance implements ITerminalInstance { return; } - const computedStyle = window.getComputedStyle(this._container.parentElement); + const computedStyle = window.getComputedStyle(this._container.parentElement!); const width = parseInt(computedStyle.getPropertyValue('width').replace('px', ''), 10); const height = parseInt(computedStyle.getPropertyValue('height').replace('px', ''), 10); this._evaluateColsAndRows(width, height); @@ -201,7 +201,7 @@ export class TerminalInstance implements ITerminalInstance { * @param height The height of the container. * @return The terminal's width if it requires a layout. */ - private _evaluateColsAndRows(width: number, height: number): number { + private _evaluateColsAndRows(width: number, height: number): number | null { // Ignore if dimensions are undefined or 0 if (!width || !height) { return null; @@ -213,6 +213,9 @@ export class TerminalInstance implements ITerminalInstance { } const font = this._configHelper.getFont(this._xterm); + if (!font.charWidth || !font.charHeight) { + return null; + } // Because xterm.js converts from CSS pixels to actual pixels through // the use of canvas, window.devicePixelRatio needs to be used here in @@ -236,7 +239,7 @@ export class TerminalInstance implements ITerminalInstance { return dimension.width; } - private _getDimension(width: number, height: number): dom.Dimension { + private _getDimension(width: number, height: number): dom.Dimension | null { // The font needs to have been initialized const font = this._configHelper.getFont(this._xterm); if (!font || !font.charWidth || !font.charHeight) { @@ -261,9 +264,9 @@ export class TerminalInstance implements ITerminalInstance { } const wrapperElementStyle = getComputedStyle(this._wrapperElement); - const marginLeft = parseInt(wrapperElementStyle.marginLeft.split('px')[0], 10); - const marginRight = parseInt(wrapperElementStyle.marginRight.split('px')[0], 10); - const bottom = parseInt(wrapperElementStyle.bottom.split('px')[0], 10); + const marginLeft = parseInt(wrapperElementStyle.marginLeft!.split('px')[0], 10); + const marginRight = parseInt(wrapperElementStyle.marginRight!.split('px')[0], 10); + const bottom = parseInt(wrapperElementStyle.bottom!.split('px')[0], 10); const innerWidth = width - marginLeft - marginRight; const innerHeight = height - bottom; @@ -320,11 +323,11 @@ export class TerminalInstance implements ITerminalInstance { if (this._processManager) { this._processManager.onProcessData(data => this._onProcessData(data)); - this._xterm.on('data', data => this._processManager.write(data)); + this._xterm.on('data', data => this._processManager!.write(data)); // TODO: How does the cwd work on detached processes? this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, this._xterm, platform.platform); this.processReady.then(() => { - this._linkHandler.processCwd = this._processManager.initialCwd; + this._linkHandler.processCwd = this._processManager!.initialCwd; }); } this._xterm.on('focus', () => this._onFocus.fire(this)); @@ -383,7 +386,7 @@ export class TerminalInstance implements ITerminalInstance { (this._wrapperElement).xterm = this._xterm; this._xterm.open(this._xtermElement); - this._xterm.attachCustomKeyEventHandler((event: KeyboardEvent) => { + this._xterm.attachCustomKeyEventHandler((event: KeyboardEvent): boolean => { // Disable all input if the terminal is exiting if (this._isExiting) { return false; @@ -408,7 +411,7 @@ export class TerminalInstance implements ITerminalInstance { return false; } - return undefined; + return true; }); this._disposables.push(dom.addDisposableListener(this._xterm.element, 'mousedown', () => { // We need to listen to the mouseup event on the document since the user may release @@ -435,7 +438,7 @@ export class TerminalInstance implements ITerminalInstance { this._disposables.push(dom.addDisposableListener(focusTrap, 'focus', () => { let currentElement = focusTrap; while (!dom.hasClass(currentElement, 'part')) { - currentElement = currentElement.parentElement; + currentElement = currentElement.parentElement!; } const hidePanelElement = currentElement.querySelector('.hide-panel-action'); hidePanelElement.focus(); @@ -598,15 +601,14 @@ export class TerminalInstance implements ITerminalInstance { if ((this._wrapperElement).xterm) { (this._wrapperElement).xterm = null; } - this._container.removeChild(this._wrapperElement); - this._wrapperElement = null; - this._xtermElement = null; + if (this._wrapperElement.parentElement) { + this._container.removeChild(this._wrapperElement); + } } if (this._xterm) { const buffer = (this._xterm._core.buffer); this._sendLineData(buffer, buffer.ybase + buffer.y); this._xterm.dispose(); - this._xterm = null; } if (this._processManager) { this._processManager.dispose(immediate); @@ -664,7 +666,7 @@ export class TerminalInstance implements ITerminalInstance { // If the terminal has a process, send it to the process if (this._processManager) { this._processManager.ptyProcessReady.then(() => { - this._processManager.write(text); + this._processManager!.write(text); }); } } @@ -675,6 +677,10 @@ export class TerminalInstance implements ITerminalInstance { const hasSpace = path.indexOf(' ') !== -1; if (platform.isWindows) { const exe = this.shellLaunchConfig.executable; + if (!exe) { + c(path); + return; + } // 17063 is the build number where wsl path was introduced. // Update Windows uriPath to be executed in WSL. if (((exe.indexOf('wsl') !== -1) || ((exe.indexOf('bash.exe') !== -1) && (exe.indexOf('git') === -1))) && (TerminalInstance.getWindowsBuildNumber() >= 17063)) { @@ -796,7 +802,7 @@ export class TerminalInstance implements ITerminalInstance { this._processManager.ptyProcessReady.then(() => { this._xtermReadyPromise.then(() => { if (!this._isDisposed) { - this._windowsShellHelper = new WindowsShellHelper(this._processManager.shellProcessId, this, this._xterm); + this._windowsShellHelper = new WindowsShellHelper(this._processManager!.shellProcessId, this, this._xterm); } }); }); @@ -805,7 +811,7 @@ export class TerminalInstance implements ITerminalInstance { // Create the process asynchronously to allow the terminal's container // to be created so dimensions are accurate setTimeout(() => { - this._processManager.createProcess(this._shellLaunchConfig, this._cols, this._rows); + this._processManager!.createProcess(this._shellLaunchConfig, this._cols, this._rows); }, 0); } @@ -833,13 +839,13 @@ export class TerminalInstance implements ITerminalInstance { exitCodeMessage = nls.localize('terminal.integrated.exitedWithCode', 'The terminal process terminated with exit code: {0}', exitCode); } - this._logService.debug(`Terminal process exit (id: ${this.id}) state ${this._processManager.processState}`); + this._logService.debug(`Terminal process exit (id: ${this.id}) state ${this._processManager!.processState}`); // Only trigger wait on exit when the exit was *not* triggered by the // user (via the `workbench.action.terminal.kill` command). - if (this._shellLaunchConfig.waitOnExit && this._processManager.processState !== ProcessState.KILLED_BY_USER) { + if (this._shellLaunchConfig.waitOnExit && this._processManager!.processState !== ProcessState.KILLED_BY_USER) { if (exitCode) { - this._xterm.writeln(exitCodeMessage); + this._xterm.writeln(exitCodeMessage!); } if (typeof this._shellLaunchConfig.waitOnExit === 'string') { let message = this._shellLaunchConfig.waitOnExit; @@ -855,7 +861,7 @@ export class TerminalInstance implements ITerminalInstance { } else { this.dispose(); if (exitCode) { - if (this._processManager.processState === ProcessState.KILLED_DURING_LAUNCH) { + if (this._processManager!.processState === ProcessState.KILLED_DURING_LAUNCH) { let args = ''; if (typeof this._shellLaunchConfig.args === 'string') { args = this._shellLaunchConfig.args; @@ -874,9 +880,9 @@ export class TerminalInstance implements ITerminalInstance { } } else { if (this._configHelper.config.showExitAlert) { - this._notificationService.error(exitCodeMessage); + this._notificationService.error(exitCodeMessage!); } else { - console.warn(exitCodeMessage); + console.warn(exitCodeMessage!); } } } @@ -886,15 +892,15 @@ export class TerminalInstance implements ITerminalInstance { } private _attachPressAnyKeyToCloseListener() { - this._processManager.addDisposable(dom.addDisposableListener(this._xterm.textarea, 'keypress', (event: KeyboardEvent) => { + this._processManager!.addDisposable(dom.addDisposableListener(this._xterm.textarea, 'keypress', (event: KeyboardEvent) => { this.dispose(); event.preventDefault(); })); } - public reuseTerminal(shell?: IShellLaunchConfig): void { + public reuseTerminal(shell: IShellLaunchConfig): void { // Kill and clear up the process, making the process manager ready for a new process - this._processManager.dispose(); + this._processManager!.dispose(); // Ensure new processes' output starts at start of new line this._xterm.write('\n\x1b[G'); @@ -918,7 +924,7 @@ export class TerminalInstance implements ITerminalInstance { if (oldTitle !== this._title) { this.setTitle(this._title, true); } - this._processManager.onProcessData(data => this._onProcessData(data)); + this._processManager!.onProcessData(data => this._onProcessData(data)); } private _sendRendererInput(input: string): void { @@ -1086,11 +1092,11 @@ export class TerminalInstance implements ITerminalInstance { } if (this._processManager) { - this._processManager.ptyProcessReady.then(() => this._processManager.setDimensions(cols, rows)); + this._processManager.ptyProcessReady.then(() => this._processManager!.setDimensions(cols, rows)); } } - public setTitle(title: string, eventFromProcess: boolean): void { + public setTitle(title: string | undefined, eventFromProcess: boolean): void { if (!title) { return; } @@ -1105,7 +1111,6 @@ export class TerminalInstance implements ITerminalInstance { // automatically updates the terminal name if (this._messageTitleDisposable) { lifecycle.dispose(this._messageTitleDisposable); - this._messageTitleDisposable = null; } } const didTitleChange = title !== this._title; @@ -1145,22 +1150,22 @@ export class TerminalInstance implements ITerminalInstance { cursor: cursorColor ? cursorColor.toString() : null, cursorAccent: cursorAccentColor ? cursorAccentColor.toString() : null, selection: selectionColor ? selectionColor.toString() : null, - black: theme.getColor(ansiColorIdentifiers[0]).toString(), - red: theme.getColor(ansiColorIdentifiers[1]).toString(), - green: theme.getColor(ansiColorIdentifiers[2]).toString(), - yellow: theme.getColor(ansiColorIdentifiers[3]).toString(), - blue: theme.getColor(ansiColorIdentifiers[4]).toString(), - magenta: theme.getColor(ansiColorIdentifiers[5]).toString(), - cyan: theme.getColor(ansiColorIdentifiers[6]).toString(), - white: theme.getColor(ansiColorIdentifiers[7]).toString(), - brightBlack: theme.getColor(ansiColorIdentifiers[8]).toString(), - brightRed: theme.getColor(ansiColorIdentifiers[9]).toString(), - brightGreen: theme.getColor(ansiColorIdentifiers[10]).toString(), - brightYellow: theme.getColor(ansiColorIdentifiers[11]).toString(), - brightBlue: theme.getColor(ansiColorIdentifiers[12]).toString(), - brightMagenta: theme.getColor(ansiColorIdentifiers[13]).toString(), - brightCyan: theme.getColor(ansiColorIdentifiers[14]).toString(), - brightWhite: theme.getColor(ansiColorIdentifiers[15]).toString() + black: theme.getColor(ansiColorIdentifiers[0])!.toString(), + red: theme.getColor(ansiColorIdentifiers[1])!.toString(), + green: theme.getColor(ansiColorIdentifiers[2])!.toString(), + yellow: theme.getColor(ansiColorIdentifiers[3])!.toString(), + blue: theme.getColor(ansiColorIdentifiers[4])!.toString(), + magenta: theme.getColor(ansiColorIdentifiers[5])!.toString(), + cyan: theme.getColor(ansiColorIdentifiers[6])!.toString(), + white: theme.getColor(ansiColorIdentifiers[7])!.toString(), + brightBlack: theme.getColor(ansiColorIdentifiers[8])!.toString(), + brightRed: theme.getColor(ansiColorIdentifiers[9])!.toString(), + brightGreen: theme.getColor(ansiColorIdentifiers[10])!.toString(), + brightYellow: theme.getColor(ansiColorIdentifiers[11])!.toString(), + brightBlue: theme.getColor(ansiColorIdentifiers[12])!.toString(), + brightMagenta: theme.getColor(ansiColorIdentifiers[13])!.toString(), + brightCyan: theme.getColor(ansiColorIdentifiers[14])!.toString(), + brightWhite: theme.getColor(ansiColorIdentifiers[15])!.toString() }; }