Skip to content

Commit 933fff6

Browse files
committed
Fix lifecycle issues in DecorationAddon
DecorationAddon owns the decorations, not the markers so it's not its job to dispose them. This change also disposes the DecorationAddon inside XtermTerminal when the setting is switched off and recreates when it goes back on, this needed some changes around restoring DecorationAddon properly for existing terminals as well. Fixes microsoft#145212
1 parent f326929 commit 933fff6

File tree

6 files changed

+38
-20
lines changed

6 files changed

+38
-20
lines changed

src/vs/platform/terminal/common/capabilities/capabilities.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export interface ICommandDetectionCapability {
8787
readonly commands: readonly ITerminalCommand[];
8888
/** The command currently being executed, otherwise undefined. */
8989
readonly executingCommand: string | undefined;
90+
readonly executingCommandObject: ITerminalCommand | undefined;
9091
/** The current cwd at the cursor's position. */
9192
readonly cwd: string | undefined;
9293
readonly onCommandStarted: Event<ITerminalCommand>;

src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ export class CommandDetectionCapability implements ICommandDetectionCapability {
5656

5757
get commands(): readonly ITerminalCommand[] { return this._commands; }
5858
get executingCommand(): string | undefined { return this._currentCommand.command; }
59+
// TODO: as is unsafe here and it duplicates behavor of executingCommand
60+
get executingCommandObject(): ITerminalCommand | undefined {
61+
if (this._currentCommand.commandStartMarker) {
62+
return { marker: this._currentCommand.commandStartMarker } as ITerminalCommand;
63+
}
64+
return undefined;
65+
}
5966
get cwd(): string | undefined { return this._cwd; }
6067

6168
private readonly _onCommandStarted = new Emitter<ITerminalCommand>();

src/vs/workbench/contrib/terminal/browser/terminalInstance.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -495,10 +495,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
495495
e.affectsConfiguration(TerminalSettingId.TerminalDescription)) {
496496
this._labelComputer?.refreshLabel();
497497
}
498-
if ((e.affectsConfiguration(TerminalSettingId.ShellIntegrationDecorationsEnabled) && !this._configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationsEnabled)) ||
499-
(e.affectsConfiguration(TerminalSettingId.ShellIntegrationEnabled) && !this._configurationService.getValue(TerminalSettingId.ShellIntegrationEnabled))) {
500-
this.xterm?.clearDecorations();
501-
}
502498
}));
503499
this._workspaceContextService.onDidChangeWorkspaceFolders(() => this._labelComputer?.refreshLabel());
504500

