Skip to content
6 changes: 4 additions & 2 deletions src/vs/platform/terminal/node/terminalEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,16 @@ export function getShellIntegrationInjection(
if (options.shellIntegration.nonce) {
envMixin['VSCODE_NONCE'] = options.shellIntegration.nonce;
}
// Temporarily pass list of hardcoded env vars for shell env api
const scopedDownShellEnvs = ['PATH', 'VIRTUAL_ENV', 'HOME', 'SHELL', 'PWD'];
if (shellLaunchConfig.shellIntegrationEnvironmentReporting) {
if (isWindows) {
const enableWindowsEnvReporting = options.windowsUseConptyDll || options.windowsEnableConpty && getWindowsBuildNumber() >= 22631 && shell !== 'bash.exe';
if (enableWindowsEnvReporting) {
envMixin['VSCODE_SHELL_ENV_REPORTING'] = '1';
envMixin['VSCODE_SHELL_ENV_REPORTING'] = scopedDownShellEnvs.join(',');
}
} else {
envMixin['VSCODE_SHELL_ENV_REPORTING'] = '1';
envMixin['VSCODE_SHELL_ENV_REPORTING'] = scopedDownShellEnvs.join(',');
}
}
// Windows
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ bash_major_version=${BASH_VERSINFO[0]}
__vscode_shell_env_reporting="$VSCODE_SHELL_ENV_REPORTING"
unset VSCODE_SHELL_ENV_REPORTING

envVarsToReport=()
IFS=',' read -ra envVarsToReport <<< "$__vscode_shell_env_reporting"

if (( BASH_VERSINFO[0] >= 4 )); then
use_associative_array=1
# Associative arrays are only available in bash 4.0+
Expand Down Expand Up @@ -248,26 +251,6 @@ __updateEnvCacheAA() {
fi
}

__trackMissingEnvVarsAA() {
if [ "$use_associative_array" = 1 ]; then
declare -A currentEnvMap
while IFS= read -r line; do
if [[ "$line" == *"="* ]]; then
local key="${line%%=*}"
local value="${line#*=}"
currentEnvMap["$key"]="$value"
fi
done < <(env)

for key in "${!vsc_aa_env[@]}"; do
if [ -z "${currentEnvMap[$key]}" ]; then
builtin printf '\e]633;EnvSingleDelete;%s;%s;%s\a' "$key" "$(__vsc_escape_value "${vsc_aa_env[$key]}")" "$__vsc_nonce"
builtin unset "vsc_aa_env[$key]"
fi
done
fi
}

__updateEnvCache() {
local key="$1"
local value="$2"
Expand All @@ -287,86 +270,51 @@ __updateEnvCache() {
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
}

__trackMissingEnvVars() {
local current_env_keys=()

while IFS='=' read -r key value; do
current_env_keys+=("$key")
done < <(env)

# Compare vsc_env_keys with user's current_env_keys
for key in "${vsc_env_keys[@]}"; do
local found=0
for env_key in "${current_env_keys[@]}"; do
if [[ "$key" == "$env_key" ]]; then
found=1
break
fi
done
if [ "$found" = 0 ]; then
builtin printf '\e]633;EnvSingleDelete;%s;%s;%s\a' "${vsc_env_keys[i]}" "$(__vsc_escape_value "${vsc_env_values[i]}")" "$__vsc_nonce"
builtin unset 'vsc_env_keys[i]'
builtin unset 'vsc_env_values[i]'
fi
done

# Remove gaps from unset
vsc_env_keys=("${vsc_env_keys[@]}")
vsc_env_values=("${vsc_env_values[@]}")
}

__vsc_update_env() {
if [[ "$__vscode_shell_env_reporting" == "1" ]]; then
if [[ ${#envVarsToReport[@]} -gt 0 ]]; then
builtin printf '\e]633;EnvSingleStart;%s;%s\a' 0 $__vsc_nonce

if [ "$use_associative_array" = 1 ]; then
if [ ${#vsc_aa_env[@]} -eq 0 ]; then
# Associative array is empty, do not diff, just add
# Use null byte instead of a newline to support multi-line values (e.g. PS1 values)
while IFS= read -r -d $'\0' line; do
if [[ "$line" == *"="* ]]; then
# %% removes longest match of =* Ensure we get everything before first equal sign.
local key="${line%%=*}"
# # removes shortest match of *= Ensure we get everything after first equal sign. Preserving additional equal signs.
local value="${line#*=}"
for key in "${envVarsToReport[@]}"; do
if [ -n "${!key+x}" ]; then
local value="${!key}"
vsc_aa_env["$key"]="$value"
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
fi
done < <(env -0) # env command with null bytes as separator instead of newlines
done
else
# Diff approach for associative array
while IFS= read -r -d $'\0' line; do
if [[ "$line" == *"="* ]]; then
local key="${line%%=*}"
local value="${line#*=}"
for key in "${envVarsToReport[@]}"; do
if [ -n "${!key+x}" ]; then
local value="${!key}"
__updateEnvCacheAA "$key" "$value"
fi
done < <(env -0)
__trackMissingEnvVarsAA
done
# Track missing env vars not needed for now, as we are only tracking pre-defined env var from terminalEnvironment.
fi

else
if [[ -z ${vsc_env_keys[@]} ]] && [[ -z ${vsc_env_values[@]} ]]; then
# Non associative arrays are both empty, do not diff, just add
while IFS= read -r -d $'\0' line; do
if [[ "$line" == *"="* ]]; then
local key="${line%%=*}"
local value="${line#*=}"
for key in "${envVarsToReport[@]}"; do
if [ -n "${!key+x}" ]; then
local value="${!key}"
vsc_env_keys+=("$key")
vsc_env_values+=("$value")
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
fi
done < <(env -0)
done
else
# Diff approach for non-associative arrays
while IFS= read -r -d $'\0' line; do
if [[ "$line" == *"="* ]]; then
local key="${line%%=*}"
local value="${line#*=}"
for key in "${envVarsToReport[@]}"; do
if [ -n "${!key+x}" ]; then
local value="${!key}"
__updateEnvCache "$key" "$value"
fi
done < <(env -0)
__trackMissingEnvVars
done
# Track missing env vars not needed for now, as we are only tracking pre-defined env var from terminalEnvironment.
fi
fi
builtin printf '\e]633;EnvSingleEnd;%s;\a' $__vsc_nonce
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ unset VSCODE_NONCE
__vscode_shell_env_reporting="$VSCODE_SHELL_ENV_REPORTING"
unset VSCODE_SHELL_ENV_REPORTING

envVarsToReport=()
IFS=',' read -rA envVarsToReport <<< "$__vscode_shell_env_reporting"

builtin printf "\e]633;P;ContinuationPrompt=%s\a" "$(echo "$PS2" | sed 's/\x1b/\\\\x1b/g')"

# Report prompt type
Expand Down Expand Up @@ -150,23 +153,6 @@ __update_env_cache_aa() {
fi
}

__track_missing_env_vars_aa() {
if [ $__vsc_use_aa -eq 1 ]; then
typeset -A currentEnvMap
while IFS='=' read -r key value; do
currentEnvMap["$key"]="$value"
done < <(env)

for k in "${(@k)vsc_aa_env}"; do
# if currentEnvMap does not have the key, then it is missing
if ! [[ -v currentEnvMap[$k] ]]; then
builtin printf '\e]633;EnvSingleDelete;%s;%s;%s\a' "${(Q)k}" "$(__vsc_escape_value "${vsc_aa_env[$k]}")" "$__vsc_nonce"
builtin unset "vsc_aa_env[$k]"
fi
done
fi
}

__update_env_cache() {
local key="$1"
local value="$2"
Expand All @@ -187,69 +173,49 @@ __update_env_cache() {
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
}

__track_missing_env_vars() {
local currentEnvKeys=();

while IFS='=' read -r key value; do
currentEnvKeys+=("$key");
done < <(env);

# Compare __vsc_env_keys with user's currentEnvKeys
for ((i = 1; i <= ${#__vsc_env_keys[@]}; i++)); do
local found=0;
for envKey in "${currentEnvKeys[@]}"; do
if [[ "${__vsc_env_keys[$i]}" == "$envKey" ]]; then
found=1;
break;
fi;
done;
if [ "$found" = 0 ]; then
builtin printf '\e]633;EnvSingleDelete;%s;%s;%s\a' "${__vsc_env_keys[$i]}" "$(__vsc_escape_value "${__vsc_env_values[$i]}")" "$__vsc_nonce";
unset "__vsc_env_keys[$i]";
unset "__vsc_env_values[$i]";
fi;
done;

# Remove gaps from unset
__vsc_env_keys=("${(@)__vsc_env_keys}");
__vsc_env_values=("${(@)__vsc_env_values}");
}


__vsc_update_env() {
if [[ "$__vscode_shell_env_reporting" == "1" ]]; then
if [[ ${#envVarsToReport[@]} -gt 0 ]]; then
builtin printf '\e]633;EnvSingleStart;%s;%s;\a' 0 $__vsc_nonce
if [ $__vsc_use_aa -eq 1 ]; then
if [[ ${#vsc_aa_env[@]} -eq 0 ]]; then
# Associative array is empty, do not diff, just add
while IFS='=' read -r key value; do
vsc_aa_env["$key"]="$value"
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
done < <(env)
for key in "${envVarsToReport[@]}"; do
if [[ -v $key ]]; then
vsc_aa_env["$key"]="${(P)key}"
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "${(P)key}")" "$__vsc_nonce"
fi
done
else
# Diff approach for associative array
while IFS='=' read -r key value; do
__update_env_cache_aa "$key" "$value"
done < <(env)
__track_missing_env_vars_aa

for var in "${envVarsToReport[@]}"; do
if [[ -v $var ]]; then
value="${(P)var}"
__update_env_cache_aa "$var" "$value"
fi
done
# Track missing env vars not needed for now, as we are only tracking pre-defined env var from terminalEnvironment.
fi
else
# Two arrays approach
if [[ ${#__vsc_env_keys[@]} -eq 0 ]] && [[ ${#__vsc_env_values[@]} -eq 0 ]]; then
# Non-associative arrays are both empty, do not diff, just add
while IFS='=' read -r key value; do
__vsc_env_keys+=("$key")
__vsc_env_values+=("$value")
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
done < <(env)
for key in "${envVarsToReport[@]}"; do
if [[ -v $key ]]; then
value="${(P)key}"
__vsc_env_keys+=("$key")
__vsc_env_values+=("$value")
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
fi
done
else
# Diff approach for non-associative arrays
while IFS='=' read -r key value; do
__update_env_cache "$key" "$value"
done < <(env)
__track_missing_env_vars

for var in "${envVarsToReport[@]}"; do
if [[ -v $var ]]; then
value="${(P)var}"
__update_env_cache "$var" "$value"
fi
done
# Track missing env vars not needed for now, as we are only tracking pre-defined env var from terminalEnvironment.
fi
fi

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ or exit
set --global VSCODE_SHELL_INTEGRATION 1
set --global __vscode_shell_env_reporting $VSCODE_SHELL_ENV_REPORTING
set -e VSCODE_SHELL_ENV_REPORTING
set -g envVarsToReport
if test -n "$__vscode_shell_env_reporting"
set envVarsToReport (string split "," "$__vscode_shell_env_reporting")
end

# Apply any explicit path prefix (see #99878)
# On fish, '$fish_user_paths' is always prepended to the PATH, for both login and non-login shells, so we need
Expand Down Expand Up @@ -159,15 +163,20 @@ function __vsc_update_cwd --on-event fish_prompt
end
end

if test "$__vscode_shell_env_reporting" = "1"
if test -n "$__vscode_shell_env_reporting"
function __vsc_update_env --on-event fish_prompt
__vsc_esc EnvSingleStart 1
for line in (env)
set myVar (echo $line | awk -F= '{print $1}')
set myVal (echo $line | awk -F= '{print $2}')
__vsc_esc EnvSingleEntry $myVar (__vsc_escape_value "$myVal")
if test (count $envVarsToReport) -gt 0
__vsc_esc EnvSingleStart 1

for key in $envVarsToReport
if set -q $key
set -l value $$key
__vsc_esc EnvSingleEntry $key (__vsc_escape_value "$value")
end
end

__vsc_esc EnvSingleEnd
end
__vsc_esc EnvSingleEnd
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ $env:VSCODE_STABLE = $null

$__vscode_shell_env_reporting = $env:VSCODE_SHELL_ENV_REPORTING
$env:VSCODE_SHELL_ENV_REPORTING = $null
$Global:envVarsToReport = @()
if ($__vscode_shell_env_reporting) {
$Global:envVarsToReport = $__vscode_shell_env_reporting.Split(',')
}

$osVersion = [System.Environment]::OSVersion.Version
$isWindows10 = $IsWindows -and $osVersion.Major -eq 10 -and $osVersion.Minor -eq 0 -and $osVersion.Build -lt 22000
Expand Down Expand Up @@ -97,11 +101,15 @@ function Global:Prompt() {

# Send current environment variables as JSON
# OSC 633 ; EnvJson ; <Environment> ; <Nonce>
if ($__vscode_shell_env_reporting -eq "1") {
if ($Global:envVarsToReport.Count -gt 0) {
$envMap = @{}
Get-ChildItem Env: | ForEach-Object { $envMap[$_.Name] = $_.Value }
$envJson = $envMap | ConvertTo-Json -Compress
$Result += "$([char]0x1b)]633;EnvJson;$(__VSCode-Escape-Value $envJson);$Nonce`a"
foreach ($varName in $envVarsToReport) {
if (Test-Path "env:$varName") {
$envMap[$varName] = (Get-Item "env:$varName").Value
}
}
$envJson = $envMap | ConvertTo-Json -Compress
$Result += "$([char]0x1b)]633;EnvJson;$(__VSCode-Escape-Value $envJson);$Nonce`a"
}

# Before running the original prompt, put $? back to what it was:
Expand Down
Loading