From ae39ce1405bdcd2241fdf362860af5aafa141625 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 20 Mar 2023 15:14:04 -0700 Subject: [PATCH] Add terminal tab hover action for env changes Fixes #177128 --- .../browser/environmentVariableInfo.ts | 20 +++++- .../contrib/terminal/browser/terminal.ts | 2 + .../terminal/browser/terminalInstance.ts | 4 +- .../browser/terminalProcessManager.ts | 1 + .../contrib/terminal/common/terminal.ts | 3 + .../contrib/terminal/terminal.all.ts | 1 + ...erminal.environmentChanges.contribution.ts | 66 +++++++++++++++++++ 7 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 src/vs/workbench/contrib/terminalContrib/environmentChanges/browser/terminal.environmentChanges.contribution.ts diff --git a/src/vs/workbench/contrib/terminal/browser/environmentVariableInfo.ts b/src/vs/workbench/contrib/terminal/browser/environmentVariableInfo.ts index 220381f43fbbb..c799b07bccfa0 100644 --- a/src/vs/workbench/contrib/terminal/browser/environmentVariableInfo.ts +++ b/src/vs/workbench/contrib/terminal/browser/environmentVariableInfo.ts @@ -8,9 +8,13 @@ import { ITerminalStatus, ITerminalStatusHoverAction, TerminalCommandId } from ' import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { localize } from 'vs/nls'; import { Codicon } from 'vs/base/common/codicons'; -import { IExtensionOwnedEnvironmentVariableMutator, IMergedEnvironmentVariableCollection, IMergedEnvironmentVariableCollectionDiff } from 'vs/platform/terminal/common/environmentVariable'; +import { EnvironmentVariableMutatorType, IExtensionOwnedEnvironmentVariableMutator, IMergedEnvironmentVariableCollection, IMergedEnvironmentVariableCollectionDiff } from 'vs/platform/terminal/common/environmentVariable'; import { TerminalStatus } from 'vs/workbench/contrib/terminal/browser/terminalStatusList'; import Severity from 'vs/base/common/severity'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { URI } from 'vs/base/common/uri'; +import { Schemas } from 'vs/base/common/network'; +import { ICommandService } from 'vs/platform/commands/common/commands'; export class EnvironmentVariableInfoStale implements IEnvironmentVariableInfo { readonly requiresAction = true; @@ -59,7 +63,8 @@ export class EnvironmentVariableInfoChangesActive implements IEnvironmentVariabl readonly requiresAction = false; constructor( - private readonly _collection: IMergedEnvironmentVariableCollection + private readonly _collection: IMergedEnvironmentVariableCollection, + @ICommandService private readonly _commandService: ICommandService ) { } @@ -75,11 +80,20 @@ export class EnvironmentVariableInfoChangesActive implements IEnvironmentVariabl return message; } + private _getActions(): ITerminalStatusHoverAction[] { + return [{ + label: localize('showEnvironmentContributions', "Show environment contributions"), + run: () => this._commandService.executeCommand(TerminalCommandId.ShowEnvironmentContributions), + commandId: TerminalCommandId.ShowEnvironmentContributions + }]; + } + getStatus(): ITerminalStatus { return { id: TerminalStatus.EnvironmentVariableInfoChangesActive, severity: Severity.Info, - tooltip: this._getInfo() + tooltip: this._getInfo(), + hoverActions: this._getActions() }; } } diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 15b97797a0483..b1cef6380c7a7 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -12,6 +12,7 @@ import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IKeyMods } from 'vs/platform/quickinput/common/quickInput'; import { IMarkProperties, ITerminalCapabilityStore, ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities'; +import { IMergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable'; import { IExtensionTerminalProfile, IReconnectionProperties, IShellIntegration, IShellLaunchConfig, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, TerminalExitReason, TerminalIcon, TerminalLocation, TerminalShellType, TerminalType, TitleEventSource, WaitOnExitValue } from 'vs/platform/terminal/common/terminal'; import { IColorTheme } from 'vs/platform/theme/common/themeService'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -457,6 +458,7 @@ export interface ITerminalInstance { readonly capabilities: ITerminalCapabilityStore; readonly usedShellIntegrationInjection: boolean; readonly injectedArgs: string[] | undefined; + readonly extEnvironmentVariableCollection: IMergedEnvironmentVariableCollection | undefined; readonly statusList: ITerminalStatusList; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 4ef9fbca444db..47c94694f232f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -84,7 +84,7 @@ import { IAudioCueService, AudioCue } from 'vs/platform/audioCues/browser/audioC import { ITerminalQuickFixOptions } from 'vs/platform/terminal/common/xterm/terminalQuickFix'; import { FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files'; import { preparePathForShell } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; -import { IEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable'; +import { IEnvironmentVariableCollection, IMergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable'; import { ISimpleSelectedSuggestion } from 'vs/workbench/services/suggest/browser/simpleSuggestWidget'; import { TERMINAL_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { editorBackground } from 'vs/platform/theme/common/colorRegistry'; @@ -221,6 +221,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { */ get quickFix(): ITerminalQuickFixAddon | undefined { return this._quickFixAddon; } + get extEnvironmentVariableCollection(): IMergedEnvironmentVariableCollection | undefined { return this._processManager.extEnvironmentVariableCollection; } + xterm?: XtermTerminal; disableLayout: boolean = false; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index ae8d3aac50097..9cb4d00bd7960 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -122,6 +122,7 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce get hasWrittenData(): boolean { return this._hasWrittenData; } get hasChildProcesses(): boolean { return this._hasChildProcesses; } get reconnectionProperties(): IReconnectionProperties | undefined { return this._shellLaunchConfig?.attachPersistentProcess?.reconnectionProperties || this._shellLaunchConfig?.reconnectionProperties || undefined; } + get extEnvironmentVariableCollection(): IMergedEnvironmentVariableCollection | undefined { return this._extEnvironmentVariableCollection; } constructor( private readonly _instanceId: number, diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 330725d104cbd..3fd3c49f09c31 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -18,6 +18,7 @@ import { ThemeIcon } from 'vs/base/common/themables'; import { IProcessDetails } from 'vs/platform/terminal/common/terminalProcess'; import { ITerminalQuickFixProvider, ITerminalCommandSelector, ITerminalOutputMatch, ITerminalOutputMatcher } from 'vs/platform/terminal/common/xterm/terminalQuickFix'; import Severity from 'vs/base/common/severity'; +import { IMergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable'; export const TERMINAL_VIEW_ID = 'terminal'; @@ -395,6 +396,7 @@ export interface ITerminalProcessManager extends IDisposable { readonly hasChildProcesses: boolean; readonly backend: ITerminalBackend | undefined; readonly capabilities: ITerminalCapabilityStore; + readonly extEnvironmentVariableCollection: IMergedEnvironmentVariableCollection | undefined; readonly onPtyDisconnect: Event; readonly onPtyReconnect: Event; @@ -618,6 +620,7 @@ export const enum TerminalCommandId { AcceptSelectedSuggestion = 'workbench.action.terminal.acceptSelectedSuggestion', HideSuggestWidget = 'workbench.action.terminal.hideSuggestWidget', FocusHover = 'workbench.action.terminal.focusHover', + ShowEnvironmentContributions = 'workbench.action.terminal.showEnvironmentContributions', } export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ diff --git a/src/vs/workbench/contrib/terminal/terminal.all.ts b/src/vs/workbench/contrib/terminal/terminal.all.ts index 5b6be8a682dab..f8fa0775a5e8c 100644 --- a/src/vs/workbench/contrib/terminal/terminal.all.ts +++ b/src/vs/workbench/contrib/terminal/terminal.all.ts @@ -15,5 +15,6 @@ import 'vs/workbench/contrib/terminal/browser/terminalView'; // primary workbench contribution) import 'vs/workbench/contrib/terminalContrib/accessibility/browser/terminal.accessibility.contribution'; import 'vs/workbench/contrib/terminalContrib/developer/browser/terminal.developer.contribution'; +import 'vs/workbench/contrib/terminalContrib/environmentChanges/browser/terminal.environmentChanges.contribution'; import 'vs/workbench/contrib/terminalContrib/find/browser/terminal.find.contribution'; import 'vs/workbench/contrib/terminalContrib/links/browser/terminal.links.contribution'; diff --git a/src/vs/workbench/contrib/terminalContrib/environmentChanges/browser/terminal.environmentChanges.contribution.ts b/src/vs/workbench/contrib/terminalContrib/environmentChanges/browser/terminal.environmentChanges.contribution.ts new file mode 100644 index 0000000000000..0adfe7d63292a --- /dev/null +++ b/src/vs/workbench/contrib/terminalContrib/environmentChanges/browser/terminal.environmentChanges.contribution.ts @@ -0,0 +1,66 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Schemas } from 'vs/base/common/network'; +import { localize } from 'vs/nls'; +import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; +import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { EnvironmentVariableMutatorType, IMergedEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable'; +import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; +import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey'; +import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { URI } from 'vs/base/common/uri'; + +const category = terminalStrings.actionCategory; + +// TODO: The rest of the terminal environment changes feature should move here https://github.com/microsoft/vscode/issues/177241 + +registerAction2(class extends Action2 { + constructor() { + super({ + id: TerminalCommandId.ShowEnvironmentContributions, + title: { value: localize('workbench.action.terminal.showEnvironmentContributions', "Show Environment Contributions"), original: 'Show Environment Contributions' }, + category, + f1: true, + precondition: TerminalContextKeys.processSupported + }); + } + async run(accessor: ServicesAccessor) { + const collection = accessor.get(ITerminalService).activeInstance?.extEnvironmentVariableCollection; + if (collection) { + const editorService = accessor.get(IEditorService); + await editorService.openEditor({ + resource: URI.from({ + scheme: Schemas.untitled + }), + contents: describeEnvironmentChanges(collection), + languageId: 'markdown' + }); + } + } +}); + + +function describeEnvironmentChanges(collection: IMergedEnvironmentVariableCollection): string { + let content = `# ${localize('envChanges', 'Terminal Environment Changes')}`; + for (const [ext, coll] of collection.collections) { + content += `\n\n## ${localize('extension', 'Extension: {0}', ext)}`; + content += '\n'; + for (const [variable, mutator] of coll.map.entries()) { + content += `\n- \`${mutatorTypeLabel(mutator.type, mutator.value, variable)}\``; + } + } + return content; +} + +function mutatorTypeLabel(type: EnvironmentVariableMutatorType, value: string, variable: string): string { + switch (type) { + case EnvironmentVariableMutatorType.Prepend: return `${variable}=${value}\${env:${variable}}`; + case EnvironmentVariableMutatorType.Append: return `${variable}=\${env:${variable}}${value}`; + default: return `${variable}=${value}`; + } +}