diff --git a/src/vs/platform/terminal/common/environmentVariable.ts b/src/vs/platform/terminal/common/environmentVariable.ts index 3df82accaae..8ff5a08abc4 100644 --- a/src/vs/platform/terminal/common/environmentVariable.ts +++ b/src/vs/platform/terminal/common/environmentVariable.ts @@ -11,17 +11,12 @@ export enum EnvironmentVariableMutatorType { Append = 2, Prepend = 3 } -// export enum EnvironmentVariableMutatorTiming { -// AtSpawn = 1, -// AfterShellIntegration = 2 -// // TODO: Do we need a both? -// } export interface IEnvironmentVariableMutator { readonly variable: string; readonly value: string; readonly type: EnvironmentVariableMutatorType; readonly scope?: EnvironmentVariableScope; - // readonly timing?: EnvironmentVariableMutatorTiming; + readonly options?: IEnvironmentVariableMutatorOptions; } export interface IEnvironmentDescriptionMutator { @@ -29,6 +24,11 @@ export interface IEnvironmentDescriptionMutator { readonly scope?: EnvironmentVariableScope; } +export interface IEnvironmentVariableMutatorOptions { + applyAtProcessCreation?: boolean; + applyAtShellIntegration?: boolean; +} + export type EnvironmentVariableScope = { workspaceFolder?: IWorkspaceFolderData; }; diff --git a/src/vs/platform/terminal/common/environmentVariableCollection.ts b/src/vs/platform/terminal/common/environmentVariableCollection.ts index 3c223347ceb..af9c677286b 100644 --- a/src/vs/platform/terminal/common/environmentVariableCollection.ts +++ b/src/vs/platform/terminal/common/environmentVariableCollection.ts @@ -8,11 +8,11 @@ import { EnvironmentVariableMutatorType, EnvironmentVariableScope, IEnvironmentV type VariableResolver = (str: string) => Promise; -// const mutatorTypeToLabelMap: Map = new Map([ -// [EnvironmentVariableMutatorType.Append, 'APPEND'], -// [EnvironmentVariableMutatorType.Prepend, 'PREPEND'], -// [EnvironmentVariableMutatorType.Replace, 'REPLACE'] -// ]); +const mutatorTypeToLabelMap: Map = new Map([ + [EnvironmentVariableMutatorType.Append, 'APPEND'], + [EnvironmentVariableMutatorType.Prepend, 'PREPEND'], + [EnvironmentVariableMutatorType.Replace, 'REPLACE'] +]); export class MergedEnvironmentVariableCollection implements IMergedEnvironmentVariableCollection { private readonly map: Map = new Map(); @@ -69,26 +69,33 @@ export class MergedEnvironmentVariableCollection implements IMergedEnvironmentVa const actualVariable = isWindows ? lowerToActualVariableNames![variable.toLowerCase()] || variable : variable; for (const mutator of mutators) { const value = variableResolver ? await variableResolver(mutator.value) : mutator.value; - // if (mutator.timing === EnvironmentVariableMutatorTiming.AfterShellIntegration) { - // const key = `VSCODE_ENV_${mutatorTypeToLabelMap.get(mutator.type)!}`; - // env[key] = (env[key] ? env[key] + ':' : '') + variable + '=' + value; - // continue; - // } - switch (mutator.type) { - case EnvironmentVariableMutatorType.Append: - env[actualVariable] = (env[actualVariable] || '') + value; - break; - case EnvironmentVariableMutatorType.Prepend: - env[actualVariable] = value + (env[actualVariable] || ''); - break; - case EnvironmentVariableMutatorType.Replace: - env[actualVariable] = value; - break; + // Default: true + if (mutator.options?.applyAtProcessCreation ?? true) { + switch (mutator.type) { + case EnvironmentVariableMutatorType.Append: + env[actualVariable] = (env[actualVariable] || '') + value; + break; + case EnvironmentVariableMutatorType.Prepend: + env[actualVariable] = value + (env[actualVariable] || ''); + break; + case EnvironmentVariableMutatorType.Replace: + env[actualVariable] = value; + break; + } + } + // Default: false + if (mutator.options?.applyAtShellIntegration ?? false) { + const key = `VSCODE_ENV_${mutatorTypeToLabelMap.get(mutator.type)!}`; + env[key] = (env[key] ? env[key] + ':' : '') + variable + '=' + this._encodeColons(value); } } } } + private _encodeColons(value: string): string { + return value.replaceAll(':', '\\x3a'); + } + diff(other: IMergedEnvironmentVariableCollection, scope: EnvironmentVariableScope | undefined): IMergedEnvironmentVariableCollectionDiff | undefined { const added: Map = new Map(); const changed: Map = new Map(); diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index f43a403ff42..d11771537f0 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -407,6 +407,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape map: deserializeEnvironmentVariableCollection(collection), descriptionMap: deserializeEnvironmentDescriptionMap(descriptionMap) }; + console.log('translatedCollection', translatedCollection); this._environmentVariableService.set(extensionIdentifier, translatedCollection); } else { this._environmentVariableService.delete(extensionIdentifier); diff --git a/src/vs/workbench/api/common/extHostTerminalService.ts b/src/vs/workbench/api/common/extHostTerminalService.ts index c7031319846..89520de6787 100644 --- a/src/vs/workbench/api/common/extHostTerminalService.ts +++ b/src/vs/workbench/api/common/extHostTerminalService.ts @@ -892,15 +892,18 @@ class EnvironmentVariableCollection implements vscode.EnvironmentVariableCollect } replace(variable: string, value: string, scope?: vscode.EnvironmentVariableScope): void { - this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Replace, scope }); + // TODO: Implement options in API + this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Replace, scope, options: {} }); } append(variable: string, value: string, scope?: vscode.EnvironmentVariableScope): void { - this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Append, scope }); + // TODO: Implement options in API + this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Append, scope, options: {} }); } prepend(variable: string, value: string, scope?: vscode.EnvironmentVariableScope): void { - this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Prepend, scope }); + // TODO: Implement options in API + this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Prepend, scope, options: {} }); } private _setIfDiffers(variable: string, mutator: vscode.EnvironmentVariableMutator): void { @@ -920,6 +923,7 @@ class EnvironmentVariableCollection implements vscode.EnvironmentVariableCollect get(variable: string, scope?: vscode.EnvironmentVariableScope): vscode.EnvironmentVariableMutator | undefined { const key = this.getKey(variable, scope); const value = this.map.get(key); + // TODO: Set options to defaults if needed return value ? convertMutator(value) : undefined; } @@ -1030,6 +1034,7 @@ function asTerminalColor(color?: vscode.ThemeColor): ThemeColor | undefined { function convertMutator(mutator: IEnvironmentVariableMutator): vscode.EnvironmentVariableMutator { const newMutator = { ...mutator }; newMutator.scope = newMutator.scope ?? undefined; + newMutator.options = newMutator.options ?? undefined; delete (newMutator as any).variable; return newMutator as vscode.EnvironmentVariableMutator; } diff --git a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 index e3201449086..616b9b9736f 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 +++ b/src/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1 @@ -21,6 +21,10 @@ $Global:__LastHistoryId = -1 $Nonce = $env:VSCODE_NONCE $env:VSCODE_NONCE = $null +Write-Host "REPLACE: " $env:VSCODE_ENV_REPLACE +Write-Host "PREPEND: " $env:VSCODE_ENV_PREPEND +Write-Host "APPEND: " $env:VSCODE_ENV_APPEND + if ($env:VSCODE_ENV_REPLACE) { $Split = $env:VSCODE_ENV_REPLACE.Split(":") foreach ($Item in $Split) { diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index c18e798edf8..9d70b48d6c7 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -33,6 +33,7 @@ export const allApiProposals = Object.freeze({ dropMetadata: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.dropMetadata.d.ts', editSessionIdentityProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.editSessionIdentityProvider.d.ts', editorInsets: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.editorInsets.d.ts', + envCollectionOptions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.envCollectionOptions.d.ts', envCollectionWorkspace: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.envCollectionWorkspace.d.ts', envShellEvent: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.envShellEvent.d.ts', extensionRuntime: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.extensionRuntime.d.ts', diff --git a/src/vscode-dts/vscode.proposed.envCollectionOptions.d.ts b/src/vscode-dts/vscode.proposed.envCollectionOptions.d.ts new file mode 100644 index 00000000000..b55c72fe214 --- /dev/null +++ b/src/vscode-dts/vscode.proposed.envCollectionOptions.d.ts @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + // https://github.com/microsoft/vscode/issues/179476 + + export interface EnvironmentVariableMutatorOptions { + /** + * Apply to the environment just before the process is created. + * + * Defaults to true. + */ + applyAtProcessCreation?: boolean; + + /** + * Apply to the environment in the shell integration script. Note that this _will not_ apply + * the mutator if shell integration is disabled or not working for some reason. + * + * Defaults to false. + */ + applyAtShellIntegration?: boolean; + } + + /** + * A type of mutation and its value to be applied to an environment variable. + */ + export interface EnvironmentVariableMutator { + /** + * Options applied to the mutator. + */ + readonly options: EnvironmentVariableMutatorOptions; + } + + export interface EnvironmentVariableCollection extends Iterable<[variable: string, mutator: EnvironmentVariableMutator]> { + // TODO: Uncomment when workspace/scopes is removed from the other proposal + // /** + // * @param options Options applied to the mutator. + // */ + // replace(variable: string, value: string, options?: EnvironmentVariableMutatorOptions): void; + + // /** + // * @param options Options applied to the mutator. + // */ + // append(variable: string, value: string, options?: EnvironmentVariableMutatorOptions): void; + + // /** + // * @param options Options applied to the mutator. + // */ + // prepend(variable: string, value: string, options?: EnvironmentVariableMutatorOptions): void; + } +}