Skip to content

Commit e37672f

Browse files
authored
Merge pull request microsoft#232740 from microsoft/tyriar/232656__232658
Put terminal quick fixes into the SI menu too
2 parents d9d4fc8 + d5c34d7 commit e37672f

File tree

6 files changed

+58
-12
lines changed

6 files changed

+58
-12
lines changed

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Event } from '../../../base/common/event.js';
77
import { IProcessEnvironment, OperatingSystem } from '../../../base/common/platform.js';
88
import { URI, UriComponents } from '../../../base/common/uri.js';
99
import { createDecorator } from '../../instantiation/common/instantiation.js';
10-
import { IPtyHostProcessReplayEvent, ISerializedCommandDetectionCapability, ITerminalCapabilityStore } from './capabilities/capabilities.js';
10+
import { IPtyHostProcessReplayEvent, ISerializedCommandDetectionCapability, ITerminalCapabilityStore, type ITerminalCommand } from './capabilities/capabilities.js';
1111
import { IGetTerminalLayoutInfoArgs, IProcessDetails, ISetTerminalLayoutInfoArgs } from './terminalProcess.js';
1212
import { ThemeIcon } from '../../../base/common/themables.js';
1313
import { ISerializableEnvironmentVariableCollections } from './environmentVariable.js';
@@ -16,6 +16,8 @@ import { IWorkspaceFolder } from '../../workspace/common/workspace.js';
1616
import { Registry } from '../../registry/common/platform.js';
1717
import type * as performance from '../../../base/common/performance.js';
1818
import { ILogService } from '../../log/common/log.js';
19+
import type { IAction } from '../../../base/common/actions.js';
20+
import type { IDisposable } from '../../../base/common/lifecycle.js';
1921

2022
export const terminalTabFocusModeContextKey = new RawContextKey<boolean>('terminalTabFocusMode', false, true);
2123

@@ -929,6 +931,10 @@ export interface IShellIntegration {
929931
deserialize(serialized: ISerializedCommandDetectionCapability): void;
930932
}
931933

