aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/terminal/shellintegrations
diff options
context:
space:
mode:
authorMarcus Tillmanns <[email protected]>2023-09-28 16:07:17 +0200
committerMarcus Tillmanns <[email protected]>2023-10-04 11:13:46 +0000
commit43f770b08778739f45fb2e25aec564acd3114669 (patch)
tree1134587c9d79d099c969b58ff5a434a28c569f7d /src/plugins/terminal/shellintegrations
parentfc93f7d1b71c93b573660c7b59cb5b748ec4fc51 (diff)
Terminal: Pull upstream shellintegration scripts
Change-Id: Ic0fed1a56ec635351716dca1e410050990d2dd98 Reviewed-by: <[email protected]> Reviewed-by: Alessandro Portale <[email protected]>
Diffstat (limited to 'src/plugins/terminal/shellintegrations')
-rwxr-xr-xsrc/plugins/terminal/shellintegrations/shellintegration-bash.sh43
-rw-r--r--src/plugins/terminal/shellintegrations/shellintegration-rc.zsh33
-rw-r--r--src/plugins/terminal/shellintegrations/shellintegration.fish103
-rw-r--r--src/plugins/terminal/shellintegrations/shellintegration.ps139
4 files changed, 187 insertions, 31 deletions
diff --git a/src/plugins/terminal/shellintegrations/shellintegration-bash.sh b/src/plugins/terminal/shellintegrations/shellintegration-bash.sh
index 7db188be08e..d9792f34baa 100755
--- a/src/plugins/terminal/shellintegrations/shellintegration-bash.sh
+++ b/src/plugins/terminal/shellintegrations/shellintegration-bash.sh
@@ -3,7 +3,7 @@
# Prevent the script recursing when setting up
-if [[ -n "$VSCODE_SHELL_INTEGRATION" ]]; then
+if [[ -n "${VSCODE_SHELL_INTEGRATION:-}" ]]; then
builtin return
fi
@@ -32,7 +32,7 @@ if [ "$VSCODE_INJECTION" == "1" ]; then
builtin unset VSCODE_SHELL_LOGIN
# Apply any explicit path prefix (see #99878)
- if [ -n "$VSCODE_PATH_PREFIX" ]; then
+ if [ -n "${VSCODE_PATH_PREFIX:-}" ]; then
export PATH=$VSCODE_PATH_PREFIX$PATH
builtin unset VSCODE_PATH_PREFIX
fi
@@ -44,6 +44,35 @@ if [ -z "$VSCODE_SHELL_INTEGRATION" ]; then
builtin return
fi
+# Apply EnvironmentVariableCollections if needed
+if [ -n "${VSCODE_ENV_REPLACE:-}" ]; then
+ IFS=':' read -ra ADDR <<< "$VSCODE_ENV_REPLACE"
+ for ITEM in "${ADDR[@]}"; do
+ VARNAME="$(echo $ITEM | cut -d "=" -f 1)"
+ VALUE="$(echo -e "$ITEM" | cut -d "=" -f 2)"
+ export $VARNAME="$VALUE"
+ done
+ builtin unset VSCODE_ENV_REPLACE
+fi
+if [ -n "${VSCODE_ENV_PREPEND:-}" ]; then
+ IFS=':' read -ra ADDR <<< "$VSCODE_ENV_PREPEND"
+ for ITEM in "${ADDR[@]}"; do
+ VARNAME="$(echo $ITEM | cut -d "=" -f 1)"
+ VALUE="$(echo -e "$ITEM" | cut -d "=" -f 2)"
+ export $VARNAME="$VALUE${!VARNAME}"
+ done
+ builtin unset VSCODE_ENV_PREPEND
+fi
+if [ -n "${VSCODE_ENV_APPEND:-}" ]; then
+ IFS=':' read -ra ADDR <<< "$VSCODE_ENV_APPEND"
+ for ITEM in "${ADDR[@]}"; do
+ VARNAME="$(echo $ITEM | cut -d "=" -f 1)"
+ VALUE="$(echo -e "$ITEM" | cut -d "=" -f 2)"
+ export $VARNAME="${!VARNAME}$VALUE"
+ done
+ builtin unset VSCODE_ENV_APPEND
+fi
+
__vsc_get_trap() {
# 'trap -p DEBUG' outputs a shell command like `trap -- '…shellcode…' DEBUG`.
# The terms are quoted literals, but are not guaranteed to be on a single line.
@@ -110,6 +139,10 @@ __vsc_custom_PS2=""
__vsc_in_command_execution="1"
__vsc_current_command=""
+# It's fine this is in the global scope as it getting at it requires access to the shell environment
+__vsc_nonce="$VSCODE_NONCE"
+unset VSCODE_NONCE
+
__vsc_prompt_start() {
builtin printf '\e]633;A\a'
}
@@ -124,7 +157,7 @@ __vsc_update_cwd() {
__vsc_command_output_start() {
builtin printf '\e]633;C\a'
- builtin printf '\e]633;E;%s\a' "$(__vsc_escape_value "${__vsc_current_command}")"
+ builtin printf '\e]633;E;%s;%s\a' "$(__vsc_escape_value "${__vsc_current_command}")" $__vsc_nonce
}
__vsc_continuation_start() {
@@ -241,10 +274,10 @@ __vsc_prompt_cmd() {
# PROMPT_COMMAND arrays and strings seem to be handled the same (handling only the first entry of
# the array?)
-__vsc_original_prompt_command=$PROMPT_COMMAND
+__vsc_original_prompt_command=${PROMPT_COMMAND:-}
if [[ -z "${bash_preexec_imported:-}" ]]; then
- if [[ -n "$__vsc_original_prompt_command" && "$__vsc_original_prompt_command" != "__vsc_prompt_cmd" ]]; then
+ if [[ -n "${__vsc_original_prompt_command:-}" && "${__vsc_original_prompt_command:-}" != "__vsc_prompt_cmd" ]]; then
PROMPT_COMMAND=__vsc_prompt_cmd_original
else
PROMPT_COMMAND=__vsc_prompt_cmd
diff --git a/src/plugins/terminal/shellintegrations/shellintegration-rc.zsh b/src/plugins/terminal/shellintegrations/shellintegration-rc.zsh
index df4109131a9..119c85be9e0 100644
--- a/src/plugins/terminal/shellintegrations/shellintegration-rc.zsh
+++ b/src/plugins/terminal/shellintegrations/shellintegration-rc.zsh
@@ -37,6 +37,32 @@ if [ -z "$VSCODE_SHELL_INTEGRATION" ]; then
builtin return
fi
+# Apply EnvironmentVariableCollections if needed
+if [ -n "${VSCODE_ENV_REPLACE:-}" ]; then
+ IFS=':' read -rA ADDR <<< "$VSCODE_ENV_REPLACE"
+ for ITEM in "${ADDR[@]}"; do
+ VARNAME="$(echo ${ITEM%%=*})"
+ export $VARNAME="$(echo -e ${ITEM#*=})"
+ done
+ unset VSCODE_ENV_REPLACE
+fi
+if [ -n "${VSCODE_ENV_PREPEND:-}" ]; then
+ IFS=':' read -rA ADDR <<< "$VSCODE_ENV_PREPEND"
+ for ITEM in "${ADDR[@]}"; do
+ VARNAME="$(echo ${ITEM%%=*})"
+ export $VARNAME="$(echo -e ${ITEM#*=})${(P)VARNAME}"
+ done
+ unset VSCODE_ENV_PREPEND
+fi
+if [ -n "${VSCODE_ENV_APPEND:-}" ]; then
+ IFS=':' read -rA ADDR <<< "$VSCODE_ENV_APPEND"
+ for ITEM in "${ADDR[@]}"; do
+ VARNAME="$(echo ${ITEM%%=*})"
+ export $VARNAME="${(P)VARNAME}$(echo -e ${ITEM#*=})"
+ done
+ unset VSCODE_ENV_APPEND
+fi
+
# The property (P) and command (E) codes embed values which require escaping.
# Backslashes are doubled. Non-alphanumeric characters are converted to escaped hex.
__vsc_escape_value() {
@@ -66,6 +92,10 @@ __vsc_escape_value() {
__vsc_in_command_execution="1"
__vsc_current_command=""
+# It's fine this is in the global scope as it getting at it requires access to the shell environment
+__vsc_nonce="$VSCODE_NONCE"
+unset VSCODE_NONCE
+
__vsc_prompt_start() {
builtin printf '\e]633;A\a'
}
@@ -80,7 +110,7 @@ __vsc_update_cwd() {
__vsc_command_output_start() {
builtin printf '\e]633;C\a'
- builtin printf '\e]633;E;%s\a' "${__vsc_current_command}"
+ builtin printf '\e]633;E;%s;%s\a' "$(__vsc_escape_value "${__vsc_current_command}")" $__vsc_nonce
}
__vsc_continuation_start() {
@@ -149,6 +179,7 @@ __vsc_preexec() {
RPROMPT="$__vsc_prior_rprompt"
fi
__vsc_in_command_execution="1"
+ # For some reason Qt Creator needs this to be $2 instead of $1
__vsc_current_command=$2
__vsc_command_output_start
}
diff --git a/src/plugins/terminal/shellintegrations/shellintegration.fish b/src/plugins/terminal/shellintegrations/shellintegration.fish
index 7495bab3f40..21cc823c480 100644
--- a/src/plugins/terminal/shellintegrations/shellintegration.fish
+++ b/src/plugins/terminal/shellintegrations/shellintegration.fish
@@ -26,16 +26,48 @@ if status --is-login; and set -q VSCODE_PATH_PREFIX
end
set -e VSCODE_PATH_PREFIX
+# Apply EnvironmentVariableCollections if needed
+if test -n "$VSCODE_ENV_REPLACE"
+ set ITEMS (string split : $VSCODE_ENV_REPLACE)
+ for B in $ITEMS
+ set split (string split = $B)
+ set -gx "$split[1]" (echo -e "$split[2]")
+ end
+ set -e VSCODE_ENV_REPLACE
+end
+if test -n "$VSCODE_ENV_PREPEND"
+ set ITEMS (string split : $VSCODE_ENV_PREPEND)
+ for B in $ITEMS
+ set split (string split = $B)
+ set -gx "$split[1]" (echo -e "$split[2]")"$$split[1]" # avoid -p as it adds a space
+ end
+ set -e VSCODE_ENV_PREPEND
+end
+if test -n "$VSCODE_ENV_APPEND"
+ set ITEMS (string split : $VSCODE_ENV_APPEND)
+ for B in $ITEMS
+ set split (string split = $B)
+ set -gx "$split[1]" "$$split[1]"(echo -e "$split[2]") # avoid -a as it adds a space
+ end
+ set -e VSCODE_ENV_APPEND
+end
+
+# Handle the shell integration nonce
+if set -q VSCODE_NONCE
+ set -l __vsc_nonce $VSCODE_NONCE
+ set -e VSCODE_NONCE
+end
+
# Helper function
function __vsc_esc -d "Emit escape sequences for VS Code shell integration"
- builtin printf "\e]633;%s\a" (string join ";" $argv)
+ builtin printf "\e]633;%s\a" (string join ";" -- $argv)
end
# Sent right before executing an interactive command.
# Marks the beginning of command output.
function __vsc_cmd_executed --on-event fish_preexec
__vsc_esc C
- __vsc_esc E (__vsc_escape_value "$argv")
+ __vsc_esc E (__vsc_escape_value "$argv") $__vsc_nonce
# Creates a marker to indicate a command was run.
set --global _vsc_has_cmd
@@ -64,6 +96,31 @@ function __vsc_cmd_clear --on-event fish_cancel
__vsc_esc D
end
+# Preserve the user's existing prompt, to wrap in our escape sequences.
+function __preserve_fish_prompt --on-event fish_prompt
+ if functions --query fish_prompt
+ if functions --query __vsc_fish_prompt
+ # Erase the fallback so it can be set to the user's prompt
+ functions --erase __vsc_fish_prompt
+ end
+ functions --copy fish_prompt __vsc_fish_prompt
+ functions --erase __preserve_fish_prompt
+ # Now __vsc_fish_prompt is guaranteed to be defined
+ __init_vscode_shell_integration
+ else
+ if functions --query __vsc_fish_prompt
+ functions --erase __preserve_fish_prompt
+ __init_vscode_shell_integration
+ else
+ # There is no fish_prompt set, so stick with the default
+ # Now __vsc_fish_prompt is guaranteed to be defined
+ function __vsc_fish_prompt
+ echo -n (whoami)@(prompt_hostname) (prompt_pwd) '~> '
+ end
+ end
+ end
+end
+
# Sent whenever a new fish prompt is about to be displayed.
# Updates the current working directory.
function __vsc_update_cwd --on-event fish_prompt
@@ -94,29 +151,29 @@ function __vsc_fish_has_mode_prompt -d "Returns true if fish_mode_prompt is defi
functions fish_mode_prompt | string match -rvq '^ *(#|function |end$|$)'
end
-# Preserve the user's existing prompt, to wrap in our escape sequences.
-functions --copy fish_prompt __vsc_fish_prompt
-
# Preserve and wrap fish_mode_prompt (which appears to the left of the regular
# prompt), but only if it's not defined as an empty function (which is the
# officially documented way to disable that feature).
-if __vsc_fish_has_mode_prompt
- functions --copy fish_mode_prompt __vsc_fish_mode_prompt
-
- function fish_mode_prompt
- __vsc_fish_prompt_start
- __vsc_fish_mode_prompt
- end
-
- function fish_prompt
- __vsc_fish_prompt
- __vsc_fish_cmd_start
- end
-else
- # No fish_mode_prompt, so put everything in fish_prompt.
- function fish_prompt
- __vsc_fish_prompt_start
- __vsc_fish_prompt
- __vsc_fish_cmd_start
+function __init_vscode_shell_integration
+ if __vsc_fish_has_mode_prompt
+ functions --copy fish_mode_prompt __vsc_fish_mode_prompt
+
+ function fish_mode_prompt
+ __vsc_fish_prompt_start
+ __vsc_fish_mode_prompt
+ __vsc_fish_cmd_start
+ end
+
+ function fish_prompt
+ __vsc_fish_prompt
+ end
+ else
+ # No fish_mode_prompt, so put everything in fish_prompt.
+ function fish_prompt
+ __vsc_fish_prompt_start
+ __vsc_fish_prompt
+ __vsc_fish_cmd_start
+ end
end
end
+__preserve_fish_prompt
diff --git a/src/plugins/terminal/shellintegrations/shellintegration.ps1 b/src/plugins/terminal/shellintegrations/shellintegration.ps1
index 4fd978a8844..e277724b0a2 100644
--- a/src/plugins/terminal/shellintegrations/shellintegration.ps1
+++ b/src/plugins/terminal/shellintegrations/shellintegration.ps1
@@ -15,6 +15,35 @@ $Global:__VSCodeOriginalPrompt = $function:Prompt
$Global:__LastHistoryId = -1
+# Store the nonce in script scope and unset the global
+$Nonce = $env:VSCODE_NONCE
+$env:VSCODE_NONCE = $null
+
+if ($env:VSCODE_ENV_REPLACE) {
+ $Split = $env:VSCODE_ENV_REPLACE.Split(":")
+ foreach ($Item in $Split) {
+ $Inner = $Item.Split('=')
+ [Environment]::SetEnvironmentVariable($Inner[0], $Inner[1].Replace('\x3a', ':'))
+ }
+ $env:VSCODE_ENV_REPLACE = $null
+}
+if ($env:VSCODE_ENV_PREPEND) {
+ $Split = $env:VSCODE_ENV_PREPEND.Split(":")
+ foreach ($Item in $Split) {
+ $Inner = $Item.Split('=')
+ [Environment]::SetEnvironmentVariable($Inner[0], $Inner[1].Replace('\x3a', ':') + [Environment]::GetEnvironmentVariable($Inner[0]))
+ }
+ $env:VSCODE_ENV_PREPEND = $null
+}
+if ($env:VSCODE_ENV_APPEND) {
+ $Split = $env:VSCODE_ENV_APPEND.Split(":")
+ foreach ($Item in $Split) {
+ $Inner = $Item.Split('=')
+ [Environment]::SetEnvironmentVariable($Inner[0], [Environment]::GetEnvironmentVariable($Inner[0]) + $Inner[1].Replace('\x3a', ':'))
+ }
+ $env:VSCODE_ENV_APPEND = $null
+}
+
function Global:__VSCode-Escape-Value([string]$value) {
# NOTE: In PowerShell v6.1+, this can be written `$value -replace '…', { … }` instead of `[regex]::Replace`.
# Replace any non-alphanumeric characters.
@@ -40,7 +69,7 @@ function Global:Prompt() {
$Result += "$([char]0x1b)]633;D`a"
} else {
# Command finished command line
- # OSC 633 ; A ; <CommandLine?> ST
+ # OSC 633 ; E ; <CommandLine?> ; <Nonce?> ST
$Result = "$([char]0x1b)]633;E;"
# Sanitize the command line to ensure it can get transferred to the terminal and can be parsed
# correctly. This isn't entirely safe but good for most cases, it's important for the Pt parameter
@@ -51,6 +80,7 @@ function Global:Prompt() {
$CommandLine = ""
}
$Result += $(__VSCode-Escape-Value $CommandLine)
+ $Result += ";$Nonce"
$Result += "`a"
# Command finished exit code
# OSC 633 ; D [; <ExitCode>] ST
@@ -88,7 +118,12 @@ if (Get-Module -Name PSReadLine) {
}
# Set IsWindows property
-[Console]::Write("$([char]0x1b)]633;P;IsWindows=$($IsWindows)`a")
+if ($PSVersionTable.PSVersion -lt "6.0") {
+ # Windows PowerShell is only available on Windows
+ [Console]::Write("$([char]0x1b)]633;P;IsWindows=$true`a")
+} else {
+ [Console]::Write("$([char]0x1b)]633;P;IsWindows=$IsWindows`a")
+}
# Set always on key handlers which map to default VS Code keybindings
function Set-MappedKeyHandler {