This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
# 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
|
||||
|
||||
# Apply any explicit path prefix (see #99878)
|
||||
if status --is-login; and set -q VSCODE_PATH_PREFIX
|
||||
fish_add_path -p $VSCODE_PATH_PREFIX
|
||||
end
|
||||
set -e VSCODE_PATH_PREFIX
|
||||
|
||||
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 = $B)
|
||||
set -gx "$split[1]" (echo -e "$split[2]")
|
||||
end
|
||||
set -e VSCODE_ENV_REPLACE
|
||||
end
|
||||
if test -n "$VSCODE_ENV_PREPEND"
|
||||
set ITEMS (string split : $VSCODE_ENV_PREPEND)
|
||||
for B in $ITEMS
|
||||
set split (string split = $B)
|
||||
set -gx "$split[1]" (echo -e "$split[2]")"$$split[1]" # avoid -p as it adds a space
|
||||
end
|
||||
set -e VSCODE_ENV_PREPEND
|
||||
end
|
||||
if test -n "$VSCODE_ENV_APPEND"
|
||||
set ITEMS (string split : $VSCODE_ENV_APPEND)
|
||||
for B in $ITEMS
|
||||
set split (string split = $B)
|
||||
set -gx "$split[1]" "$$split[1]"(echo -e "$split[2]") # avoid -a as it adds a space
|
||||
end
|
||||
set -e VSCODE_ENV_APPEND
|
||||
end
|
||||
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
|
||||
__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
|
||||
|
||||
# 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
|
||||
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
|
||||
__preserve_fish_prompt
|
@@ -0,0 +1,351 @@
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
__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.
|
||||
local -r LC_ALL=C
|
||||
local -r str="${1}"
|
||||
local -ir len="${#str}"
|
||||
|
||||
local -i i
|
||||
local -i val
|
||||
local byte
|
||||
local token
|
||||
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
|
||||
if [[ "$(uname -s)" =~ ^CYGWIN*|MINGW*|MSYS* ]]; 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
|
||||
if [[ "$HISTCONTROL" =~ .*(erasedups|ignoreboth|ignoredups).* ]]; then
|
||||
__vsc_history_verify=0
|
||||
else
|
||||
__vsc_history_verify=1
|
||||
fi
|
||||
|
||||
__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
|
||||
|
||||
__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")"
|
||||
}
|
||||
|
||||
__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
|
||||
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_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="$?"
|
||||
__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
|
||||
local cmd
|
||||
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,9 @@
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
|
||||
ZDOTDIR=$USER_ZDOTDIR
|
||||
if [[ $options[norcs] = off && -o "login" && -f $ZDOTDIR/.zlogin ]]; then
|
||||
. $ZDOTDIR/.zlogin
|
||||
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 [[ $options[norcs] = off && -o "login" && -f $USER_ZDOTDIR/.zprofile ]]; then
|
||||
VSCODE_ZDOTDIR=$ZDOTDIR
|
||||
ZDOTDIR=$USER_ZDOTDIR
|
||||
. $USER_ZDOTDIR/.zprofile
|
||||
ZDOTDIR=$VSCODE_ZDOTDIR
|
||||
|
||||
# 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,193 @@
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# 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=''
|
||||
|
||||
for (( i = 0; i < ${#str}; ++i )); do
|
||||
byte="${str:$i:1}"
|
||||
|
||||
# Escape backslashes, semi-colons and newlines
|
||||
if [ "$byte" = "\\" ]; then
|
||||
token="\\\\"
|
||||
elif [ "$byte" = ";" ]; then
|
||||
token="\\x3b"
|
||||
elif [ "$byte" = $'\n' ]; then
|
||||
token="\x0a"
|
||||
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
|
||||
|
||||
__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}")"
|
||||
}
|
||||
|
||||
__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() {
|
||||
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_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,258 @@
|
||||
# ---------------------------------------------------------------------------------------------
|
||||
# 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:__VSCodeOriginalPrompt) {
|
||||
return;
|
||||
}
|
||||
|
||||
# Disable shell integration when the language mode is restricted
|
||||
if ($ExecutionContext.SessionState.LanguageMode -ne "FullLanguage") {
|
||||
return;
|
||||
}
|
||||
|
||||
$Global:__VSCodeOriginalPrompt = $function:Prompt
|
||||
|
||||
$Global:__LastHistoryId = -1
|
||||
|
||||
# Store the nonce in script scope and unset the global
|
||||
$Nonce = $env:VSCODE_NONCE
|
||||
$env:VSCODE_NONCE = $null
|
||||
|
||||
$isStable = $env:VSCODE_STABLE
|
||||
$env:VSCODE_STABLE = $null
|
||||
|
||||
$osVersion = [System.Environment]::OSVersion.Version
|
||||
$isWindows10 = $IsWindows -and $osVersion.Major -eq 10 -and $osVersion.Minor -eq 0 -and $osVersion.Build -lt 22000
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
if ($Global:__LastHistoryId -ne -1) {
|
||||
if ($LastHistoryEntry.Id -eq $Global:__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" }
|
||||
# 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:__VSCodeOriginalPrompt.Invoke()
|
||||
$Result += $OriginalPrompt
|
||||
|
||||
# Prompt
|
||||
# OSC 633 ; <Property>=<Value> ST
|
||||
if ($isStable -eq "0") {
|
||||
$Result += "$([char]0x1b)]633;P;Prompt=$(__VSCode-Escape-Value $OriginalPrompt)`a"
|
||||
}
|
||||
|
||||
# Write command started
|
||||
$Result += "$([char]0x1b)]633;B`a"
|
||||
$Global:__LastHistoryId = $LastHistoryEntry.Id
|
||||
return $Result
|
||||
}
|
||||
|
||||
# Only send the command executed sequence when PSReadLine is loaded, if not shell integration should
|
||||
# still work thanks to the command line sequence
|
||||
if (Get-Module -Name PSReadLine) {
|
||||
$__VSCodeOriginalPSConsoleHostReadLine = $function:PSConsoleHostReadLine
|
||||
function Global:PSConsoleHostReadLine {
|
||||
$CommandLine = $__VSCodeOriginalPSConsoleHostReadLine.Invoke()
|
||||
|
||||
# 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 ($IsWindows10 -eq $false) {
|
||||
$Result += ";$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 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 ContinuationPrompt property
|
||||
if ($isStable -eq "0") {
|
||||
$ContinuationPrompt = (Get-PSReadLineOption).ContinuationPrompt
|
||||
if ($ContinuationPrompt) {
|
||||
[Console]::Write("$([char]0x1b)]633;P;ContinuationPrompt=$(__VSCode-Escape-Value $ContinuationPrompt)`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'
|
||||
|
||||
# Enable suggestions if the environment variable is set and Windows PowerShell is not being used
|
||||
# as APIs are not available to support this feature
|
||||
if ($env:VSCODE_SUGGEST -eq '1' -and $PSVersionTable.PSVersion -ge "6.0") {
|
||||
Remove-Item Env:VSCODE_SUGGEST
|
||||
|
||||
# VS Code send completions request (may override Ctrl+Spacebar)
|
||||
Set-PSReadLineKeyHandler -Chord 'F12,e' -ScriptBlock {
|
||||
Send-Completions
|
||||
}
|
||||
|
||||
# TODO: When does this invalidate? Installing a new module could add new commands. We could expose a command to update? Track `(Get-Module).Count`?
|
||||
# Commands are expensive to complete and send over, do this once for the empty string so we
|
||||
# don't need to do it each time the user requests. Additionally we also want to do filtering
|
||||
# and ranking on the client side with the full list of results.
|
||||
$result = "$([char]0x1b)]633;CompletionsPwshCommands;commands;"
|
||||
$result += [System.Management.Automation.CompletionCompleters]::CompleteCommand('') | ConvertTo-Json -Compress
|
||||
$result += "`a"
|
||||
Write-Host -NoNewLine $result
|
||||
}
|
||||
}
|
||||
|
||||
function Send-Completions {
|
||||
$commandLine = ""
|
||||
$cursorIndex = 0
|
||||
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$commandLine, [ref]$cursorIndex)
|
||||
$completionPrefix = $commandLine
|
||||
|
||||
# Start completions sequence
|
||||
$result = "$([char]0x1b)]633;Completions"
|
||||
|
||||
# If there is a space in the input, defer to TabExpansion2 as it's more complicated to
|
||||
# determine what type of completions to use
|
||||
# `[` is included here as namespace commands are not included in CompleteCommand(''),
|
||||
# additionally for some reason CompleteVariable('[') causes the prompt to clear and reprint
|
||||
# multiple times
|
||||
if ($completionPrefix.Contains(' ') -or $completionPrefix.Contains('[') -or $PSVersionTable.PSVersion -lt "6.0") {
|
||||
$completions = TabExpansion2 -inputScript $completionPrefix -cursorColumn $cursorIndex
|
||||
if ($null -ne $completions.CompletionMatches) {
|
||||
$result += ";$($completions.ReplacementIndex);$($completions.ReplacementLength);$($cursorIndex);"
|
||||
if ($completions.CompletionMatches.Count -gt 0 -and $completions.CompletionMatches.Where({ $_.ResultType -eq 3 -or $_.ResultType -eq 4 })) {
|
||||
$json = [System.Collections.ArrayList]@($completions.CompletionMatches)
|
||||
# Add . and .. to the completions list
|
||||
$json.Add([System.Management.Automation.CompletionResult]::new(
|
||||
'.', '.', [System.Management.Automation.CompletionResultType]::ProviderContainer, (Get-Location).Path)
|
||||
)
|
||||
$json.Add([System.Management.Automation.CompletionResult]::new(
|
||||
'..', '..', [System.Management.Automation.CompletionResultType]::ProviderContainer, (Split-Path (Get-Location) -Parent))
|
||||
)
|
||||
$result += $json | ConvertTo-Json -Compress
|
||||
} else {
|
||||
$result += $completions.CompletionMatches | ConvertTo-Json -Compress
|
||||
}
|
||||
}
|
||||
}
|
||||
# If there is no space, get completions using CompletionCompleters as it gives us more
|
||||
# control and works on the empty string
|
||||
else {
|
||||
# Note that CompleteCommand isn't included here as it's expensive
|
||||
$completions = $(
|
||||
([System.Management.Automation.CompletionCompleters]::CompleteFilename($completionPrefix));
|
||||
([System.Management.Automation.CompletionCompleters]::CompleteVariable($completionPrefix));
|
||||
)
|
||||
if ($null -ne $completions) {
|
||||
$result += ";$($completions.ReplacementIndex);$($completions.ReplacementLength);$($cursorIndex);"
|
||||
$result += $completions | ConvertTo-Json -Compress
|
||||
} else {
|
||||
$result += ";0;$($completionPrefix.Length);$($completionPrefix.Length);[]"
|
||||
}
|
||||
}
|
||||
|
||||
# End completions sequence
|
||||
$result += "`a"
|
||||
|
||||
Write-Host -NoNewLine $result
|
||||
}
|
||||
|
||||
# Register key handlers if PSReadLine is available
|
||||
if (Get-Module -Name PSReadLine) {
|
||||
Set-MappedKeyHandlers
|
||||
}
|
Reference in New Issue
Block a user