Initial commit, 90% there
This commit is contained in:
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
@@ -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
|
||||
@@ -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
|
||||
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
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user