diff --git a/src/vs/workbench/contrib/terminal/browser/media/terminal.css b/src/vs/workbench/contrib/terminal/browser/media/terminal.css index 17933a5776d..16275cb5114 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/terminal.css +++ b/src/vs/workbench/contrib/terminal/browser/media/terminal.css @@ -14,6 +14,10 @@ position: relative; } +.terminal-command-decoration.hide { + visibility: hidden; +} + .monaco-workbench .pane-body.integrated-terminal .terminal-outer-container, .monaco-workbench .pane-body.integrated-terminal .terminal-groups-container, .monaco-workbench .pane-body.integrated-terminal .terminal-group, diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index 9dc9017d20f..bb3b8225a5f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -46,6 +46,7 @@ import { getTerminalActionBarArgs } from 'vs/workbench/contrib/terminal/browser/ import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey'; import { getShellIntegrationTooltip } from 'vs/workbench/contrib/terminal/browser/terminalTooltip'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; +import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities'; export class TerminalViewPane extends ViewPane { private _actions: IAction[] | undefined; @@ -65,7 +66,7 @@ export class TerminalViewPane extends ViewPane { @IKeybindingService keybindingService: IKeybindingService, @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IViewDescriptorService viewDescriptorService: IViewDescriptorService, - @IConfigurationService configurationService: IConfigurationService, + @IConfigurationService private readonly _configurationService: IConfigurationService, @IContextMenuService private readonly _contextMenuService: IContextMenuService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @ITerminalService private readonly _terminalService: ITerminalService, @@ -81,7 +82,7 @@ export class TerminalViewPane extends ViewPane { @ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService, @IThemeService private readonly _themeService: IThemeService ) { - super(options, keybindingService, _contextMenuService, configurationService, _contextKeyService, viewDescriptorService, _instantiationService, openerService, themeService, telemetryService); + super(options, keybindingService, _contextMenuService, _configurationService, _contextKeyService, viewDescriptorService, _instantiationService, openerService, themeService, telemetryService); this._register(this._terminalService.onDidRegisterProcessSupport(() => { if (this._actions) { for (const action of this._actions) { @@ -111,20 +112,34 @@ export class TerminalViewPane extends ViewPane { this._terminalTabbedView?.rerenderTabs(); } })); - configurationService.onDidChangeConfiguration(e => { - if ((e.affectsConfiguration(TerminalSettingId.ShellIntegrationDecorationsEnabled) && !configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationsEnabled)) || - (e.affectsConfiguration(TerminalSettingId.ShellIntegrationEnabled) && !configurationService.getValue(TerminalSettingId.ShellIntegrationEnabled))) { - this._parentDomElement?.classList.remove('shell-integration'); - } else if (configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationsEnabled) && configurationService.getValue(TerminalSettingId.ShellIntegrationEnabled)) { - this._parentDomElement?.classList.add('shell-integration'); + _configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration(TerminalSettingId.ShellIntegrationDecorationsEnabled) || e.affectsConfiguration(TerminalSettingId.ShellIntegrationEnabled)) { + this._updateForShellIntegration(); } }); + this._register(this._terminalService.onDidCreateInstance((i) => { + i.capabilities.onDidAddCapability(c => { + if (c === TerminalCapability.CommandDetection && !this._gutterDecorationsEnabled()) { + this._parentDomElement?.classList.add('shell-integration'); + } + }); + })); + this._updateForShellIntegration(); + } - if (configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationsEnabled) && configurationService.getValue(TerminalSettingId.ShellIntegrationEnabled)) { + private _updateForShellIntegration() { + if (this._gutterDecorationsEnabled()) { this._parentDomElement?.classList.add('shell-integration'); + } else { + this._parentDomElement?.classList.remove('shell-integration'); } } + private _gutterDecorationsEnabled(): boolean { + const decorationsEnabled = this._configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationsEnabled); + return (decorationsEnabled === 'both' || decorationsEnabled === 'gutter') && this._configurationService.getValue(TerminalSettingId.ShellIntegrationEnabled); + } + override renderBody(container: HTMLElement): void { super.renderBody(container); diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts index 45b820a935c..31d764e8de2 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts @@ -28,13 +28,14 @@ import { IGenericMarkProperties } from 'vs/platform/terminal/common/terminalProc const enum DecorationSelector { CommandDecoration = 'terminal-command-decoration', + Hide = 'hide', ErrorColor = 'error', DefaultColor = 'default-color', Default = 'default', Codicon = 'codicon', XtermDecoration = 'xterm-decoration', - OverviewRuler = 'xterm-decoration-overview-ruler', - GenericMarkerIcon = 'codicon-circle-small-filled' + GenericMarkerIcon = 'codicon-circle-small-filled', + OverviewRuler = '.xterm-decoration-overview-ruler' } const enum DecorationStyles { @@ -51,6 +52,8 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { private _contextMenuVisible: boolean = false; private _decorations: Map = new Map(); private _placeholderDecoration: IDecoration | undefined; + private _showGutterDecorations?: boolean; + private _showOverviewRulerDecorations?: boolean; private readonly _onDidRequestRunCommand = this._register(new Emitter<{ command: ITerminalCommand; copyAsHtml?: boolean }>()); readonly onDidRequestRunCommand = this._onDidRequestRunCommand.event; @@ -79,9 +82,67 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { this.refreshLayouts(); } else if (e.affectsConfiguration('workbench.colorCustomizations')) { this._refreshStyles(true); + } else if (e.affectsConfiguration(TerminalSettingId.ShellIntegrationDecorationsEnabled)) { + if (this._commandDetectionListeners) { + dispose(this._commandDetectionListeners); + this._commandDetectionListeners = undefined; + } + this._updateDecorationVisibility(); } }); this._themeService.onDidColorThemeChange(() => this._refreshStyles(true)); + this._updateDecorationVisibility(); + this._register(this._capabilities.onDidAddCapability(c => { + if (c === TerminalCapability.CommandDetection) { + this._addCommandDetectionListeners(); + } + })); + this._register(this._capabilities.onDidRemoveCapability(c => { + if (c === TerminalCapability.CommandDetection) { + if (this._commandDetectionListeners) { + dispose(this._commandDetectionListeners); + this._commandDetectionListeners = undefined; + } + } + })); + } + + private _updateDecorationVisibility(): void { + const showDecorations = this._configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationsEnabled); + this._showGutterDecorations = (showDecorations === 'both' || showDecorations === 'gutter'); + this._showOverviewRulerDecorations = (showDecorations === 'both' || showDecorations === 'overviewRuler'); + this._disposeAllDecorations(); + if (this._showGutterDecorations || this._showOverviewRulerDecorations) { + this._attachToCommandCapability(); + this._updateGutterDecorationVisibility(); + } + const currentCommand = this._capabilities.get(TerminalCapability.CommandDetection)?.executingCommandObject; + if (currentCommand) { + this.registerCommandDecoration(currentCommand, true); + } + } + + private _disposeAllDecorations(): void { + this._placeholderDecoration?.dispose(); + for (const value of this._decorations.values()) { + value.decoration.dispose(); + dispose(value.disposables); + } + } + + private _updateGutterDecorationVisibility(): void { + const commandDecorationElements = document.querySelectorAll(DecorationSelector.CommandDecoration); + for (const commandDecorationElement of commandDecorationElements) { + this._updateCommandDecorationVisibility(commandDecorationElement); + } + } + + private _updateCommandDecorationVisibility(commandDecorationElement: Element): void { + if (this._showGutterDecorations) { + commandDecorationElement.classList.remove(DecorationSelector.Hide); + } else { + commandDecorationElement.classList.add(DecorationSelector.Hide); + } } public refreshLayouts(): void { @@ -128,31 +189,14 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { public clearDecorations(): void { this._placeholderDecoration?.marker.dispose(); this._clearPlaceholder(); - for (const value of this._decorations.values()) { - value.decoration.dispose(); - dispose(value.disposables); - } + this._disposeAllDecorations(); this._decorations.clear(); } private _attachToCommandCapability(): void { if (this._capabilities.has(TerminalCapability.CommandDetection)) { this._addCommandDetectionListeners(); - } else { - this._register(this._capabilities.onDidAddCapability(c => { - if (c === TerminalCapability.CommandDetection) { - this._addCommandDetectionListeners(); - } - })); } - this._register(this._capabilities.onDidRemoveCapability(c => { - if (c === TerminalCapability.CommandDetection) { - if (this._commandDetectionListeners) { - dispose(this._commandDetectionListeners); - this._commandDetectionListeners = undefined; - } - } - })); } private _addCommandDetectionListeners(): void { @@ -204,13 +248,12 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { } registerCommandDecoration(command: ITerminalCommand, beforeCommandExecution?: boolean): IDecoration | undefined { - if (!this._terminal || (beforeCommandExecution && command.genericMarkProperties)) { + if (!this._terminal || (beforeCommandExecution && command.genericMarkProperties) || (!this._showGutterDecorations && !this._showOverviewRulerDecorations)) { return undefined; } if (!command.marker) { throw new Error(`cannot add a decoration for a command ${JSON.stringify(command)} with no marker`); } - this._clearPlaceholder(); let color = command.exitCode === undefined ? defaultColor : command.exitCode ? errorColor : successColor; if (color && typeof color !== 'string') { @@ -220,9 +263,9 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { } const decoration = this._terminal.registerDecoration({ marker: command.marker, - overviewRulerOptions: beforeCommandExecution + overviewRulerOptions: this._showOverviewRulerDecorations ? (beforeCommandExecution ? { color, position: 'left' } - : { color, position: command.exitCode ? 'right' : 'left' } + : { color, position: command.exitCode ? 'right' : 'left' }) : undefined }); if (!decoration) { return undefined; @@ -287,20 +330,25 @@ export class DecorationAddon extends Disposable implements ITerminalAddon { element.classList.remove(classes); } element.classList.add(DecorationSelector.CommandDecoration, DecorationSelector.Codicon, DecorationSelector.XtermDecoration); + if (genericMarkProperties) { element.classList.add(DecorationSelector.DefaultColor, DecorationSelector.GenericMarkerIcon); if (!genericMarkProperties.hoverMessage) { //disable the mouse pointer element.classList.add(DecorationSelector.Default); } - } else if (exitCode === undefined) { - element.classList.add(DecorationSelector.DefaultColor, DecorationSelector.Default); - element.classList.add(`codicon-${this._configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationIcon)}`); - } else if (exitCode) { - element.classList.add(DecorationSelector.ErrorColor); - element.classList.add(`codicon-${this._configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationIconError)}`); } else { - element.classList.add(`codicon-${this._configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationIconSuccess)}`); + // command decoration + this._updateCommandDecorationVisibility(element); + if (exitCode === undefined) { + element.classList.add(DecorationSelector.DefaultColor, DecorationSelector.Default); + element.classList.add(`codicon-${this._configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationIcon)}`); + } else if (exitCode) { + element.classList.add(DecorationSelector.ErrorColor); + element.classList.add(`codicon-${this._configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationIconError)}`); + } else { + element.classList.add(`codicon-${this._configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationIconSuccess)}`); + } } } diff --git a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts index 3c5513e7c90..c5b6caee4af 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalConfiguration.ts @@ -117,17 +117,17 @@ const terminalConfiguration: IConfigurationNode = { [TerminalSettingId.ShellIntegrationDecorationIconSuccess]: { type: 'string', default: 'primitive-dot', - markdownDescription: localize('terminal.integrated.shellIntegration.decorationIconSuccess', "Controls the icon that will be used for each command in terminals with shell integration enabled that do not have an associated exit code. Set to {0} to hide the icon or disable decorations with {1}.", '`\'\'`', '`#terminal.integrated.shellIntegration.decorationsEnabled#`') + markdownDescription: localize('terminal.integrated.shellIntegration.decorationIconSuccess', "Controls the icon that will be used for each command in terminals with shell integration enabled that do not have an associated exit code. Set to {0} to hide the icon or disable decorations with {1}.", '`\"\"`', '`#terminal.integrated.shellIntegration.decorationsEnabled#`') }, [TerminalSettingId.ShellIntegrationDecorationIconError]: { type: 'string', default: 'error-small', - markdownDescription: localize('terminal.integrated.shellIntegration.decorationIconError', "Controls the icon that will be used for each command in terminals with shell integration enabled that do have an associated exit code. Set to {0} to hide the icon or disable decorations with {1}.", '`\'\'`', '`#terminal.integrated.shellIntegration.decorationsEnabled#`') + markdownDescription: localize('terminal.integrated.shellIntegration.decorationIconError', "Controls the icon that will be used for each command in terminals with shell integration enabled that do have an associated exit code. Set to {0} to hide the icon or disable decorations with {1}.", '`\"\"`', '`#terminal.integrated.shellIntegration.decorationsEnabled#`') }, [TerminalSettingId.ShellIntegrationDecorationIcon]: { type: 'string', default: 'circle-outline', - markdownDescription: localize('terminal.integrated.shellIntegration.decorationIcon', "Controls the icon that will be used for skipped/empty commands. Set to {0} to hide the icon or disable decorations with {1}.", '`\'\'`', '`#terminal.integrated.shellIntegration.decorationsEnabled#`') + markdownDescription: localize('terminal.integrated.shellIntegration.decorationIcon', "Controls the icon that will be used for skipped/empty commands. Set to {0} to hide the icon or disable decorations with {1}.", '`\"\"`', '`#terminal.integrated.shellIntegration.decorationsEnabled#`') }, [TerminalSettingId.TabsFocusMode]: { type: 'string', @@ -546,15 +546,22 @@ const terminalConfiguration: IConfigurationNode = { }, [TerminalSettingId.ShellIntegrationEnabled]: { restricted: true, - markdownDescription: localize('terminal.integrated.shellIntegration.enabled', "Enable features like enhanced command tracking and current working directory detection. \n\nShell integration works by injecting the shell with a startup script. The script gives VS Code insight into what is happening within the terminal.\n\nSupported shells:\n\n- Linux/macOS: bash, pwsh, zsh\n - Windows: pwsh\n\nThis setting applies only when terminals are created, so you will need to restart your terminals for it to take effect.\n\n Note that the script injection may not work if you have custom arguments defined in the terminal profile, a [complex bash `PROMPT_COMMAND`](https://code.visualstudio.com/docs/editor/integrated-terminal#_complex-bash-promptcommand), or other unsupported setup."), + markdownDescription: localize('terminal.integrated.shellIntegration.enabled', "Determines whether or not shell integration is auto-injected to support features like enhanced command tracking and current working directory detection. \n\nShell integration works by injecting the shell with a startup script. The script gives VS Code insight into what is happening within the terminal.\n\nSupported shells:\n\n- Linux/macOS: bash, pwsh, zsh\n - Windows: pwsh\n\nThis setting applies only when terminals are created, so you will need to restart your terminals for it to take effect.\n\n Note that the script injection may not work if you have custom arguments defined in the terminal profile, a [complex bash `PROMPT_COMMAND`](https://code.visualstudio.com/docs/editor/integrated-terminal#_complex-bash-promptcommand), or other unsupported setup. To disable decorations, see {0}", '`#terminal.integrated.shellIntegrations.decorationsEnabled#`'), type: 'boolean', default: true }, [TerminalSettingId.ShellIntegrationDecorationsEnabled]: { restricted: true, markdownDescription: localize('terminal.integrated.shellIntegration.decorationsEnabled', "When shell integration is enabled, adds a decoration for each command."), - type: 'boolean', - default: true + type: 'string', + enum: ['both', 'gutter', 'overviewRuler', 'never'], + enumDescriptions: [ + localize('terminal.integrated.shellIntegration.decorationsEnabled.both', "Show decorations in the gutter (left) and overview ruler (right)"), + localize('terminal.integrated.shellIntegration.decorationsEnabled.gutter', "Show gutter decorations to the left of the terminal"), + localize('terminal.integrated.shellIntegration.decorationsEnabled.overviewRuler', "Show overview ruler decorations to the right of the terminal"), + localize('terminal.integrated.shellIntegration.decorationsEnabled.never', "Do not show decorations"), + ], + default: 'both' }, [TerminalSettingId.ShellIntegrationCommandHistory]: { restricted: true, diff --git a/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts b/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts index 3ea312e1e1e..ddcbd66e3b2 100644 --- a/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts +++ b/src/vs/workbench/contrib/terminal/test/browser/xterm/decorationAddon.test.ts @@ -37,7 +37,14 @@ suite('DecorationAddon', () => { const instantiationService = new TestInstantiationService(); const configurationService = new TestConfigurationService({ workbench: { - hover: { delay: 5 } + hover: { delay: 5 }, + }, + terminal: { + integrated: { + shellIntegration: { + decorationsEnabled: 'both' + } + } } }); instantiationService.stub(IThemeService, new TestThemeService()); diff --git a/test/automation/src/terminal.ts b/test/automation/src/terminal.ts index 73f169e1c05..67f012bf483 100644 --- a/test/automation/src/terminal.ts +++ b/test/automation/src/terminal.ts @@ -25,7 +25,8 @@ export enum Selector { Tabs = '.tabs-list .monaco-list-row', SplitButton = '.editor .codicon-split-horizontal', XtermSplitIndex0 = '#terminal .terminal-groups-container .split-view-view:nth-child(1) .terminal-wrapper', - XtermSplitIndex1 = '#terminal .terminal-groups-container .split-view-view:nth-child(2) .terminal-wrapper' + XtermSplitIndex1 = '#terminal .terminal-groups-container .split-view-view:nth-child(2) .terminal-wrapper', + Hide = '.hide' } /** @@ -226,14 +227,18 @@ export class Terminal { await this.code.waitForElement(Selector.TerminalView, result => result === undefined); } - async assertCommandDecorations(expectedCounts?: ICommandDecorationCounts, customConfig?: { updatedIcon: string; count: number }): Promise { + async assertCommandDecorations(expectedCounts?: ICommandDecorationCounts, customIcon?: { updatedIcon: string; count: number }, showDecorations?: 'both' | 'gutter' | 'overviewRuler' | 'never'): Promise { if (expectedCounts) { - await this.code.waitForElements(Selector.CommandDecorationPlaceholder, true, decorations => decorations && decorations.length === expectedCounts.placeholder); - await this.code.waitForElements(Selector.CommandDecorationSuccess, true, decorations => decorations && decorations.length === expectedCounts.success); - await this.code.waitForElements(Selector.CommandDecorationError, true, decorations => decorations && decorations.length === expectedCounts.error); + const placeholderSelector = showDecorations === 'overviewRuler' ? `${Selector.CommandDecorationPlaceholder}${Selector.Hide}` : Selector.CommandDecorationPlaceholder; + await this.code.waitForElements(placeholderSelector, true, decorations => decorations && decorations.length === expectedCounts.placeholder); + const successSelector = showDecorations === 'overviewRuler' ? `${Selector.CommandDecorationSuccess}${Selector.Hide}` : Selector.CommandDecorationSuccess; + await this.code.waitForElements(successSelector, true, decorations => decorations && decorations.length === expectedCounts.success); + const errorSelector = showDecorations === 'overviewRuler' ? `${Selector.CommandDecorationError}${Selector.Hide}` : Selector.CommandDecorationError; + await this.code.waitForElements(errorSelector, true, decorations => decorations && decorations.length === expectedCounts.error); } - if (customConfig) { - await this.code.waitForElements(`.terminal-command-decoration.codicon-${customConfig.updatedIcon}`, true, decorations => decorations && decorations.length === customConfig.count); + + if (customIcon) { + await this.code.waitForElements(`.terminal-command-decoration.codicon-${customIcon.updatedIcon}`, true, decorations => decorations && decorations.length === customIcon.count); } } diff --git a/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts b/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts index b0f4425a162..23fb97dda74 100644 --- a/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts +++ b/test/smoke/src/areas/terminal/terminal-shellIntegration.test.ts @@ -36,7 +36,6 @@ export function setup() { }); describe('Decorations', function () { describe('Should show default icons', function () { - it('Placeholder', async () => { await createShellIntegrationProfile(); await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 }); @@ -62,8 +61,37 @@ export function setup() { await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationIconSuccess', '"zap"'); await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationIconError', '"zap"'); await terminal.assertCommandDecorations(undefined, { updatedIcon: "zap", count: 3 }); + }); + }); + describe('terminal.integrated.shellIntegration.decorationsEnabled should determine gutter and overview ruler decoration visibility', function () { + beforeEach(async () => { + await settingsEditor.clearUserSettings(); + await setTerminalTestSettings(app, [['terminal.integrated.shellIntegration.enabled', 'true']]); + await createShellIntegrationProfile(); + await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 }); + await terminal.runCommandInTerminal(`echo "foo"`); + await terminal.runCommandInTerminal(`bar`); + await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 }); + }); + afterEach(async () => { await app.workbench.terminal.runCommand(TerminalCommandId.KillAll); }); + it('never', async () => { + await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationsEnabled', '"never"'); + await terminal.assertCommandDecorations({ placeholder: 0, success: 0, error: 0 }, undefined, 'never'); + }); + it('both', async () => { + await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationsEnabled', '"both"'); + await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 }, undefined, 'both'); + }); + it('gutter', async () => { + await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationsEnabled', '"gutter"'); + await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 }, undefined, 'gutter'); + }); + it('overviewRuler', async () => { + await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationsEnabled', '"overviewRuler"'); + await terminal.assertCommandDecorations({ placeholder: 1, success: 1, error: 1 }, undefined, 'overviewRuler'); + }); }); }); });