diff --git a/src/vs/workbench/contrib/terminal/browser/addons/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/addons/xtermTerminal.ts new file mode 100644 index 0000000000000..65735a6caec9f --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/addons/xtermTerminal.ts @@ -0,0 +1,143 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type { ITheme, RendererType, Terminal as IXtermTerminal } from 'xterm'; +// import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { TerminalLocation, TerminalSettingId } from 'vs/platform/terminal/common/terminal'; +import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import { IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views'; +import { editorBackground } from 'vs/platform/theme/common/colorRegistry'; +import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; +import { TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal'; +import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; +import { Color } from 'vs/base/common/color'; + +export const enum XtermTerminalConstants { + DefaultCols = 80, + DefaultRows = 30, + MaxSupportedCols = 5000, + MaxCanvasWidth = 8000 +} + +/** + * Wraps the xterm object with additional functionality. Interaction with the backing process is out + * of the scope of this class. + */ +export class XtermTerminal extends DisposableStore { + /** The raw xterm.js instance */ + readonly raw: IXtermTerminal; + target?: TerminalLocation; + + // private _core: IXtermCore; + private static _suggestedRendererType: 'canvas' | 'dom' | undefined = undefined; + private _cols: number = 0; + private _rows: number = 0; + + /** + * @param xtermCtor The xterm.js constructor, this is passed in so it can be fetched lazily + * outside of this class such that {@link raw} is not nullable. + */ + constructor( + xtermCtor: typeof IXtermTerminal, + private readonly _configHelper: TerminalConfigHelper, + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IThemeService private readonly _themeService: IThemeService, + @IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService, + ) { + super(); + + const font = this._configHelper.getFont(undefined, true); + const config = this._configHelper.config; + const editorOptions = this._configurationService.getValue('editor'); + + this.raw = this.add(new xtermCtor({ + cols: this._cols || XtermTerminalConstants.DefaultCols, + rows: this._rows || XtermTerminalConstants.DefaultRows, + altClickMovesCursor: config.altClickMovesCursor && editorOptions.multiCursorModifier === 'alt', + scrollback: config.scrollback, + theme: this._getXtermTheme(), + drawBoldTextInBrightColors: config.drawBoldTextInBrightColors, + fontFamily: font.fontFamily, + fontWeight: config.fontWeight, + fontWeightBold: config.fontWeightBold, + fontSize: font.fontSize, + letterSpacing: font.letterSpacing, + lineHeight: font.lineHeight, + minimumContrastRatio: config.minimumContrastRatio, + cursorBlink: config.cursorBlinking, + cursorStyle: config.cursorStyle === 'line' ? 'bar' : config.cursorStyle, + cursorWidth: config.cursorWidth, + bellStyle: 'none', + macOptionIsMeta: config.macOptionIsMeta, + macOptionClickForcesSelection: config.macOptionClickForcesSelection, + rightClickSelectsWord: config.rightClickBehavior === 'selectWord', + fastScrollModifier: 'alt', + fastScrollSensitivity: editorOptions.fastScrollSensitivity, + scrollSensitivity: editorOptions.mouseWheelScrollSensitivity, + rendererType: this._getBuiltInXtermRenderer(config.gpuAcceleration, XtermTerminal._suggestedRendererType), + wordSeparator: config.wordSeparators + })); + + this.add(this._configurationService.onDidChangeConfiguration(async e => { + if (e.affectsConfiguration(TerminalSettingId.GpuAcceleration)) { + XtermTerminal._suggestedRendererType = undefined; + } + })); + } + + private _getBuiltInXtermRenderer(gpuAcceleration: string, suggestedRendererType?: string): RendererType { + let rendererType: RendererType = 'canvas'; + if (gpuAcceleration === 'off' || (gpuAcceleration === 'auto' && suggestedRendererType === 'dom')) { + rendererType = 'dom'; + } + return rendererType; + } + + private _getXtermTheme(theme?: IColorTheme): ITheme { + if (!theme) { + theme = this._themeService.getColorTheme(); + } + + const location = this._viewDescriptorService.getViewLocationById(TERMINAL_VIEW_ID)!; + const foregroundColor = theme.getColor(TERMINAL_FOREGROUND_COLOR); + let backgroundColor: Color | undefined; + if (this.target === TerminalLocation.Editor) { + backgroundColor = theme.getColor(TERMINAL_BACKGROUND_COLOR) || theme.getColor(editorBackground); + } else { + backgroundColor = theme.getColor(TERMINAL_BACKGROUND_COLOR) || (location === ViewContainerLocation.Panel ? theme.getColor(PANEL_BACKGROUND) : theme.getColor(SIDE_BAR_BACKGROUND)); + } + const cursorColor = theme.getColor(TERMINAL_CURSOR_FOREGROUND_COLOR) || foregroundColor; + const cursorAccentColor = theme.getColor(TERMINAL_CURSOR_BACKGROUND_COLOR) || backgroundColor; + const selectionColor = theme.getColor(TERMINAL_SELECTION_BACKGROUND_COLOR); + + return { + background: backgroundColor ? backgroundColor.toString() : undefined, + foreground: foregroundColor ? foregroundColor.toString() : undefined, + cursor: cursorColor ? cursorColor.toString() : undefined, + cursorAccent: cursorAccentColor ? cursorAccentColor.toString() : undefined, + selection: selectionColor ? selectionColor.toString() : undefined, + 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() + }; + } +} diff --git a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts index fda5316ce1352..d76761635fdf5 100644 --- a/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/links/terminalLinkManager.ts @@ -23,7 +23,7 @@ import { TerminalProtocolLinkProvider } from 'vs/workbench/contrib/terminal/brow import { TerminalValidatedLocalLinkProvider, lineAndColumnClause, unixLocalLinkClause, winLocalLinkClause, winDrivePrefix, winLineAndColumnMatchIndex, unixLineAndColumnMatchIndex, lineAndColumnClauseGroupCount } from 'vs/workbench/contrib/terminal/browser/links/terminalValidatedLocalLinkProvider'; import { TerminalWordLinkProvider } from 'vs/workbench/contrib/terminal/browser/links/terminalWordLinkProvider'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; +import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; import { TerminalHover, ILinkHoverTargetOptions } from 'vs/workbench/contrib/terminal/browser/widgets/terminalHoverWidget'; import { TerminalLink } from 'vs/workbench/contrib/terminal/browser/links/terminalLink'; import { TerminalExternalLinkProviderAdapter } from 'vs/workbench/contrib/terminal/browser/links/terminalExternalLinkProviderAdapter'; @@ -94,7 +94,7 @@ export class TerminalLinkManager extends DisposableStore { return; } - const core = (this._xterm as any)._core as XTermCore; + const core = (this._xterm as any)._core as IXtermCore; const cellDimensions = { width: core._renderService.dimensions.actualCellWidth, height: core._renderService.dimensions.actualCellHeight diff --git a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts index 8ad20f4f43df9..dff4154376e5a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts @@ -17,7 +17,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { InstallRecommendedExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { IProductService } from 'vs/platform/product/common/productService'; -import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; +import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; import { IShellLaunchConfig } from 'vs/platform/terminal/common/terminal'; import { isLinux, isWindows } from 'vs/base/common/platform'; @@ -154,7 +154,7 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper { * Gets the font information based on the terminal.integrated.fontFamily * terminal.integrated.fontSize, terminal.integrated.lineHeight configuration properties */ - getFont(xtermCore?: XTermCore, excludeDimensions?: boolean): ITerminalFont { + getFont(xtermCore?: IXtermCore, excludeDimensions?: boolean): ITerminalFont { const editorConfig = this._configurationService.getValue('editor'); let fontFamily = this.config.fontFamily || editorConfig.fontFamily || EDITOR_FONT_DEFAULTS.fontFamily; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index cd45b4a33ecf2..fca02407cb907 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -37,7 +37,7 @@ import type { Unicode11Addon } from 'xterm-addon-unicode11'; import type { WebglAddon } from 'xterm-addon-webgl'; import { CommandTrackerAddon } from 'vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon'; import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/addons/navigationModeAddon'; -import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; +import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IViewsService, IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views'; import { EnvironmentVariableInfoWidget } from 'vs/workbench/contrib/terminal/browser/widgets/environmentVariableInfoWidget'; @@ -74,6 +74,7 @@ import { IPathService } from 'vs/workbench/services/path/common/pathService'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { LineDataEventAddon } from 'vs/workbench/contrib/terminal/browser/addons/lineDataEventAddon'; +import { XtermTerminal } from 'vs/workbench/contrib/terminal/browser/addons/xtermTerminal'; // How long in milliseconds should an average frame take to render for a notification to appear // which suggests the fallback DOM-based renderer @@ -135,8 +136,9 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _titleSource: TitleEventSource = TitleEventSource.Process; private _container: HTMLElement | undefined; private _wrapperElement: (HTMLElement & { xterm?: XTermTerminal }) | undefined; - private _xterm: XTermTerminal | undefined; - private _xtermCore: XTermCore | undefined; + private _xterm: XtermTerminal | undefined; + // private _xterm: XTermTerminal | undefined; + private _xtermCore: IXtermCore | undefined; private _xtermTypeAhead: TypeAheadAddon | undefined; private _xtermSearch: SearchAddon | undefined; private _xtermUnicode11: Unicode11Addon | undefined; @@ -613,51 +615,23 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { */ protected async _createXterm(): Promise { const Terminal = await this._getXtermConstructor(); - const font = this._configHelper.getFont(undefined, true); - const config = this._configHelper.config; - const editorOptions = this._configurationService.getValue('editor'); - const xterm = new Terminal({ - cols: this._cols || Constants.DefaultCols, - rows: this._rows || Constants.DefaultRows, - altClickMovesCursor: config.altClickMovesCursor && editorOptions.multiCursorModifier === 'alt', - scrollback: config.scrollback, - theme: this._getXtermTheme(), - drawBoldTextInBrightColors: config.drawBoldTextInBrightColors, - fontFamily: font.fontFamily, - fontWeight: config.fontWeight, - fontWeightBold: config.fontWeightBold, - fontSize: font.fontSize, - letterSpacing: font.letterSpacing, - lineHeight: font.lineHeight, - minimumContrastRatio: config.minimumContrastRatio, - cursorBlink: config.cursorBlinking, - cursorStyle: config.cursorStyle === 'line' ? 'bar' : config.cursorStyle, - cursorWidth: config.cursorWidth, - bellStyle: 'none', - macOptionIsMeta: config.macOptionIsMeta, - macOptionClickForcesSelection: config.macOptionClickForcesSelection, - rightClickSelectsWord: config.rightClickBehavior === 'selectWord', - fastScrollModifier: 'alt', - fastScrollSensitivity: editorOptions.fastScrollSensitivity, - scrollSensitivity: editorOptions.mouseWheelScrollSensitivity, - rendererType: this._getBuiltInXtermRenderer(config.gpuAcceleration, TerminalInstance._suggestedRendererType), - wordSeparator: config.wordSeparators - }); + // TODO: Move cols/rows over to XtermTerminal + const xterm = this._instantiationService.createInstance(XtermTerminal, Terminal, this._configHelper); this._xterm = xterm; - this._xtermCore = (xterm as any)._core as XTermCore; + this._xtermCore = (xterm as any)._core as IXtermCore; const lineDataEventAddon = new LineDataEventAddon(); - this._xterm.loadAddon(lineDataEventAddon); + this._xterm.raw.loadAddon(lineDataEventAddon); this._updateUnicodeVersion(); this.updateAccessibilitySupport(); this._terminalInstanceService.getXtermSearchConstructor().then(addonCtor => { this._xtermSearch = new addonCtor(); - xterm.loadAddon(this._xtermSearch); + xterm.raw.loadAddon(this._xtermSearch); }); // Write initial text, deferring onLineFeed listener when applicable to avoid firing // onLineData events containing initialText if (this._shellLaunchConfig.initialText) { - this._xterm.writeln(this._shellLaunchConfig.initialText, () => { + this._xterm.raw.writeln(this._shellLaunchConfig.initialText, () => { lineDataEventAddon.onLineData(e => this._onLineData.fire(e)); }); } else { @@ -666,7 +640,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Delay the creation of the bell listener to avoid showing the bell when the terminal // starts up or reconnects setTimeout(() => { - this._xterm?.onBell(() => { + xterm.raw.onBell(() => { if (this._configHelper.config.enableBell) { this.statusList.add({ id: TerminalStatus.Bell, @@ -677,16 +651,16 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } }); }, 1000); - this._xterm.onKey(e => this._onKey(e.key, e.domEvent)); - this._xterm.onSelectionChange(async () => this._onSelectionChange()); - this._xterm.buffer.onBufferChange(() => this._refreshAltBufferContextKey()); + xterm.raw.onKey(e => this._onKey(e.key, e.domEvent)); + xterm.raw.onSelectionChange(async () => this._onSelectionChange()); + xterm.raw.buffer.onBufferChange(() => this._refreshAltBufferContextKey()); this._processManager.onProcessData(e => this._onProcessData(e)); - this._xterm.onData(async data => { + xterm.raw.onData(async data => { await this._processManager.write(data); this._onDidInputData.fire(this); }); - this._xterm.onBinary(data => this._processManager.processBinary(data)); + xterm.raw.onBinary(data => this._processManager.processBinary(data)); this.processReady.then(async () => { if (this._linkManager) { this._linkManager.processCwd = await this._processManager.getInitialCwd(); @@ -704,28 +678,28 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { lineDataEventAddon.setOperatingSystem(this._processManager.os); } if (this._processManager.os === OperatingSystem.Windows) { - xterm.setOption('windowsMode', processTraits.requiresWindowsMode || false); + xterm.raw.setOption('windowsMode', processTraits.requiresWindowsMode || false); } - this._linkManager = this._instantiationService.createInstance(TerminalLinkManager, xterm, this._processManager!); + this._linkManager = this._instantiationService.createInstance(TerminalLinkManager, xterm.raw, this._processManager!); this._areLinksReady = true; this._onLinksReady.fire(this); }); this._commandTrackerAddon = new CommandTrackerAddon(); - this._xterm.loadAddon(this._commandTrackerAddon); - this._register(this._themeService.onDidColorThemeChange(theme => this._updateTheme(xterm, theme))); + xterm.raw.loadAddon(this._commandTrackerAddon); + this._register(this._themeService.onDidColorThemeChange(theme => this._updateTheme(xterm.raw, theme))); this._register(this._viewDescriptorService.onDidChangeLocation(({ views }) => { if (views.some(v => v.id === TERMINAL_VIEW_ID)) { - this._updateTheme(xterm); + this._updateTheme(xterm.raw); } })); this._xtermTypeAhead = this._register(this._instantiationService.createInstance(TypeAheadAddon, this._processManager, this._configHelper)); - this._xterm.loadAddon(this._xtermTypeAhead); + xterm.raw.loadAddon(this._xtermTypeAhead); this._pathService.userHome().then(userHome => { this._userHome = userHome.fsPath; }); - return xterm; + return xterm.raw; } detachFromElement(): void { @@ -749,7 +723,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Update the theme when attaching as the terminal location could have changed if (this._xterm) { - this._updateTheme(this._xterm); + this._updateTheme(this._xterm.raw); } // The container changed, reattach @@ -1002,7 +976,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } hasSelection(): boolean { - return this._xterm ? this._xterm.hasSelection() : false; + return this._xterm ? this._xterm.raw.hasSelection() : false; } async copySelection(): Promise { @@ -1015,17 +989,17 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } get selection(): string | undefined { - return this._xterm && this.hasSelection() ? this._xterm.getSelection() : undefined; + return this._xterm && this.hasSelection() ? this._xterm.raw.getSelection() : undefined; } clearSelection(): void { - this._xterm?.clearSelection(); + this._xterm?.raw.clearSelection(); } selectAll(): void { // Focus here to ensure the terminal context key is set - this._xterm?.focus(); - this._xterm?.selectAll(); + this._xterm?.raw.focus(); + this._xterm?.raw.selectAll(); } findNext(term: string, searchOptions: ISearchOptions): boolean { @@ -1046,12 +1020,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (!this._xterm) { return; } - const terminalFocused = !isFocused && (document.activeElement === this._xterm.textarea || document.activeElement === this._xterm.element); + const terminalFocused = !isFocused && (document.activeElement === this._xterm.raw.textarea || document.activeElement === this._xterm.raw.element); this._terminalFocusContextKey.set(terminalFocused); } private _refreshAltBufferContextKey() { - this._terminalAltBufferActiveContextKey.set(!!(this._xterm && this._xterm.buffer.active === this._xterm.buffer.alternate)); + this._terminalAltBufferActiveContextKey.set(!!(this._xterm && this._xterm.raw.buffer.active === this._xterm.raw.buffer.alternate)); } override dispose(immediate?: boolean): void { @@ -1062,7 +1036,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._commandTrackerAddon = undefined; dispose(this._widgetManager); - if (this._xterm && this._xterm.element) { + if (this._xterm?.raw.element) { this._hadFocusOnExit = this.hasFocus; } if (this._wrapperElement) { @@ -1102,7 +1076,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } this._webglAddon?.clearTextureAtlas(); - this._xterm?.clearTextureAtlas(); + this._xterm?.raw.clearTextureAtlas(); } focus(force?: boolean): void { @@ -1116,7 +1090,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } const text = selection.toString(); if (!text || force) { - this._xterm.focus(); + this._xterm.raw.focus(); } } @@ -1131,7 +1105,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } this.focus(); - this._xterm.paste(await this._clipboardService.readText()); + this._xterm.raw.paste(await this._clipboardService.readText()); } async pasteSelection(): Promise { @@ -1139,7 +1113,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } this.focus(); - this._xterm.paste(await this._clipboardService.readText('selection')); + this._xterm.raw.paste(await this._clipboardService.readText('selection')); } async sendText(text: string, addNewLine: boolean): Promise { @@ -1176,31 +1150,31 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } scrollDownLine(): void { - this._xterm?.scrollLines(1); + this._xterm?.raw.scrollLines(1); } scrollDownPage(): void { - this._xterm?.scrollPages(1); + this._xterm?.raw.scrollPages(1); } scrollToBottom(): void { - this._xterm?.scrollToBottom(); + this._xterm?.raw.scrollToBottom(); } scrollUpLine(): void { - this._xterm?.scrollLines(-1); + this._xterm?.raw.scrollLines(-1); } scrollUpPage(): void { - this._xterm?.scrollPages(-1); + this._xterm?.raw.scrollPages(-1); } scrollToTop(): void { - this._xterm?.scrollToTop(); + this._xterm?.raw.scrollToTop(); } clear(): void { - this._xterm?.clear(); + this._xterm?.raw.clear(); } private _refreshSelectionContextKey() { @@ -1286,7 +1260,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Re-evaluate dimensions if the container has been set since the xterm instance was created if (this._container && this._cols === 0 && this._rows === 0) { this._initDimensions(); - this._xterm?.resize(this._cols || Constants.DefaultCols, this._rows || Constants.DefaultRows); + this._xterm?.raw.resize(this._cols || Constants.DefaultCols, this._rows || Constants.DefaultRows); } const hadIcon = !!this.shellLaunchConfig.icon; @@ -1304,14 +1278,14 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { const messageId = ++this._latestXtermWriteData; if (ev.trackCommit) { ev.writePromise = new Promise(r => { - this._xterm?.write(ev.data, () => { + this._xterm?.raw.write(ev.data, () => { this._latestXtermParseData = messageId; this._processManager.acknowledgeDataEvent(ev.data.length); r(); }); }); } else { - this._xterm?.write(ev.data, () => { + this._xterm?.raw.write(ev.data, () => { this._latestXtermParseData = messageId; this._processManager.acknowledgeDataEvent(ev.data.length); }); @@ -1479,17 +1453,17 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (this._xterm) { if (!reset) { // Ensure new processes' output starts at start of new line - await new Promise(r => this._xterm!.write('\n\x1b[G', r)); + await new Promise(r => this._xterm!.raw.write('\n\x1b[G', r)); } // Print initialText if specified if (shell.initialText) { - await new Promise(r => this._xterm!.writeln(shell.initialText!, r)); + await new Promise(r => this._xterm!.raw.writeln(shell.initialText!, r)); } // Clean up waitOnExit state if (this._isExiting && this._shellLaunchConfig.waitOnExit) { - this._xterm.setOption('disableStdin', false); + this._xterm.raw.setOption('disableStdin', false); this._isExiting = false; } } @@ -1594,13 +1568,13 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } private async _enableWebglRenderer(): Promise { - if (!this._xterm?.element || this._webglAddon) { + if (!this._xterm?.raw.element || this._webglAddon) { return; } const Addon = await this._terminalInstanceService.getXtermWebglConstructor(); this._webglAddon = new Addon(); try { - this._xterm.loadAddon(this._webglAddon); + this._xterm.raw.loadAddon(this._webglAddon); this._webglAddon.onContextLoss(() => { this._logService.info(`Webgl lost context, disposing of webgl renderer`); this._disposeOfWebglRenderer(); @@ -1635,10 +1609,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { if (!this._xtermUnicode11 && this._configHelper.config.unicodeVersion === '11') { const Addon = await this._terminalInstanceService.getXtermUnicode11Constructor(); this._xtermUnicode11 = new Addon(); - this._xterm.loadAddon(this._xtermUnicode11); + this._xterm.raw.loadAddon(this._xtermUnicode11); } - if (this._xterm.unicode.activeVersion !== this._configHelper.config.unicodeVersion) { - this._xterm.unicode.activeVersion = this._configHelper.config.unicodeVersion; + if (this._xterm.raw.unicode.activeVersion !== this._configHelper.config.unicodeVersion) { + this._xterm.raw.unicode.activeVersion = this._configHelper.config.unicodeVersion; this._processManager.setUnicodeVersion(this._configHelper.config.unicodeVersion); } } @@ -1647,32 +1621,32 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { const isEnabled = this._accessibilityService.isScreenReaderOptimized(); if (isEnabled) { this._navigationModeAddon = new NavigationModeAddon(this._terminalA11yTreeFocusContextKey); - this._xterm!.loadAddon(this._navigationModeAddon); + this._xterm!.raw.loadAddon(this._navigationModeAddon); } else { this._navigationModeAddon?.dispose(); this._navigationModeAddon = undefined; } - this._xterm!.setOption('screenReaderMode', isEnabled); + this._xterm!.raw.setOption('screenReaderMode', isEnabled); } private _setCursorBlink(blink: boolean): void { - if (this._xterm && this._xterm.getOption('cursorBlink') !== blink) { - this._xterm.setOption('cursorBlink', blink); - this._xterm.refresh(0, this._xterm.rows - 1); + if (this._xterm && this._xterm.raw.getOption('cursorBlink') !== blink) { + this._xterm.raw.setOption('cursorBlink', blink); + this._xterm.raw.refresh(0, this._xterm.raw.rows - 1); } } private _setCursorStyle(style: string): void { - if (this._xterm && this._xterm.getOption('cursorStyle') !== style) { + if (this._xterm && this._xterm.raw.getOption('cursorStyle') !== style) { // 'line' is used instead of bar in VS Code to be consistent with editor.cursorStyle const xtermOption = style === 'line' ? 'bar' : style; - this._xterm.setOption('cursorStyle', xtermOption); + this._xterm.raw.setOption('cursorStyle', xtermOption); } } private _setCursorWidth(width: number): void { - if (this._xterm && this._xterm.getOption('cursorWidth') !== width) { - this._xterm.setOption('cursorWidth', width); + if (this._xterm && this._xterm.raw.getOption('cursorWidth') !== width) { + this._xterm.raw.setOption('cursorWidth', width); } } @@ -1688,8 +1662,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } - if (this._xterm.getOption(key) !== value) { - this._xterm.setOption(key, value); + if (this._xterm.raw.getOption(key) !== value) { + this._xterm.raw.setOption(key, value); } } @@ -1749,14 +1723,14 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { return; } - if (cols !== this._xterm.cols || rows !== this._xterm.rows) { + if (cols !== this._xterm.raw.cols || rows !== this._xterm.raw.rows) { if (this._fixedRows || this._fixedCols) { await this.updateProperty(ProcessPropertyType.FixedDimensions, { cols: this._fixedCols, rows: this._fixedRows }); } this._onDimensionsChanged.fire(); } - this._xterm.resize(cols, rows); + this._xterm.raw.resize(cols, rows); TerminalInstance._lastKnownGridDimensions = { cols, rows }; if (this._isVisible) { @@ -1764,11 +1738,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // This is to fix an issue where dragging the windpow to the top of the screen to // maximize on Windows/Linux would fire an event saying that the terminal was not // visible. - if (this._xterm.getOption('rendererType') === 'canvas') { + if (this._xterm.raw.getOption('rendererType') === 'canvas') { this._xtermCore._renderService?._onIntersectionChange({ intersectionRatio: 1 }); // HACK: Force a refresh of the screen to ensure links are refresh corrected. // This can probably be removed when the above hack is fixed in Chromium. - this._xterm.refresh(0, this._xterm.rows - 1); + this._xterm.raw.refresh(0, this._xterm.raw.rows - 1); } } } @@ -1807,7 +1781,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { const titleChanged = title !== this._title; this._title = title; this._labelComputer?.refreshLabel(); - this._setAriaLabel(this._xterm, this._instanceId, this._title); + this._setAriaLabel(this._xterm?.raw, this._instanceId, this._title); if (this._titleReadyComplete) { this._titleReadyComplete(title); @@ -1919,7 +1893,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } async toggleSizeToContentWidth(): Promise { - if (!this._xterm?.buffer.active) { + if (!this._xterm?.raw.buffer.active) { return; } if (this._hasScrollBar) { @@ -1932,12 +1906,12 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._horizontalScrollbar?.setScrollDimensions({ scrollWidth: 0 }); } else { let maxCols = 0; - if (!this._xterm.buffer.active.getLine(0)) { + if (!this._xterm.raw.buffer.active.getLine(0)) { return; } - const lineWidth = this._xterm.buffer.active.getLine(0)!.length; - for (let i = this._xterm.buffer.active.length - 1; i >= this._xterm.buffer.active.viewportY; i--) { - const lineInfo = this._getWrappedLineCount(i, this._xterm.buffer.active); + const lineWidth = this._xterm.raw.buffer.active.getLine(0)!.length; + for (let i = this._xterm.raw.buffer.active.length - 1; i >= this._xterm.raw.buffer.active.viewportY; i--) { + const lineInfo = this._getWrappedLineCount(i, this._xterm.raw.buffer.active); maxCols = Math.max(maxCols, ((lineInfo.lineCount * lineWidth) - lineInfo.endSpaces) || 0); i = lineInfo.currentIndex; } @@ -1950,10 +1924,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private async _addScrollbar(): Promise { const charWidth = this._configHelper?.getFont(this._xtermCore).charWidth; - if (!this._xterm?.element || !this._wrapperElement || !this._container || !charWidth || !this._fixedCols) { + if (!this._xterm?.raw.element || !this._wrapperElement || !this._container || !charWidth || !this._fixedCols) { return; } - if (this._fixedCols < this._xterm.buffer.active.getLine(0)!.length) { + if (this._fixedCols < this._xterm.raw.buffer.active.getLine(0)!.length) { // no scrollbar needed return; } @@ -1974,14 +1948,14 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { } this._horizontalScrollbar.setScrollDimensions( { - width: this._xterm.element.clientWidth, + width: this._xterm.raw.element.clientWidth, scrollWidth: this._fixedCols * charWidth }); this._horizontalScrollbar!.getDomNode().style.paddingBottom = '16px'; // work around for https://github.com/xtermjs/xterm.js/issues/3482 - for (let i = this._xterm.buffer.active.viewportY; i < this._xterm.buffer.active.length; i++) { - let line = this._xterm.buffer.active.getLine(i); + for (let i = this._xterm.raw.buffer.active.viewportY; i < this._xterm.raw.buffer.active.length; i++) { + let line = this._xterm.raw.buffer.active.getLine(i); (line as any)._line.isWrapped = false; } } @@ -2022,7 +1996,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { private _onEnvironmentVariableInfoChanged(info: IEnvironmentVariableInfo): void { if (info.requiresAction) { - this._xterm?.textarea?.setAttribute('aria-label', nls.localize('terminalStaleTextBoxAriaLabel', "Terminal {0} environment is stale, run the 'Show Environment Information' command for more information", this._instanceId)); + this._xterm?.raw.textarea?.setAttribute('aria-label', nls.localize('terminalStaleTextBoxAriaLabel', "Terminal {0} environment is stale, run the 'Show Environment Information' command for more information", this._instanceId)); } this._refreshEnvironmentVariableInfoWidgetState(info); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts b/src/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts index 8bdf4fcf67e82..689c92ae0a0c0 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts @@ -11,7 +11,7 @@ import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { escapeRegExpCharacters } from 'vs/base/common/strings'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; -import { XTermAttributes, XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; +import { XtermAttributes, IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; import { DEFAULT_LOCAL_ECHO_EXCLUDE, IBeforeProcessDataEvent, ITerminalConfiguration, ITerminalProcessManager } from 'vs/workbench/contrib/terminal/common/terminal'; import type { IBuffer, IBufferCell, IDisposable, ITerminalAddon, Terminal } from 'xterm'; @@ -44,7 +44,7 @@ const statsToggleOffThreshold = 0.5; // if latency is less than `threshold * thi */ const PREDICTION_OMIT_RE = /^(\x1b\[(\??25[hl]|\??[0-9;]+n))+/; -const core = (terminal: Terminal): XTermCore => (terminal as any)._core; +const core = (terminal: Terminal): IXtermCore => (terminal as any)._core; const flushOutput = (terminal: Terminal) => { // TODO: Flushing output is not possible anymore without async }; @@ -1032,7 +1032,7 @@ export class PredictionTimeline { /** * Gets the escape sequence args to restore state/appearence in the cell. */ -const attributesToArgs = (cell: XTermAttributes) => { +const attributesToArgs = (cell: XtermAttributes) => { if (cell.isAttributeDefault()) { return [0]; } const args = []; @@ -1058,7 +1058,7 @@ const attributesToArgs = (cell: XTermAttributes) => { /** * Gets the escape sequence to restore state/appearence in the cell. */ -const attributesToSeq = (cell: XTermAttributes) => `${CSI}${attributesToArgs(cell).join(';')}m`; +const attributesToSeq = (cell: XtermAttributes) => `${CSI}${attributesToArgs(cell).join(';')}m`; const arrayHasPrefixAt = (a: ReadonlyArray, ai: number, b: ReadonlyArray) => { if (a.length - ai > b.length) { diff --git a/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts b/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts index 35d8ed4ef5580..833423a9084b6 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts @@ -7,9 +7,9 @@ import { IBufferCell } from 'xterm'; -export type XTermAttributes = Omit & { clone?(): XTermAttributes }; +export type XtermAttributes = Omit & { clone?(): XtermAttributes }; -export interface XTermCore { +export interface IXtermCore { viewport?: { _innerRefresh(): void; }; @@ -25,7 +25,7 @@ export interface XTermCore { }; _inputHandler: { - _curAttrData: XTermAttributes; + _curAttrData: XtermAttributes; }; _renderService: { diff --git a/src/vs/workbench/contrib/terminal/test/browser/terminalCommandTracker.test.ts b/src/vs/workbench/contrib/terminal/test/browser/terminalCommandTracker.test.ts index 8a53a67dad112..6f342babbcb48 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/terminalCommandTracker.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/terminalCommandTracker.test.ts @@ -7,10 +7,10 @@ import * as assert from 'assert'; import { Terminal } from 'xterm'; import { CommandTrackerAddon } from 'vs/workbench/contrib/terminal/browser/addons/commandTrackerAddon'; import { isWindows } from 'vs/base/common/platform'; -import { XTermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; +import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; interface TestTerminal extends Terminal { - _core: XTermCore; + _core: IXtermCore; } const ROWS = 10;