mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 13:46:13 +00:00
disable decorations (#154430)
This commit is contained in:
parent
a03ebcaa0d
commit
ff31a8c6fd
|
@ -14,6 +14,10 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.terminal-command-decoration.hide {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.monaco-workbench .pane-body.integrated-terminal .terminal-outer-container,
|
.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-groups-container,
|
||||||
.monaco-workbench .pane-body.integrated-terminal .terminal-group,
|
.monaco-workbench .pane-body.integrated-terminal .terminal-group,
|
||||||
|
|
|
@ -46,6 +46,7 @@ import { getTerminalActionBarArgs } from 'vs/workbench/contrib/terminal/browser/
|
||||||
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
|
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
|
||||||
import { getShellIntegrationTooltip } from 'vs/workbench/contrib/terminal/browser/terminalTooltip';
|
import { getShellIntegrationTooltip } from 'vs/workbench/contrib/terminal/browser/terminalTooltip';
|
||||||
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
|
||||||
|
import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
|
||||||
|
|
||||||
export class TerminalViewPane extends ViewPane {
|
export class TerminalViewPane extends ViewPane {
|
||||||
private _actions: IAction[] | undefined;
|
private _actions: IAction[] | undefined;
|
||||||
|
@ -65,7 +66,7 @@ export class TerminalViewPane extends ViewPane {
|
||||||
@IKeybindingService keybindingService: IKeybindingService,
|
@IKeybindingService keybindingService: IKeybindingService,
|
||||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||||
@IConfigurationService configurationService: IConfigurationService,
|
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||||
@IContextMenuService private readonly _contextMenuService: IContextMenuService,
|
@IContextMenuService private readonly _contextMenuService: IContextMenuService,
|
||||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||||
|
@ -81,7 +82,7 @@ export class TerminalViewPane extends ViewPane {
|
||||||
@ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService,
|
@ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService,
|
||||||
@IThemeService private readonly _themeService: IThemeService
|
@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(() => {
|
this._register(this._terminalService.onDidRegisterProcessSupport(() => {
|
||||||
if (this._actions) {
|
if (this._actions) {
|
||||||
for (const action of this._actions) {
|
for (const action of this._actions) {
|
||||||
|
@ -111,20 +112,34 @@ export class TerminalViewPane extends ViewPane {
|
||||||
this._terminalTabbedView?.rerenderTabs();
|
this._terminalTabbedView?.rerenderTabs();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
configurationService.onDidChangeConfiguration(e => {
|
_configurationService.onDidChangeConfiguration(e => {
|
||||||
if ((e.affectsConfiguration(TerminalSettingId.ShellIntegrationDecorationsEnabled) && !configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationsEnabled)) ||
|
if (e.affectsConfiguration(TerminalSettingId.ShellIntegrationDecorationsEnabled) || e.affectsConfiguration(TerminalSettingId.ShellIntegrationEnabled)) {
|
||||||
(e.affectsConfiguration(TerminalSettingId.ShellIntegrationEnabled) && !configurationService.getValue(TerminalSettingId.ShellIntegrationEnabled))) {
|
this._updateForShellIntegration();
|
||||||
this._parentDomElement?.classList.remove('shell-integration');
|
|
||||||
} else if (configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationsEnabled) && configurationService.getValue(TerminalSettingId.ShellIntegrationEnabled)) {
|
|
||||||
this._parentDomElement?.classList.add('shell-integration');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
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');
|
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 {
|
override renderBody(container: HTMLElement): void {
|
||||||
super.renderBody(container);
|
super.renderBody(container);
|
||||||
|
|
||||||
|
|
|
@ -28,13 +28,14 @@ import { IGenericMarkProperties } from 'vs/platform/terminal/common/terminalProc
|
||||||
|
|
||||||
const enum DecorationSelector {
|
const enum DecorationSelector {
|
||||||
CommandDecoration = 'terminal-command-decoration',
|
CommandDecoration = 'terminal-command-decoration',
|
||||||
|
Hide = 'hide',
|
||||||
ErrorColor = 'error',
|
ErrorColor = 'error',
|
||||||
DefaultColor = 'default-color',
|
DefaultColor = 'default-color',
|
||||||
Default = 'default',
|
Default = 'default',
|
||||||
Codicon = 'codicon',
|
Codicon = 'codicon',
|
||||||
XtermDecoration = 'xterm-decoration',
|
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 {
|
const enum DecorationStyles {
|
||||||
|
@ -51,6 +52,8 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
|
||||||
private _contextMenuVisible: boolean = false;
|
private _contextMenuVisible: boolean = false;
|
||||||
private _decorations: Map<number, IDisposableDecoration> = new Map();
|
private _decorations: Map<number, IDisposableDecoration> = new Map();
|
||||||
private _placeholderDecoration: IDecoration | undefined;
|
private _placeholderDecoration: IDecoration | undefined;
|
||||||
|
private _showGutterDecorations?: boolean;
|
||||||
|
private _showOverviewRulerDecorations?: boolean;
|
||||||
|
|
||||||
private readonly _onDidRequestRunCommand = this._register(new Emitter<{ command: ITerminalCommand; copyAsHtml?: boolean }>());
|
private readonly _onDidRequestRunCommand = this._register(new Emitter<{ command: ITerminalCommand; copyAsHtml?: boolean }>());
|
||||||
readonly onDidRequestRunCommand = this._onDidRequestRunCommand.event;
|
readonly onDidRequestRunCommand = this._onDidRequestRunCommand.event;
|
||||||
|
@ -79,9 +82,67 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
|
||||||
this.refreshLayouts();
|
this.refreshLayouts();
|
||||||
} else if (e.affectsConfiguration('workbench.colorCustomizations')) {
|
} else if (e.affectsConfiguration('workbench.colorCustomizations')) {
|
||||||
this._refreshStyles(true);
|
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._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 {
|
public refreshLayouts(): void {
|
||||||
|
@ -128,31 +189,14 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
|
||||||
public clearDecorations(): void {
|
public clearDecorations(): void {
|
||||||
this._placeholderDecoration?.marker.dispose();
|
this._placeholderDecoration?.marker.dispose();
|
||||||
this._clearPlaceholder();
|
this._clearPlaceholder();
|
||||||
for (const value of this._decorations.values()) {
|
this._disposeAllDecorations();
|
||||||
value.decoration.dispose();
|
|
||||||
dispose(value.disposables);
|
|
||||||
}
|
|
||||||
this._decorations.clear();
|
this._decorations.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _attachToCommandCapability(): void {
|
private _attachToCommandCapability(): void {
|
||||||
if (this._capabilities.has(TerminalCapability.CommandDetection)) {
|
if (this._capabilities.has(TerminalCapability.CommandDetection)) {
|
||||||
this._addCommandDetectionListeners();
|
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 {
|
private _addCommandDetectionListeners(): void {
|
||||||
|
@ -204,13 +248,12 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
|
||||||
}
|
}
|
||||||
|
|
||||||
registerCommandDecoration(command: ITerminalCommand, beforeCommandExecution?: boolean): IDecoration | undefined {
|
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;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (!command.marker) {
|
if (!command.marker) {
|
||||||
throw new Error(`cannot add a decoration for a command ${JSON.stringify(command)} with no marker`);
|
throw new Error(`cannot add a decoration for a command ${JSON.stringify(command)} with no marker`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._clearPlaceholder();
|
this._clearPlaceholder();
|
||||||
let color = command.exitCode === undefined ? defaultColor : command.exitCode ? errorColor : successColor;
|
let color = command.exitCode === undefined ? defaultColor : command.exitCode ? errorColor : successColor;
|
||||||
if (color && typeof color !== 'string') {
|
if (color && typeof color !== 'string') {
|
||||||
|
@ -220,9 +263,9 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
|
||||||
}
|
}
|
||||||
const decoration = this._terminal.registerDecoration({
|
const decoration = this._terminal.registerDecoration({
|
||||||
marker: command.marker,
|
marker: command.marker,
|
||||||
overviewRulerOptions: beforeCommandExecution
|
overviewRulerOptions: this._showOverviewRulerDecorations ? (beforeCommandExecution
|
||||||
? { color, position: 'left' }
|
? { color, position: 'left' }
|
||||||
: { color, position: command.exitCode ? 'right' : 'left' }
|
: { color, position: command.exitCode ? 'right' : 'left' }) : undefined
|
||||||
});
|
});
|
||||||
if (!decoration) {
|
if (!decoration) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -287,20 +330,25 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
|
||||||
element.classList.remove(classes);
|
element.classList.remove(classes);
|
||||||
}
|
}
|
||||||
element.classList.add(DecorationSelector.CommandDecoration, DecorationSelector.Codicon, DecorationSelector.XtermDecoration);
|
element.classList.add(DecorationSelector.CommandDecoration, DecorationSelector.Codicon, DecorationSelector.XtermDecoration);
|
||||||
|
|
||||||
if (genericMarkProperties) {
|
if (genericMarkProperties) {
|
||||||
element.classList.add(DecorationSelector.DefaultColor, DecorationSelector.GenericMarkerIcon);
|
element.classList.add(DecorationSelector.DefaultColor, DecorationSelector.GenericMarkerIcon);
|
||||||
if (!genericMarkProperties.hoverMessage) {
|
if (!genericMarkProperties.hoverMessage) {
|
||||||
//disable the mouse pointer
|
//disable the mouse pointer
|
||||||
element.classList.add(DecorationSelector.Default);
|
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 {
|
} 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)}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,17 +117,17 @@ const terminalConfiguration: IConfigurationNode = {
|
||||||
[TerminalSettingId.ShellIntegrationDecorationIconSuccess]: {
|
[TerminalSettingId.ShellIntegrationDecorationIconSuccess]: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: 'primitive-dot',
|
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]: {
|
[TerminalSettingId.ShellIntegrationDecorationIconError]: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: 'error-small',
|
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]: {
|
[TerminalSettingId.ShellIntegrationDecorationIcon]: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: 'circle-outline',
|
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]: {
|
[TerminalSettingId.TabsFocusMode]: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
@ -546,15 +546,22 @@ const terminalConfiguration: IConfigurationNode = {
|
||||||
},
|
},
|
||||||
[TerminalSettingId.ShellIntegrationEnabled]: {
|
[TerminalSettingId.ShellIntegrationEnabled]: {
|
||||||
restricted: true,
|
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',
|
type: 'boolean',
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
[TerminalSettingId.ShellIntegrationDecorationsEnabled]: {
|
[TerminalSettingId.ShellIntegrationDecorationsEnabled]: {
|
||||||
restricted: true,
|
restricted: true,
|
||||||
markdownDescription: localize('terminal.integrated.shellIntegration.decorationsEnabled', "When shell integration is enabled, adds a decoration for each command."),
|
markdownDescription: localize('terminal.integrated.shellIntegration.decorationsEnabled', "When shell integration is enabled, adds a decoration for each command."),
|
||||||
type: 'boolean',
|
type: 'string',
|
||||||
default: true
|
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]: {
|
[TerminalSettingId.ShellIntegrationCommandHistory]: {
|
||||||
restricted: true,
|
restricted: true,
|
||||||
|
|
|
@ -37,7 +37,14 @@ suite('DecorationAddon', () => {
|
||||||
const instantiationService = new TestInstantiationService();
|
const instantiationService = new TestInstantiationService();
|
||||||
const configurationService = new TestConfigurationService({
|
const configurationService = new TestConfigurationService({
|
||||||
workbench: {
|
workbench: {
|
||||||
hover: { delay: 5 }
|
hover: { delay: 5 },
|
||||||
|
},
|
||||||
|
terminal: {
|
||||||
|
integrated: {
|
||||||
|
shellIntegration: {
|
||||||
|
decorationsEnabled: 'both'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
instantiationService.stub(IThemeService, new TestThemeService());
|
instantiationService.stub(IThemeService, new TestThemeService());
|
||||||
|
|
|
@ -25,7 +25,8 @@ export enum Selector {
|
||||||
Tabs = '.tabs-list .monaco-list-row',
|
Tabs = '.tabs-list .monaco-list-row',
|
||||||
SplitButton = '.editor .codicon-split-horizontal',
|
SplitButton = '.editor .codicon-split-horizontal',
|
||||||
XtermSplitIndex0 = '#terminal .terminal-groups-container .split-view-view:nth-child(1) .terminal-wrapper',
|
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);
|
await this.code.waitForElement(Selector.TerminalView, result => result === undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
async assertCommandDecorations(expectedCounts?: ICommandDecorationCounts, customConfig?: { updatedIcon: string; count: number }): Promise<void> {
|
async assertCommandDecorations(expectedCounts?: ICommandDecorationCounts, customIcon?: { updatedIcon: string; count: number }, showDecorations?: 'both' | 'gutter' | 'overviewRuler' | 'never'): Promise<void> {
|
||||||
if (expectedCounts) {
|
if (expectedCounts) {
|
||||||
await this.code.waitForElements(Selector.CommandDecorationPlaceholder, true, decorations => decorations && decorations.length === expectedCounts.placeholder);
|
const placeholderSelector = showDecorations === 'overviewRuler' ? `${Selector.CommandDecorationPlaceholder}${Selector.Hide}` : Selector.CommandDecorationPlaceholder;
|
||||||
await this.code.waitForElements(Selector.CommandDecorationSuccess, true, decorations => decorations && decorations.length === expectedCounts.success);
|
await this.code.waitForElements(placeholderSelector, true, decorations => decorations && decorations.length === expectedCounts.placeholder);
|
||||||
await this.code.waitForElements(Selector.CommandDecorationError, true, decorations => decorations && decorations.length === expectedCounts.error);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ export function setup() {
|
||||||
});
|
});
|
||||||
describe('Decorations', function () {
|
describe('Decorations', function () {
|
||||||
describe('Should show default icons', function () {
|
describe('Should show default icons', function () {
|
||||||
|
|
||||||
it('Placeholder', async () => {
|
it('Placeholder', async () => {
|
||||||
await createShellIntegrationProfile();
|
await createShellIntegrationProfile();
|
||||||
await terminal.assertCommandDecorations({ placeholder: 1, success: 0, error: 0 });
|
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.decorationIconSuccess', '"zap"');
|
||||||
await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationIconError', '"zap"');
|
await settingsEditor.addUserSetting('terminal.integrated.shellIntegration.decorationIconError', '"zap"');
|
||||||
await terminal.assertCommandDecorations(undefined, { updatedIcon: "zap", count: 3 });
|
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);
|
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');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue