Initial commit, 90% there

This commit is contained in:
mdares
2025-12-02 16:27:21 +00:00
commit 755028af7e
7353 changed files with 1759505 additions and 0 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,64 @@
#!/bin/bash
function get_total_cpu_time() {
# Read the first line of /proc/stat and remove the cpu prefix
CPU=(`sed -n 's/^cpu\s//p' /proc/stat`)
# Sum all of the values in CPU to get total time
for VALUE in "${CPU[@]}"; do
let $1=$1+$VALUE
done
}
TOTAL_TIME_BEFORE=0
get_total_cpu_time TOTAL_TIME_BEFORE
# Loop over the arguments, which are a list of PIDs
# The 13th and 14th words in /proc/<PID>/stat are the user and system time
# the process has used, so sum these to get total process run time
declare -a PROCESS_BEFORE_TIMES
ITER=0
for PID in "$@"; do
if [ -f /proc/$PID/stat ]
then
PROCESS_STATS=`cat /proc/$PID/stat`
PROCESS_STAT_ARRAY=($PROCESS_STATS)
let PROCESS_TIME_BEFORE="${PROCESS_STAT_ARRAY[13]}+${PROCESS_STAT_ARRAY[14]}"
else
let PROCESS_TIME_BEFORE=0
fi
PROCESS_BEFORE_TIMES[$ITER]=$PROCESS_TIME_BEFORE
((++ITER))
done
# Wait for a second
sleep 1
TOTAL_TIME_AFTER=0
get_total_cpu_time TOTAL_TIME_AFTER
# Check the user and system time sum of each process again and compute the change
# in process time used over total system time
ITER=0
for PID in "$@"; do
if [ -f /proc/$PID/stat ]
then
PROCESS_STATS=`cat /proc/$PID/stat`
PROCESS_STAT_ARRAY=($PROCESS_STATS)
let PROCESS_TIME_AFTER="${PROCESS_STAT_ARRAY[13]}+${PROCESS_STAT_ARRAY[14]}"
else
let PROCESS_TIME_AFTER=${PROCESS_BEFORE_TIMES[$ITER]}
fi
PROCESS_TIME_BEFORE=${PROCESS_BEFORE_TIMES[$ITER]}
let PROCESS_DELTA=$PROCESS_TIME_AFTER-$PROCESS_TIME_BEFORE
let TOTAL_DELTA=$TOTAL_TIME_AFTER-$TOTAL_TIME_BEFORE
CPU_USAGE=`echo "$((100*$PROCESS_DELTA/$TOTAL_DELTA))"`
# Parent script reads from stdout, so echo result to be read
echo $CPU_USAGE
((++ITER))
done

View File

@@ -0,0 +1,39 @@
#!/bin/sh
PAGESIZE=`getconf PAGESIZE`;
TOTAL_MEMORY=`cat /proc/meminfo | head -n 1 | awk '{print $2}'`;
# Mimic the output of ps -ax -o pid=,ppid=,pcpu=,pmem=,command=
# Read all numeric subdirectories in /proc
for pid in `cd /proc && ls -d [0-9]*`
do {
if [ -e /proc/$pid/stat ]
then
echo $pid;
# ppid is the word at index 4 in the stat file for the process
awk '{print $4}' /proc/$pid/stat;
# pcpu - calculation will be done later, this is a placeholder value
echo "0.0"
# pmem - ratio of the process's working set size to total memory.
# use the page size to convert to bytes, total memory is in KB
# multiplied by 100 to get percentage, extra 10 to be able to move
# the decimal over by one place
RESIDENT_SET_SIZE=`awk '{print $24}' /proc/$pid/stat`;
PERCENT_MEMORY=$(((1000 * $PAGESIZE * $RESIDENT_SET_SIZE) / ($TOTAL_MEMORY * 1024)));
if [ $PERCENT_MEMORY -lt 10 ]
then
# replace the last character with 0. the last character
echo $PERCENT_MEMORY | sed 's/.$/0.&/'; #pmem
else
# insert . before the last character
echo $PERCENT_MEMORY | sed 's/.$/.&/';
fi
# cmdline
xargs -0 < /proc/$pid/cmdline;
fi
} | tr "\n" "\t"; # Replace newlines with tab so that all info for a process is shown on one line
echo; # But add new lines between processes
done

View File

@@ -0,0 +1,478 @@
# ---------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# ---------------------------------------------------------------------------------------------
# Prevent the script recursing when setting up
if [[ -n "${VSCODE_SHELL_INTEGRATION:-}" ]]; then
builtin return
fi
VSCODE_SHELL_INTEGRATION=1
vsc_env_keys=()
vsc_env_values=()
use_associative_array=0
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+
declare -A vsc_aa_env
fi
# Run relevant rc/profile only if shell integration has been injected, not when run manually
if [ "$VSCODE_INJECTION" == "1" ]; then
if [ -z "$VSCODE_SHELL_LOGIN" ]; then
if [ -r ~/.bashrc ]; then
. ~/.bashrc
fi
else
# Imitate -l because --init-file doesn't support it:
# run the first of these files that exists
if [ -r /etc/profile ]; then
. /etc/profile
fi
# execute the first that exists
if [ -r ~/.bash_profile ]; then
. ~/.bash_profile
elif [ -r ~/.bash_login ]; then
. ~/.bash_login
elif [ -r ~/.profile ]; then
. ~/.profile
fi
builtin unset VSCODE_SHELL_LOGIN
# Apply any explicit path prefix (see #99878)
if [ -n "${VSCODE_PATH_PREFIX:-}" ]; then
export PATH="$VSCODE_PATH_PREFIX$PATH"
builtin unset VSCODE_PATH_PREFIX
fi
fi
builtin unset VSCODE_INJECTION
fi
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
# Register Python shell activate hooks
# Prevent multiple activation with guard
if [ -z "${VSCODE_PYTHON_AUTOACTIVATE_GUARD:-}" ]; then
export VSCODE_PYTHON_AUTOACTIVATE_GUARD=1
if [ -n "${VSCODE_PYTHON_BASH_ACTIVATE:-}" ] && [ "$TERM_PROGRAM" = "vscode" ]; then
# Prevent crashing by negating exit code
if ! builtin eval "$VSCODE_PYTHON_BASH_ACTIVATE"; then
__vsc_activation_status=$?
builtin printf '\x1b[0m\x1b[7m * \x1b[0;103m VS Code Python bash activation failed with exit code %d \x1b[0m' "$__vsc_activation_status"
fi
fi
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.
# (Consider a trap like $'echo foo\necho \'bar\'').
# To parse, we splice those terms into an expression capturing them into an array.
# This preserves the quoting of those terms: when we `eval` that expression, they are preserved exactly.
# This is different than simply exploding the string, which would split everything on IFS, oblivious to quoting.
builtin local -a terms
builtin eval "terms=( $(trap -p "${1:-DEBUG}") )"
# |________________________|
# |
# \-------------------*--------------------/
# terms=( trap -- '…arbitrary shellcode…' DEBUG )
# |____||__| |_____________________| |_____|
# | | | |
# 0 1 2 3
# |
# \--------*----/
builtin printf '%s' "${terms[2]:-}"
}
__vsc_escape_value_fast() {
builtin local LC_ALL=C out
out=${1//\\/\\\\}
out=${out//;/\\x3b}
builtin printf '%s\n' "${out}"
}
# 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() {
# If the input being too large, switch to the faster function
if [ "${#1}" -ge 2000 ]; then
__vsc_escape_value_fast "$1"
builtin return
fi
# Process text byte by byte, not by codepoint.
builtin local -r LC_ALL=C
builtin local -r str="${1}"
builtin local -ir len="${#str}"
builtin local -i i
builtin local -i val
builtin local byte
builtin local token
builtin local out=''
for (( i=0; i < "${#str}"; ++i )); do
# Escape backslashes, semi-colons specially, then special ASCII chars below space (0x20).
byte="${str:$i:1}"
builtin printf -v val '%d' "'$byte"
if (( val < 31 )); then
builtin printf -v token '\\x%02x' "'$byte"
elif (( val == 92 )); then # \
token="\\\\"
elif (( val == 59 )); then # ;
token="\\x3b"
else
token="$byte"
fi
out+="$token"
done
builtin printf '%s\n' "$out"
}
# Send the IsWindows property if the environment looks like Windows
__vsc_regex_environment="^CYGWIN*|MINGW*|MSYS*"
if [[ "$(uname -s)" =~ $__vsc_regex_environment ]]; then
builtin printf '\e]633;P;IsWindows=True\a'
__vsc_is_windows=1
else
__vsc_is_windows=0
fi
# Allow verifying $BASH_COMMAND doesn't have aliases resolved via history when the right HISTCONTROL
# configuration is used
__vsc_regex_histcontrol=".*(erasedups|ignoreboth|ignoredups).*"
if [[ "${HISTCONTROL:-}" =~ $__vsc_regex_histcontrol ]]; then
__vsc_history_verify=0
else
__vsc_history_verify=1
fi
builtin unset __vsc_regex_environment
builtin unset __vsc_regex_histcontrol
__vsc_initialized=0
__vsc_original_PS1="$PS1"
__vsc_original_PS2="$PS2"
__vsc_custom_PS1=""
__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
# Some features should only work in Insiders
__vsc_stable="$VSCODE_STABLE"
unset VSCODE_STABLE
# Report continuation prompt
if [ "$__vsc_stable" = "0" ]; then
builtin printf "\e]633;P;ContinuationPrompt=$(echo "$PS2" | sed 's/\x1b/\\\\x1b/g')\a"
fi
if [ -n "$STARSHIP_SESSION_KEY" ]; then
builtin printf '\e]633;P;PromptType=starship\a'
elif [ -n "$POSH_SESSION_ID" ]; then
builtin printf '\e]633;P;PromptType=oh-my-posh\a'
fi
# Report this shell supports rich command detection
builtin printf '\e]633;P;HasRichCommandDetection=True\a'
__vsc_report_prompt() {
# Expand the original PS1 similarly to how bash would normally
# See https://stackoverflow.com/a/37137981 for technique
if ((BASH_VERSINFO[0] >= 5 || (BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 4))); then
__vsc_prompt=${__vsc_original_PS1@P}
else
__vsc_prompt=${__vsc_original_PS1}
fi
__vsc_prompt="$(builtin printf "%s" "${__vsc_prompt//[$'\001'$'\002']}")"
builtin printf "\e]633;P;Prompt=%s\a" "$(__vsc_escape_value "${__vsc_prompt}")"
}
__vsc_prompt_start() {
builtin printf '\e]633;A\a'
}
__vsc_prompt_end() {
builtin printf '\e]633;B\a'
}
__vsc_update_cwd() {
if [ "$__vsc_is_windows" = "1" ]; then
__vsc_cwd="$(cygpath -m "$PWD")"
else
__vsc_cwd="$PWD"
fi
builtin printf '\e]633;P;Cwd=%s\a' "$(__vsc_escape_value "$__vsc_cwd")"
}
__updateEnvCacheAA() {
local key="$1"
local value="$2"
if [ "$use_associative_array" = 1 ]; then
if [[ "${vsc_aa_env[$key]}" != "$value" ]]; then
vsc_aa_env["$key"]="$value"
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
fi
fi
}
__updateEnvCache() {
local key="$1"
local value="$2"
for i in "${!vsc_env_keys[@]}"; do
if [[ "${vsc_env_keys[$i]}" == "$key" ]]; then
if [[ "${vsc_env_values[$i]}" != "$value" ]]; then
vsc_env_values[$i]="$value"
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
fi
return
fi
done
vsc_env_keys+=("$key")
vsc_env_values+=("$value")
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
}
__vsc_update_env() {
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
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
else
# Diff approach for associative array
for key in "${envVarsToReport[@]}"; do
if [ -n "${!key+x}" ]; then
local value="${!key}"
__updateEnvCacheAA "$key" "$value"
fi
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
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
else
# Diff approach for non-associative arrays
for key in "${envVarsToReport[@]}"; do
if [ -n "${!key+x}" ]; then
local value="${!key}"
__updateEnvCache "$key" "$value"
fi
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
fi
}
__vsc_command_output_start() {
if [[ -z "${__vsc_first_prompt-}" ]]; then
builtin return
fi
builtin printf '\e]633;E;%s;%s\a' "$(__vsc_escape_value "${__vsc_current_command}")" $__vsc_nonce
builtin printf '\e]633;C\a'
}
__vsc_continuation_start() {
builtin printf '\e]633;F\a'
}
__vsc_continuation_end() {
builtin printf '\e]633;G\a'
}
__vsc_command_complete() {
if [[ -z "${__vsc_first_prompt-}" ]]; then
__vsc_update_cwd
builtin return
fi
if [ "$__vsc_current_command" = "" ]; then
builtin printf '\e]633;D\a'
else
builtin printf '\e]633;D;%s\a' "$__vsc_status"
fi
__vsc_update_cwd
}
__vsc_update_prompt() {
# in command execution
if [ "$__vsc_in_command_execution" = "1" ]; then
# Wrap the prompt if it is not yet wrapped, if the PS1 changed this this was last set it
# means the user re-exported the PS1 so we should re-wrap it
if [[ "$__vsc_custom_PS1" == "" || "$__vsc_custom_PS1" != "$PS1" ]]; then
__vsc_original_PS1=$PS1
__vsc_custom_PS1="\[$(__vsc_prompt_start)\]$__vsc_original_PS1\[$(__vsc_prompt_end)\]"
PS1="$__vsc_custom_PS1"
fi
if [[ "$__vsc_custom_PS2" == "" || "$__vsc_custom_PS2" != "$PS2" ]]; then
__vsc_original_PS2=$PS2
__vsc_custom_PS2="\[$(__vsc_continuation_start)\]$__vsc_original_PS2\[$(__vsc_continuation_end)\]"
PS2="$__vsc_custom_PS2"
fi
__vsc_in_command_execution="0"
fi
}
__vsc_precmd() {
__vsc_command_complete "$__vsc_status"
__vsc_current_command=""
# Report prompt is a work in progress, currently encoding is too slow
if [ "$__vsc_stable" = "0" ]; then
__vsc_report_prompt
fi
__vsc_first_prompt=1
__vsc_update_prompt
__vsc_update_env
}
__vsc_preexec() {
__vsc_initialized=1
if [[ ! $BASH_COMMAND == __vsc_prompt* ]]; then
# Use history if it's available to verify the command as BASH_COMMAND comes in with aliases
# resolved
if [ "$__vsc_history_verify" = "1" ]; then
__vsc_current_command="$(builtin history 1 | sed 's/ *[0-9]* *//')"
else
__vsc_current_command=$BASH_COMMAND
fi
else
__vsc_current_command=""
fi
__vsc_command_output_start
}
# Debug trapping/preexec inspired by starship (ISC)
if [[ -n "${bash_preexec_imported:-}" ]]; then
__vsc_preexec_only() {
if [ "$__vsc_in_command_execution" = "0" ]; then
__vsc_in_command_execution="1"
__vsc_preexec
fi
}
precmd_functions+=(__vsc_prompt_cmd)
preexec_functions+=(__vsc_preexec_only)
else
__vsc_dbg_trap="$(__vsc_get_trap DEBUG)"
if [[ -z "$__vsc_dbg_trap" ]]; then
__vsc_preexec_only() {
if [ "$__vsc_in_command_execution" = "0" ]; then
__vsc_in_command_execution="1"
__vsc_preexec
fi
}
trap '__vsc_preexec_only "$_"' DEBUG
elif [[ "$__vsc_dbg_trap" != '__vsc_preexec "$_"' && "$__vsc_dbg_trap" != '__vsc_preexec_all "$_"' ]]; then
__vsc_preexec_all() {
if [ "$__vsc_in_command_execution" = "0" ]; then
__vsc_in_command_execution="1"
__vsc_preexec
builtin eval "${__vsc_dbg_trap}"
fi
}
trap '__vsc_preexec_all "$_"' DEBUG
fi
fi
__vsc_update_prompt
__vsc_restore_exit_code() {
return "$1"
}
__vsc_prompt_cmd_original() {
__vsc_status="$?"
builtin local cmd
__vsc_restore_exit_code "${__vsc_status}"
# Evaluate the original PROMPT_COMMAND similarly to how bash would normally
# See https://unix.stackexchange.com/a/672843 for technique
for cmd in "${__vsc_original_prompt_command[@]}"; do
eval "${cmd:-}"
done
__vsc_precmd
}
__vsc_prompt_cmd() {
__vsc_status="$?"
__vsc_precmd
}
# 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:-}
if [[ -z "${bash_preexec_imported:-}" ]]; 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
fi
fi

View File

@@ -0,0 +1,16 @@
# ---------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# ---------------------------------------------------------------------------------------------
if [[ -f $USER_ZDOTDIR/.zshenv ]]; then
VSCODE_ZDOTDIR=$ZDOTDIR
ZDOTDIR=$USER_ZDOTDIR
# prevent recursion
if [[ $USER_ZDOTDIR != $VSCODE_ZDOTDIR ]]; then
. $USER_ZDOTDIR/.zshenv
fi
USER_ZDOTDIR=$ZDOTDIR
ZDOTDIR=$VSCODE_ZDOTDIR
fi

View File

@@ -0,0 +1,15 @@
# ---------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# ---------------------------------------------------------------------------------------------
# Prevent recursive sourcing
if [[ -n "$VSCODE_LOGIN_INITIALIZED" ]]; then
return
fi
export VSCODE_LOGIN_INITIALIZED=1
ZDOTDIR=$USER_ZDOTDIR
if [[ $options[norcs] = off && -o "login" && -f $ZDOTDIR/.zlogin ]]; then
. $ZDOTDIR/.zlogin
fi

View File

@@ -0,0 +1,25 @@
# ---------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# ---------------------------------------------------------------------------------------------
# Prevent recursive sourcing
if [[ -n "$VSCODE_PROFILE_INITIALIZED" ]]; then
return
fi
export VSCODE_PROFILE_INITIALIZED=1
if [[ $options[norcs] = off && -o "login" ]]; then
if [[ -f $USER_ZDOTDIR/.zprofile ]]; then
VSCODE_ZDOTDIR=$ZDOTDIR
ZDOTDIR=$USER_ZDOTDIR
. $USER_ZDOTDIR/.zprofile
ZDOTDIR=$VSCODE_ZDOTDIR
fi
# Apply any explicit path prefix (see #99878)
if (( ${+VSCODE_PATH_PREFIX} )); then
export PATH="$VSCODE_PATH_PREFIX$PATH"
fi
builtin unset VSCODE_PATH_PREFIX
fi

View File

@@ -0,0 +1,321 @@
# ---------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# ---------------------------------------------------------------------------------------------
builtin autoload -Uz add-zsh-hook is-at-least
# Prevent the script recursing when setting up
if [ -n "$VSCODE_SHELL_INTEGRATION" ]; then
ZDOTDIR=$USER_ZDOTDIR
builtin return
fi
# This variable allows the shell to both detect that VS Code's shell integration is enabled as well
# as disable it by unsetting the variable.
VSCODE_SHELL_INTEGRATION=1
# By default, zsh will set the $HISTFILE to the $ZDOTDIR location automatically. In the case of the
# shell integration being injected, this means that the terminal will use a different history file
# to other terminals. To fix this issue, set $HISTFILE back to the default location before ~/.zshrc
# is called as that may depend upon the value.
if [[ "$VSCODE_INJECTION" == "1" ]]; then
HISTFILE=$USER_ZDOTDIR/.zsh_history
fi
# Only fix up ZDOTDIR if shell integration was injected (not manually installed) and has not been called yet
if [[ "$VSCODE_INJECTION" == "1" ]]; then
if [[ $options[norcs] = off && -f $USER_ZDOTDIR/.zshrc ]]; then
VSCODE_ZDOTDIR=$ZDOTDIR
ZDOTDIR=$USER_ZDOTDIR
# A user's custom HISTFILE location might be set when their .zshrc file is sourced below
. $USER_ZDOTDIR/.zshrc
fi
fi
__vsc_use_aa=0
__vsc_env_keys=()
__vsc_env_values=()
# Associative array are only available in zsh 4.3 or later
if is-at-least 4.3; then
__vsc_use_aa=1
typeset -A vsc_aa_env
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
# Register Python shell activate hooks
# Prevent multiple activation with guard
if [ -z "${VSCODE_PYTHON_AUTOACTIVATE_GUARD:-}" ]; then
export VSCODE_PYTHON_AUTOACTIVATE_GUARD=1
if [ -n "${VSCODE_PYTHON_ZSH_ACTIVATE:-}" ] && [ "$TERM_PROGRAM" = "vscode" ]; then
# Prevent crashing by negating exit code
if ! builtin eval "$VSCODE_PYTHON_ZSH_ACTIVATE"; then
__vsc_activation_status=$?
builtin printf '\x1b[0m\x1b[7m * \x1b[0;103m VS Code Python zsh activation failed with exit code %d \x1b[0m' "$__vsc_activation_status"
fi
fi
fi
# Report prompt type
if [ -n "${P9K_SSH:-}" ] || [ -n "${P9K_TTY:-}" ]; then
builtin printf '\e]633;P;PromptType=p10k\a'
# Force shell integration on for p10k
# typeset -g POWERLEVEL9K_TERM_SHELL_INTEGRATION=true
elif [ -n "${ZSH:-}" ] && [ -n "$ZSH_VERSION" ] && (( ${+functions[omz]} )); then
builtin printf '\e]633;P;PromptType=oh-my-zsh\a'
elif [ -n "${STARSHIP_SESSION_KEY:-}" ]; then
builtin printf '\e]633;P;PromptType=starship\a'
fi
# Shell integration was disabled by the shell, exit without warning assuming either the shell has
# explicitly disabled shell integration as it's incompatible or it implements the protocol.
if [ -z "$VSCODE_SHELL_INTEGRATION" ]; then
builtin return
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() {
builtin emulate -L zsh
# Process text byte by byte, not by codepoint.
builtin local LC_ALL=C str="$1" i byte token out='' val
for (( i = 0; i < ${#str}; ++i )); do
# Escape backslashes, semi-colons specially, then special ASCII chars below space (0x20).
byte="${str:$i:1}"
val=$(printf "%d" "'$byte")
if (( val < 31 )); then
# For control characters, use hex encoding
token=$(printf "\\\\x%02x" "'$byte")
elif [ "$byte" = "\\" ]; then
token="\\\\"
elif [ "$byte" = ";" ]; then
token="\\x3b"
else
token="$byte"
fi
out+="$token"
done
builtin print -r -- "$out"
}
__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
__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 this shell supports rich command detection
builtin printf '\e]633;P;HasRichCommandDetection=True\a'
__vsc_prompt_start() {
builtin printf '\e]633;A\a'
}
__vsc_prompt_end() {
builtin printf '\e]633;B\a'
}
__vsc_update_cwd() {
builtin printf '\e]633;P;Cwd=%s\a' "$(__vsc_escape_value "${PWD}")"
}
__update_env_cache_aa() {
local key="$1"
local value="$2"
if [ $__vsc_use_aa -eq 1 ]; then
if [[ "${vsc_aa_env["$key"]}" != "$value" ]]; then
vsc_aa_env["$key"]="$value"
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
fi
fi
}
__update_env_cache() {
local key="$1"
local value="$2"
for (( i=1; i <= $#__vsc_env_keys; i++ )); do
if [[ "${__vsc_env_keys[$i]}" == "$key" ]]; then
if [[ "${__vsc_env_values[$i]}" != "$value" ]]; then
__vsc_env_values[$i]="$value"
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
fi
return
fi
done
# Key does not exist so add key, value pair
__vsc_env_keys+=("$key")
__vsc_env_values+=("$value")
builtin printf '\e]633;EnvSingleEntry;%s;%s;%s\a' "$key" "$(__vsc_escape_value "$value")" "$__vsc_nonce"
}
__vsc_update_env() {
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
for key in "${envVarsToReport[@]}"; do
if [[ -n "$key" && -n "${(P)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
for var in "${envVarsToReport[@]}"; do
if [[ -n "$var" && -n "${(P)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
for key in "${envVarsToReport[@]}"; do
if [[ -n "$key" && -n "${(P)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
for var in "${envVarsToReport[@]}"; do
if [[ -n "$var" && -n "${(P)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
builtin printf '\e]633;EnvSingleEnd;%s;\a' $__vsc_nonce
fi
}
__vsc_command_output_start() {
builtin printf '\e]633;E;%s;%s\a' "$(__vsc_escape_value "${__vsc_current_command}")" $__vsc_nonce
builtin printf '\e]633;C\a'
}
__vsc_continuation_start() {
builtin printf '\e]633;F\a'
}
__vsc_continuation_end() {
builtin printf '\e]633;G\a'
}
__vsc_right_prompt_start() {
builtin printf '\e]633;H\a'
}
__vsc_right_prompt_end() {
builtin printf '\e]633;I\a'
}
__vsc_command_complete() {
if [[ "$__vsc_current_command" == "" ]]; then
builtin printf '\e]633;D\a'
else
builtin printf '\e]633;D;%s\a' "$__vsc_status"
fi
__vsc_update_cwd
}
if [[ -o NOUNSET ]]; then
if [ -z "${RPROMPT-}" ]; then
RPROMPT=""
fi
fi
__vsc_update_prompt() {
__vsc_prior_prompt="$PS1"
__vsc_prior_prompt2="$PS2"
__vsc_in_command_execution=""
PS1="%{$(__vsc_prompt_start)%}$PS1%{$(__vsc_prompt_end)%}"
PS2="%{$(__vsc_continuation_start)%}$PS2%{$(__vsc_continuation_end)%}"
if [ -n "$RPROMPT" ]; then
__vsc_prior_rprompt="$RPROMPT"
RPROMPT="%{$(__vsc_right_prompt_start)%}$RPROMPT%{$(__vsc_right_prompt_end)%}"
fi
}
__vsc_precmd() {
builtin local __vsc_status="$?"
if [ -z "${__vsc_in_command_execution-}" ]; then
# not in command execution
__vsc_command_output_start
fi
__vsc_command_complete "$__vsc_status"
__vsc_current_command=""
# in command execution
if [ -n "$__vsc_in_command_execution" ]; then
# non null
__vsc_update_prompt
fi
__vsc_update_env
}
__vsc_preexec() {
PS1="$__vsc_prior_prompt"
PS2="$__vsc_prior_prompt2"
if [ -n "$RPROMPT" ]; then
RPROMPT="$__vsc_prior_rprompt"
fi
__vsc_in_command_execution="1"
__vsc_current_command=$1
__vsc_command_output_start
}
add-zsh-hook precmd __vsc_precmd
add-zsh-hook preexec __vsc_preexec
if [[ $options[login] = off && $USER_ZDOTDIR != $VSCODE_ZDOTDIR ]]; then
ZDOTDIR=$USER_ZDOTDIR
fi

View File

@@ -0,0 +1,252 @@
# ---------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# ---------------------------------------------------------------------------------------------
#
# Visual Studio Code terminal integration for fish
#
# Manual installation:
#
# (1) Add the following to the end of `$__fish_config_dir/config.fish`:
#
# string match -q "$TERM_PROGRAM" "vscode"
# and . (code --locate-shell-integration-path fish)
#
# (2) Restart fish.
# Don't run in scripts, other terminals, or more than once per session.
status is-interactive
and string match --quiet "$TERM_PROGRAM" "vscode"
and ! set --query VSCODE_SHELL_INTEGRATION
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
# to apply the path prefix fix always, not only for login shells (see #232291)
if set -q VSCODE_PATH_PREFIX
set -gx PATH "$VSCODE_PATH_PREFIX$PATH"
end
set -e VSCODE_PATH_PREFIX
set -g vsc_env_keys
set -g vsc_env_values
# Tracks if the shell has been initialized, this prevents
set -g vsc_initialized 0
set -g __vsc_applied_env_vars 0
function __vsc_apply_env_vars
if test $__vsc_applied_env_vars -eq 1;
return
end
set -l __vsc_applied_env_vars 1
# 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 -m1 = $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 -m1 = $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 -m1 = $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
end
# Register Python shell activate hooks
# Prevent multiple activation with guard
if not set -q VSCODE_PYTHON_AUTOACTIVATE_GUARD
set -gx VSCODE_PYTHON_AUTOACTIVATE_GUARD 1
if test -n "$VSCODE_PYTHON_FISH_ACTIVATE"; and test "$TERM_PROGRAM" = "vscode"
# Fish does not crash on eval failure, so don't need negation.
eval $VSCODE_PYTHON_FISH_ACTIVATE
set __vsc_activation_status $status
if test $__vsc_activation_status -ne 0
builtin printf '\x1b[0m\x1b[7m * \x1b[0;103m VS Code Python fish activation failed with exit code %d \x1b[0m \n' "$__vsc_activation_status"
end
end
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)
end
# Sent right before executing an interactive command.
# Marks the beginning of command output.
function __vsc_cmd_executed --on-event fish_preexec
__vsc_esc E (__vsc_escape_value "$argv") $__vsc_nonce
__vsc_esc C
# Creates a marker to indicate a command was run.
set --global _vsc_has_cmd
end
# Escape a value for use in the 'P' ("Property") or 'E' ("Command Line") sequences.
# Backslashes are doubled and non-alphanumeric characters are hex encoded.
function __vsc_escape_value
# Escape backslashes and semi-colons
echo $argv \
| string replace --all '\\' '\\\\' \
| string replace --all ';' '\\x3b' \
;
end
# Sent right after an interactive command has finished executing.
# Marks the end of command output.
function __vsc_cmd_finished --on-event fish_postexec
__vsc_esc D $status
end
# Sent when a command line is cleared or reset, but no command was run.
# Marks the cleared line with neither success nor failure.
function __vsc_cmd_clear --on-event fish_cancel
if test $vsc_initialized -eq 0;
return
end
__vsc_esc E "" $__vsc_nonce
__vsc_esc C
__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
__vsc_esc P Cwd=(__vsc_escape_value "$PWD")
# If a command marker exists, remove it.
# Otherwise, the commandline is empty and no command was run.
if set --query _vsc_has_cmd
set --erase _vsc_has_cmd
else
__vsc_cmd_clear
end
end
if test -n "$__vscode_shell_env_reporting"
function __vsc_update_env --on-event fish_prompt
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
end
end
# Sent at the start of the prompt.
# Marks the beginning of the prompt (and, implicitly, a new line).
function __vsc_fish_prompt_start
# Applying environment variables is deferred to after config.fish has been
# evaluated
__vsc_apply_env_vars
__vsc_esc A
set -g vsc_initialized 1
end
# Sent at the end of the prompt.
# Marks the beginning of the user's command input.
function __vsc_fish_cmd_start
__vsc_esc B
end
function __vsc_fish_has_mode_prompt -d "Returns true if fish_mode_prompt is defined and not empty"
functions fish_mode_prompt | string match -rvq '^ *(#|function |end$|$)'
end
# 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).
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
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
end
end
end
# Report prompt type
if set -q POSH_SESSION_ID
__vsc_esc P PromptType=oh-my-posh
end
# Report this shell supports rich command detection
__vsc_esc P HasRichCommandDetection=True
__preserve_fish_prompt

View File

@@ -0,0 +1,262 @@
# ---------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# ---------------------------------------------------------------------------------------------
# Prevent installing more than once per session
if ((Test-Path variable:global:__VSCodeState) -and $null -ne $Global:__VSCodeState.OriginalPrompt) {
return;
}
# Disable shell integration when the language mode is restricted
if ($ExecutionContext.SessionState.LanguageMode -ne "FullLanguage") {
return;
}
$Global:__VSCodeState = @{
OriginalPrompt = $function:Prompt
LastHistoryId = -1
IsInExecution = $false
EnvVarsToReport = @()
Nonce = $null
IsStable = $null
IsA11yMode = $null
IsWindows10 = $false
}
# Store the nonce in a regular variable and unset the environment variable. It's by design that
# anything that can execute PowerShell code can read the nonce, as it's basically impossible to hide
# in PowerShell. The most important thing is getting it out of the environment.
$Global:__VSCodeState.Nonce = $env:VSCODE_NONCE
$env:VSCODE_NONCE = $null
$Global:__VSCodeState.IsStable = $env:VSCODE_STABLE
$env:VSCODE_STABLE = $null
$Global:__VSCodeState.IsA11yMode = $env:VSCODE_A11Y_MODE
$env:VSCODE_A11Y_MODE = $null
$__vscode_shell_env_reporting = $env:VSCODE_SHELL_ENV_REPORTING
$env:VSCODE_SHELL_ENV_REPORTING = $null
if ($__vscode_shell_env_reporting) {
$Global:__VSCodeState.EnvVarsToReport = $__vscode_shell_env_reporting.Split(',')
}
Remove-Variable -Name __vscode_shell_env_reporting -ErrorAction SilentlyContinue
$osVersion = [System.Environment]::OSVersion.Version
$Global:__VSCodeState.IsWindows10 = $IsWindows -and $osVersion.Major -eq 10 -and $osVersion.Minor -eq 0 -and $osVersion.Build -lt 22000
Remove-Variable -Name osVersion -ErrorAction SilentlyContinue
if ($env:VSCODE_ENV_REPLACE) {
$Split = $env:VSCODE_ENV_REPLACE.Split(":")
foreach ($Item in $Split) {
$Inner = $Item.Split('=', 2)
[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('=', 2)
[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('=', 2)
[Environment]::SetEnvironmentVariable($Inner[0], [Environment]::GetEnvironmentVariable($Inner[0]) + $Inner[1].Replace('\x3a', ':'))
}
$env:VSCODE_ENV_APPEND = $null
}
# Register Python shell activate hooks
# Prevent multiple activation with guard
if (-not $env:VSCODE_PYTHON_AUTOACTIVATE_GUARD) {
$env:VSCODE_PYTHON_AUTOACTIVATE_GUARD = '1'
if ($env:VSCODE_PYTHON_PWSH_ACTIVATE -and $env:TERM_PROGRAM -eq 'vscode') {
$activateScript = $env:VSCODE_PYTHON_PWSH_ACTIVATE
Remove-Item Env:VSCODE_PYTHON_PWSH_ACTIVATE
try {
Invoke-Expression $activateScript
$Global:__VSCodeState.OriginalPrompt = $function:Prompt
}
catch {
$activationError = $_
Write-Host "`e[0m`e[7m * `e[0;103m VS Code Python powershell activation failed with exit code $($activationError.Exception.Message) `e[0m"
}
}
}
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.
[regex]::Replace($value, "[$([char]0x00)-$([char]0x1f)\\\n;]", { param($match)
# Encode the (ascii) matches as `\x<hex>`
-Join (
[System.Text.Encoding]::UTF8.GetBytes($match.Value) | ForEach-Object { '\x{0:x2}' -f $_ }
)
})
}
function Global:Prompt() {
$FakeCode = [int]!$global:?
# NOTE: We disable strict mode for the scope of this function because it unhelpfully throws an
# error when $LastHistoryEntry is null, and is not otherwise useful.
Set-StrictMode -Off
$LastHistoryEntry = Get-History -Count 1
$Result = ""
# Skip finishing the command if the first command has not yet started or an execution has not
# yet begun
if ($Global:__VSCodeState.LastHistoryId -ne -1 -and ($Global:__VSCodeState.HasPSReadLine -eq $false -or $Global:__VSCodeState.IsInExecution -eq $true)) {
$Global:__VSCodeState.IsInExecution = $false
if ($LastHistoryEntry.Id -eq $Global:__VSCodeState.LastHistoryId) {
# Don't provide a command line or exit code if there was no history entry (eg. ctrl+c, enter on no command)
$Result += "$([char]0x1b)]633;D`a"
}
else {
# Command finished exit code
# OSC 633 ; D [; <ExitCode>] ST
$Result += "$([char]0x1b)]633;D;$FakeCode`a"
}
}
# Prompt started
# OSC 633 ; A ST
$Result += "$([char]0x1b)]633;A`a"
# Current working directory
# OSC 633 ; <Property>=<Value> ST
$Result += if ($pwd.Provider.Name -eq 'FileSystem') { "$([char]0x1b)]633;P;Cwd=$(__VSCode-Escape-Value $pwd.ProviderPath)`a" }
# Send current environment variables as JSON
# OSC 633 ; EnvJson ; <Environment> ; <Nonce>
if ($Global:__VSCodeState.EnvVarsToReport.Count -gt 0) {
$envMap = @{}
foreach ($varName in $Global:__VSCodeState.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);$($Global:__VSCodeState.Nonce)`a"
}
# Before running the original prompt, put $? back to what it was:
if ($FakeCode -ne 0) {
Write-Error "failure" -ea ignore
}
# Run the original prompt
$OriginalPrompt += $Global:__VSCodeState.OriginalPrompt.Invoke()
$Result += $OriginalPrompt
# Prompt
# OSC 633 ; <Property>=<Value> ST
if ($Global:__VSCodeState.IsStable -eq "0") {
$Result += "$([char]0x1b)]633;P;Prompt=$(__VSCode-Escape-Value $OriginalPrompt)`a"
}
# Write command started
$Result += "$([char]0x1b)]633;B`a"
$Global:__VSCodeState.LastHistoryId = $LastHistoryEntry.Id
return $Result
}
# Report prompt type
if ($env:STARSHIP_SESSION_KEY) {
[Console]::Write("$([char]0x1b)]633;P;PromptType=starship`a")
}
elseif ($env:POSH_SESSION_ID) {
[Console]::Write("$([char]0x1b)]633;P;PromptType=oh-my-posh`a")
}
elseif ((Test-Path variable:global:GitPromptSettings) -and $Global:GitPromptSettings) {
[Console]::Write("$([char]0x1b)]633;P;PromptType=posh-git`a")
}
if ($Global:__VSCodeState.IsA11yMode -eq "1") {
if (-not (Get-Module -Name PSReadLine)) {
$scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$specialPsrlPath = Join-Path $scriptRoot 'psreadline'
Import-Module $specialPsrlPath
if (Get-Module -Name PSReadLine) {
Set-PSReadLineOption -EnableScreenReaderMode
}
}
}
# Only send the command executed sequence when PSReadLine is loaded, if not shell integration should
# still work thanks to the command line sequence
$Global:__VSCodeState.HasPSReadLine = $false
if (Get-Module -Name PSReadLine) {
$Global:__VSCodeState.HasPSReadLine = $true
[Console]::Write("$([char]0x1b)]633;P;HasRichCommandDetection=True`a")
$Global:__VSCodeState.OriginalPSConsoleHostReadLine = $function:PSConsoleHostReadLine
function Global:PSConsoleHostReadLine {
$CommandLine = $Global:__VSCodeState.OriginalPSConsoleHostReadLine.Invoke()
$Global:__VSCodeState.IsInExecution = $true
# Command line
# OSC 633 ; E [; <CommandLine> [; <Nonce>]] ST
$Result = "$([char]0x1b)]633;E;"
$Result += $(__VSCode-Escape-Value $CommandLine)
# Only send the nonce if the OS is not Windows 10 as it seems to echo to the terminal
# sometimes
if ($Global:__VSCodeState.IsWindows10 -eq $false) {
$Result += ";$($Global:__VSCodeState.Nonce)"
}
$Result += "`a"
# Command executed
# OSC 633 ; C ST
$Result += "$([char]0x1b)]633;C`a"
# Write command executed sequence directly to Console to avoid the new line from Write-Host
[Console]::Write($Result)
$CommandLine
}
# Set ContinuationPrompt property
$Global:__VSCodeState.ContinuationPrompt = (Get-PSReadLineOption).ContinuationPrompt
if ($Global:__VSCodeState.ContinuationPrompt) {
[Console]::Write("$([char]0x1b)]633;P;ContinuationPrompt=$(__VSCode-Escape-Value $Global:__VSCodeState.ContinuationPrompt)`a")
}
}
# Set IsWindows property
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 {
param ([string[]] $Chord, [string[]]$Sequence)
try {
$Handler = Get-PSReadLineKeyHandler -Chord $Chord | Select-Object -First 1
}
catch [System.Management.Automation.ParameterBindingException] {
# PowerShell 5.1 ships with PSReadLine 2.0.0 which does not have -Chord,
# so we check what's bound and filter it.
$Handler = Get-PSReadLineKeyHandler -Bound | Where-Object -FilterScript { $_.Key -eq $Chord } | Select-Object -First 1
}
if ($Handler) {
Set-PSReadLineKeyHandler -Chord $Sequence -Function $Handler.Function
}
}
function Set-MappedKeyHandlers {
Set-MappedKeyHandler -Chord Ctrl+Spacebar -Sequence 'F12,a'
Set-MappedKeyHandler -Chord Alt+Spacebar -Sequence 'F12,b'
Set-MappedKeyHandler -Chord Shift+Enter -Sequence 'F12,c'
Set-MappedKeyHandler -Chord Shift+End -Sequence 'F12,d'
}
if ($Global:__VSCodeState.HasPSReadLine) {
Set-MappedKeyHandlers
}