src/vs/workbench/contrib/terminal/browser/xterm/decorationAddon.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
6+
import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
77
import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal';
88
import { IDecoration, ITerminalAddon, Terminal } from 'xterm';
99
import * as dom from 'vs/base/browser/dom';
@@ -61,7 +61,7 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
6161
@IThemeService private readonly _themeService: IThemeService
6262
) {
6363
super();
64-
this._attachToCommandCapability();
64+
this._register(toDisposable(() => this.clearDecorations(true)));
6565
this._register(this._contextMenuService.onDidShowContextMenu(() => this._contextMenuVisible = true));
6666
this._register(this._contextMenuService.onDidHideContextMenu(() => this._contextMenuVisible = false));
6767
this._hoverDelayer = this._register(new Delayer(this._configurationService.getValue('workbench.hover.delay')));
@@ -116,7 +116,6 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
116116
this._placeholderDecoration?.marker.dispose();
117117
for (const value of this._decorations.values()) {
118118
value.decoration.dispose();
119-
value.decoration.marker.dispose();
120119
dispose(value.disposables);
121120
}
122121
this._decorations.clear();
@@ -126,11 +125,12 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
126125
private _attachToCommandCapability(): void {
127126
if (this._capabilities.has(TerminalCapability.CommandDetection)) {
128127
this._addCommandFinishedListener();
128+
this._addCommandStartedListener();
129129
} else {
130130
this._register(this._capabilities.onDidAddCapability(c => {
131131
if (c === TerminalCapability.CommandDetection) {
132-
this._addCommandStartedListener();
133132
this._addCommandFinishedListener();
133+
this._addCommandStartedListener();
134134
}
135135
}));
136136
}
@@ -150,11 +150,8 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
150150
if (!capability) {
151151
return;
152152
}
153-
if (capability.commands.length > 0) {
154-
const lastCommand = capability.commands[capability.commands.length - 1];
155-
if (lastCommand.marker && !lastCommand.endMarker) {
156-
this.registerCommandDecoration(lastCommand, true);
157-
}
153+
if (capability.executingCommandObject?.marker) {
154+
this.registerCommandDecoration(capability.executingCommandObject, true);
158155
}
159156
this._commandStartedListener = capability.onCommandStarted(command => this.registerCommandDecoration(command, true));
160157
}
@@ -182,6 +179,7 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
182179

183180
activate(terminal: Terminal): void {
184181
this._terminal = terminal;
182+
this._attachToCommandCapability();
185183
}
186184

187185
registerCommandDecoration(command: ITerminalCommand, beforeCommandExecution?: boolean): IDecoration | undefined {

src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal {
9090
cols: number,
9191
rows: number,
9292
location: TerminalLocation,
93-
capabilities: ITerminalCapabilityStore,
93+
private readonly _capabilities: ITerminalCapabilityStore,
9494
@IConfigurationService private readonly _configurationService: IConfigurationService,
9595
@IInstantiationService private readonly _instantiationService: IInstantiationService,
9696
@ILogService private readonly _logService: ILogService,
@@ -145,6 +145,10 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal {
145145
if (e.affectsConfiguration(TerminalSettingId.UnicodeVersion)) {
146146
this._updateUnicodeVersion();
147147
}
148+
if (e.affectsConfiguration(TerminalSettingId.ShellIntegrationDecorationsEnabled) ||
149+
e.affectsConfiguration(TerminalSettingId.ShellIntegrationEnabled)) {
150+
this._updateDecorationAddon();
151+
}
148152
}));
149153

150154
this.add(this._themeService.onDidColorThemeChange(theme => this._updateTheme(theme)));
@@ -157,16 +161,14 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal {
157161

158162
// Load addons
159163
this._updateUnicodeVersion();
160-
this._commandNavigationAddon = this._instantiationService.createInstance(CommandNavigationAddon, capabilities);
164+
this._commandNavigationAddon = this._instantiationService.createInstance(CommandNavigationAddon, _capabilities);
161165
this.raw.loadAddon(this._commandNavigationAddon);
162166
this._shellIntegrationAddon = this._instantiationService.createInstance(ShellIntegrationAddon);
163167
this.raw.loadAddon(this._shellIntegrationAddon);
164-
if (this._configurationService.getValue(TerminalSettingId.ShellIntegrationEnabled) && this._configurationService.getValue(TerminalSettingId.ShellIntegrationDecorationsEnabled)) {
165-
this._createDecorationAddon(capabilities);
166-
}
168+
this._updateDecorationAddon();
167169
}
168-
private _createDecorationAddon(capabilities: ITerminalCapabilityStore): void {
169-
this._decorationAddon = this._instantiationService.createInstance(DecorationAddon, capabilities);
170+
private _createDecorationAddon(): void {
171+
this._decorationAddon = this._instantiationService.createInstance(DecorationAddon, this._capabilities);
170172
this._decorationAddon.onDidRequestRunCommand(command => this._onDidRequestRunCommand.fire(command));
171173
this.raw.loadAddon(this._decorationAddon);
172174
}
@@ -570,4 +572,17 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal {
570572
this.raw.unicode.activeVersion = this._configHelper.config.unicodeVersion;
571573
}
572574
}
575+
576+
private _updateDecorationAddon(): void {
577+
if (this._configHelper.config.shellIntegration?.enabled && this._configHelper.config.shellIntegration.decorationsEnabled) {
578+
if (!this._decorationAddon) {
579+
this._createDecorationAddon();
580+
}
581+
return;
582+
}
583+
if (this._decorationAddon) {
584+
this._decorationAddon.dispose();
585+
this._decorationAddon = undefined;
586+
}
587+
}
573588
}

src/vs/workbench/contrib/terminal/common/terminal.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ export interface ITerminalConfiguration {
292292
autoReplies: { [key: string]: string };
293293
shellIntegration?: {
294294
enabled: boolean;
295+
decorationsEnabled: boolean;
295296
};
296297
}
297298

0 commit comments

Comments
 (0)