934+
export interface IDecorationAddon {
935+
registerMenuItems(command: ITerminalCommand, items: IAction[]): IDisposable;
936+
}
937+
932938
export interface ITerminalContributions {
933939
profiles?: ITerminalProfileContribution[];
934940
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { createDecorator } from '../../../../platform/instantiation/common/insta
1414
import { IKeyMods } from '../../../../platform/quickinput/common/quickInput.js';
1515
import { IMarkProperties, ITerminalCapabilityImplMap, ITerminalCapabilityStore, ITerminalCommand, TerminalCapability } from '../../../../platform/terminal/common/capabilities/capabilities.js';
1616
import { IMergedEnvironmentVariableCollection } from '../../../../platform/terminal/common/environmentVariable.js';
17-
import { IExtensionTerminalProfile, IReconnectionProperties, IShellIntegration, IShellLaunchConfig, ITerminalBackend, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalShellType, TerminalType, TitleEventSource, WaitOnExitValue } from '../../../../platform/terminal/common/terminal.js';
17+
import { IExtensionTerminalProfile, IReconnectionProperties, IShellIntegration, IShellLaunchConfig, ITerminalBackend, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalShellType, TerminalType, TitleEventSource, WaitOnExitValue, type IDecorationAddon } from '../../../../platform/terminal/common/terminal.js';
1818
import { IColorTheme } from '../../../../platform/theme/common/themeService.js';
1919
import { IWorkspaceFolder } from '../../../../platform/workspace/common/workspace.js';
2020
import { EditorInput } from '../../../common/editor/editorInput.js';
@@ -1063,6 +1063,8 @@ export interface IXtermTerminal extends IDisposable {
10631063
*/
10641064
readonly shellIntegration: IShellIntegration;
10651065

1066+
readonly decorationAddon: IDecorationAddon;
1067+
10661068
readonly onDidChangeSelection: Event<void>;
10671069
readonly onDidChangeFindResults: Event<{ resultIndex: number; resultCount: number }>;
10681070
readonly onDidRequestRunCommand: Event<{ command: ITerminalCommand; noNewLine?: boolean }>;

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { INotificationService, Severity } from '../../../../../platform/notifica
1919
import { IOpenerService } from '../../../../../platform/opener/common/opener.js';
2020
import { IQuickInputService, IQuickPickItem } from '../../../../../platform/quickinput/common/quickInput.js';
2121
import { CommandInvalidationReason, ICommandDetectionCapability, IMarkProperties, ITerminalCapabilityStore, ITerminalCommand, TerminalCapability } from '../../../../../platform/terminal/common/capabilities/capabilities.js';
22-
import { TerminalSettingId } from '../../../../../platform/terminal/common/terminal.js';
22+
import { TerminalSettingId, type IDecorationAddon } from '../../../../../platform/terminal/common/terminal.js';
2323
import { IThemeService } from '../../../../../platform/theme/common/themeService.js';
2424
import { terminalDecorationError, terminalDecorationIncomplete, terminalDecorationMark, terminalDecorationSuccess } from '../terminalIcons.js';
2525
import { DecorationSelector, getTerminalDecorationHoverContent, updateLayout } from './decorationStyles.js';
@@ -30,13 +30,14 @@ import { MarkdownString } from '../../../../../base/common/htmlContent.js';
3030

3131
interface IDisposableDecoration { decoration: IDecoration; disposables: IDisposable[]; exitCode?: number; markProperties?: IMarkProperties }
3232

33-
export class DecorationAddon extends Disposable implements ITerminalAddon {
33+
export class DecorationAddon extends Disposable implements ITerminalAddon, IDecorationAddon {
3434
protected _terminal: Terminal | undefined;
3535
private _capabilityDisposables: Map<TerminalCapability, DisposableStore> = new Map();
3636
private _decorations: Map<number, IDisposableDecoration> = new Map();
3737
private _placeholderDecoration: IDecoration | undefined;
3838
private _showGutterDecorations?: boolean;
3939
private _showOverviewRulerDecorations?: boolean;
40+
private readonly _registeredMenuItems: Map<ITerminalCommand, IAction[]> = new Map();
4041

4142
private readonly _onDidRequestRunCommand = this._register(new Emitter<{ command: ITerminalCommand; noNewLine?: boolean }>());
4243
readonly onDidRequestRunCommand = this._onDidRequestRunCommand.event;
@@ -309,6 +310,26 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
309310
return decoration;
310311
}
311312

313+
registerMenuItems(command: ITerminalCommand, items: IAction[]): IDisposable {
314+
const existingItems = this._registeredMenuItems.get(command);
315+
if (existingItems) {
316+
existingItems.push(...items);
317+
} else {
318+
this._registeredMenuItems.set(command, [...items]);
319+
}
320+
return toDisposable(() => {
321+
const commandItems = this._registeredMenuItems.get(command);
322+
if (commandItems) {
323+
for (const item of items.values()) {
324+
const index = commandItems.indexOf(item);
325+
if (index !== -1) {
326+
commandItems.splice(index, 1);
327+
}
328+
}
329+
}
330+
});
331+
}
332+
312333
private _createDisposables(element: HTMLElement, command?: ITerminalCommand, markProperties?: IMarkProperties): IDisposable[] {
313334
if (command?.exitCode === undefined && !command?.markProperties) {
314335
return [];
@@ -387,6 +408,10 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
387408

388409
private async _getCommandActions(command: ITerminalCommand): Promise<IAction[]> {
389410
const actions: IAction[] = [];
411+
const registeredMenuItems = this._registeredMenuItems.get(command);
412+
if (registeredMenuItems?.length) {
413+
actions.push(...registeredMenuItems, new Separator());
414+
}
390415
if (command.command !== '') {
391416
const labelRun = localize("terminal.rerunCommand", 'Rerun Command');
392417
actions.push({

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { IXtermCore } from '../xterm-private.js';
1515
import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';
1616
import { Disposable, DisposableStore } from '../../../../../base/common/lifecycle.js';
1717
import { IEditorOptions } from '../../../../../editor/common/config/editorOptions.js';
18-
import { IShellIntegration, ITerminalLogService, TerminalSettingId } from '../../../../../platform/terminal/common/terminal.js';
18+
import { IShellIntegration, ITerminalLogService, TerminalSettingId, type IDecorationAddon } from '../../../../../platform/terminal/common/terminal.js';
1919
import { ITerminalFont, ITerminalConfiguration } from '../../common/terminal.js';
2020
import { IMarkTracker, IInternalXtermTerminal, IXtermTerminal, IXtermColorProvider, XtermTerminalConstants, IXtermAttachToElementOptions, IDetachedXtermTerminal, ITerminalConfigurationService } from '../terminal.js';
2121
import { LogLevel } from '../../../../../platform/log/common/log.js';
@@ -139,6 +139,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach
139139

140140
get markTracker(): IMarkTracker { return this._markNavigationAddon; }
141141
get shellIntegration(): IShellIntegration { return this._shellIntegrationAddon; }
142+
get decorationAddon(): IDecorationAddon { return this._decorationAddon; }
142143

143144
get textureAtlas(): Promise<ImageBitmap> | undefined {
144145
const canvas = this._webglAddon?.textureAtlas;

src/vs/workbench/contrib/terminalContrib/quickFix/browser/quickFixAddon.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ const quickFixClasses = [
4646
];
4747

4848
export interface ITerminalQuickFixAddon {
49+
readonly onDidRequestRerunCommand: Event<{ command: string; shouldExecute?: boolean }>;
50+
readonly onDidUpdateQuickFixes: Event<{ command: ITerminalCommand; actions: ITerminalAction[] | undefined }>;
4951
showMenu(): void;
50-
onDidRequestRerunCommand: Event<{ command: string; shouldExecute?: boolean }>;
5152
/**
5253
* Registers a listener on onCommandFinished scoped to a particular command or regular
5354
* expression and provides a callback to be executed for commands that match.
@@ -56,8 +57,6 @@ export interface ITerminalQuickFixAddon {
5657
}
5758

5859
export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon, ITerminalQuickFixAddon {
59-
private readonly _onDidRequestRerunCommand = new Emitter<{ command: string; shouldExecute?: boolean }>();
60-
readonly onDidRequestRerunCommand = this._onDidRequestRerunCommand.event;
6160

6261
private _terminal: Terminal | undefined;
6362

@@ -76,6 +75,11 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon,
7675

7776
private _didRun: boolean = false;
7877

78+
private readonly _onDidRequestRerunCommand = new Emitter<{ command: string; shouldExecute?: boolean }>();
79+
readonly onDidRequestRerunCommand = this._onDidRequestRerunCommand.event;
80+
private readonly _onDidUpdateQuickFixes = new Emitter<{ command: ITerminalCommand; actions: ITerminalAction[] | undefined }>();
81+
readonly onDidUpdateQuickFixes = this._onDidUpdateQuickFixes.event;
82+
7983
constructor(
8084
private readonly _aliases: string[][] | undefined,
8185
private readonly _capabilities: ITerminalCapabilityStore,
@@ -186,7 +190,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon,
186190
return;
187191
}
188192
if (command.command !== '' && this._lastQuickFixId) {
189-
this._disposeQuickFix(this._lastQuickFixId);
193+
this._disposeQuickFix(command, this._lastQuickFixId);
190194
}
191195

192196
const resolver = async (selector: ITerminalQuickFixOptions, lines?: string[]) => {
@@ -212,9 +216,11 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon,
212216
this._quickFixes = result;
213217
this._lastQuickFixId = this._quickFixes[0].id;
214218
this._registerQuickFixDecoration();
219+
this._onDidUpdateQuickFixes.fire({ command, actions: this._quickFixes });
220+
this._quickFixes = undefined;
215221
}
216222

217-
private _disposeQuickFix(id: string): void {
223+
private _disposeQuickFix(command: ITerminalCommand, id: string): void {
218224
type QuickFixResultTelemetryEvent = {
219225
quickFixId: string;
220226
ranQuickFix: boolean;
@@ -231,6 +237,7 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon,
231237
});
232238
this._decoration.clear();
233239
this._decorationDisposables.clear();
240+
this._onDidUpdateQuickFixes.fire({ command, actions: this._quickFixes });
234241
this._quickFixes = undefined;
235242
this._lastQuickFixId = undefined;
236243
this._didRun = false;
@@ -295,7 +302,6 @@ export class TerminalQuickFixAddon extends Disposable implements ITerminalAddon,
295302
this._register(dom.addDisposableListener(e, dom.EventType.CLICK, () => this.showMenu()));
296303
}));
297304
store.add(decoration.onDispose(() => this._currentRenderContext = undefined));
298-
this._quickFixes = undefined;
299305
}
300306
}
301307

src/vs/workbench/contrib/terminalContrib/quickFix/browser/terminal.quickFix.contribution.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import type { Terminal as RawXtermTerminal } from '@xterm/xterm';
77
import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js';
8-
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
8+
import { DisposableStore, MutableDisposable } from '../../../../../base/common/lifecycle.js';
99
import { localize2 } from '../../../../../nls.js';
1010
import { InstantiationType, registerSingleton } from '../../../../../platform/instantiation/common/extensions.js';
1111
import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
@@ -38,6 +38,8 @@ class TerminalQuickFixContribution extends DisposableStore implements ITerminalC
3838
private _addon?: TerminalQuickFixAddon;
3939
get addon(): TerminalQuickFixAddon | undefined { return this._addon; }
4040

41+
private readonly _quickFixMenuItems = this.add(new MutableDisposable());
42+
4143
constructor(
4244
private readonly _ctx: ITerminalContributionContext,
4345
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@@ -52,6 +54,10 @@ class TerminalQuickFixContribution extends DisposableStore implements ITerminalC
5254

5355
// Hook up listeners
5456
this.add(this._addon.onDidRequestRerunCommand((e) => this._ctx.instance.runCommand(e.command, e.shouldExecute || false)));
57+
this.add(this._addon.onDidUpdateQuickFixes(e => {
58+
// Only track the latest command's quick fixes
59+
this._quickFixMenuItems.value = e.actions ? xterm.decorationAddon.registerMenuItems(e.command, e.actions) : undefined;
60+
}));
5561

5662
// Register quick fixes
5763
for (const actionOption of [

0 commit comments

Comments
 (0)