diff --git a/README.md b/README.md
index 5d43b415..6688f17f 100644
--- a/README.md
+++ b/README.md
@@ -271,6 +271,19 @@ See [Advanced configuration](#advanced-configuration) for details and more confi
+#### Microsoft PowerShell
+
+
+
+ Add the commands to `$profile.CurrentUserAllHosts` by running the following in your terminal:
+
+ ~~~ pwsh
+ echo '$Env:PYENV_ROOT="$HOME/.pyenv"' >> $profile.CurrentUserAllHosts
+ echo '$Env:PATH="$Env:PYENV_ROOT/bin:$Env:PATH"' >> $profile.CurrentUserAllHosts
+ echo 'iex ((pyenv init -) -join "`n")' >> $profile.CurrentUserAllHosts
+ ~~~
+
+
### C. Restart your shell
----
@@ -689,7 +702,7 @@ opposed to this idea. Here's what `eval "$(pyenv init -)"` actually does:
3. **Installs autocompletion.** This is entirely optional but pretty
useful. Sourcing `/completions/pyenv.bash` will set that
- up. There are also completions for Zsh and Fish.
+ up. There are also completions for Zsh, Fish and PowerShell.
4. **Rehashes shims.** From time to time you'll need to rebuild your
shim files. Doing this on init makes sure everything is up to
diff --git a/completions/pyenv.pwsh b/completions/pyenv.pwsh
new file mode 100644
index 00000000..f422f468
--- /dev/null
+++ b/completions/pyenv.pwsh
@@ -0,0 +1,17 @@
+$scriptblock = {
+ param($wordToComplete, $commandAst, $cursorPosition)
+ $words = $commandAst.ToString()
+ if ( $wordToComplete ) {
+ $matches = (($words[0..$cursorPosition] -join '') | Select-String -Pattern "\s+" -AllMatches).Matches
+ if ( $matches ) {
+ $cursorPosition = $matches[-1].Index - 1
+ }
+ }
+ $words = $words[0..$cursorPosition] -join '' -split "\s+"
+ if ( $words.Count -ge 2 ) {
+ pyenv completions $words[1] | where { $_ -match $wordToComplete }
+ } else {
+ pyenv commands | where { $_ -match $wordToComplete }
+ }
+}
+Register-ArgumentCompleter -Native -CommandName pyenv -ScriptBlock $scriptblock
diff --git a/libexec/pyenv-init b/libexec/pyenv-init
index 6341b655..eb1d5194 100755
--- a/libexec/pyenv-init
+++ b/libexec/pyenv-init
@@ -15,6 +15,7 @@ if [ "$1" = "--complete" ]; then
echo bash
echo fish
echo ksh
+ echo pwsh
echo zsh
exit
fi
@@ -102,6 +103,10 @@ function detect_profile() {
profile_explain="~/.bash_profile if it exists, otherwise ~/.profile"
rc='~/.bashrc'
;;
+ pwsh )
+ profile='~/.config/powershell/profile.ps1'
+ rc='~/.config/powershell/profile.ps1'
+ ;;
zsh )
profile='~/.zprofile'
rc='~/.zshrc'
@@ -150,6 +155,21 @@ function help_() {
echo 'pyenv init - fish | source'
echo
;;
+ pwsh )
+ echo '# Load pyenv automatically by appending'
+ echo -n "# the following to "
+ if [ "$profile" == "$rc" ]; then
+ echo "$profile :"
+ else
+ echo
+ echo "${profile_explain:-$profile} (for login shells)"
+ echo "and $rc (for interactive shells) :"
+ fi
+ echo
+ echo '$Env:PYENV_ROOT="$HOME/.pyenv"'
+ echo '$Env:PATH="$Env:PYENV_ROOT/bin:$Env:PATH"'
+ echo 'iex ((pyenv init -) -join "`n")'
+ ;;
* )
echo '# Load pyenv automatically by appending'
echo -n "# the following to "
@@ -186,6 +206,11 @@ function print_path() {
print_path_prepend_shims
echo 'end'
;;
+ pwsh )
+ echo 'if ( $Env:PATH -match "'"${PYENV_ROOT}/shims"'" ) {'
+ print_path_prepend_shims
+ echo '}'
+ ;;
* )
echo 'if [[ ":$PATH:" != *'\':"${PYENV_ROOT}"/shims:\''* ]]; then'
print_path_prepend_shims
@@ -199,6 +224,10 @@ function print_path() {
echo 'set -eg PATH[$pyenv_index]; end; set -e pyenv_index'
print_path_prepend_shims
;;
+ pwsh )
+ echo '$Env:PATH="$(($Env:PATH -split '"':'"' | where { -not ($_ -match '"'${PYENV_ROOT}/shims'"') }) -join '"':'"')"'
+ print_path_prepend_shims
+ ;;
* )
# Some distros (notably Debian-based) set Bash's SSH_SOURCE_BASHRC compilation option
# that makes it source `bashrc` under SSH even when not interactive.
@@ -223,6 +252,9 @@ function print_path_prepend_shims() {
fish )
echo 'set -gx PATH '\'"${PYENV_ROOT}/shims"\'' $PATH'
;;
+ pwsh )
+ echo '$Env:PATH="'"${PYENV_ROOT}"'/shims:$Env:PATH"'
+ ;;
* )
echo 'export PATH="'"${PYENV_ROOT}"'/shims:${PATH}"'
;;
@@ -234,6 +266,9 @@ function print_env() {
fish )
echo "set -gx PYENV_SHELL $shell"
;;
+ pwsh )
+ echo '$Env:PYENV_SHELL="'"$shell"'"'
+ ;;
* )
echo "export PYENV_SHELL=$shell"
;;
@@ -243,13 +278,27 @@ function print_env() {
function print_completion() {
completion="${0%/*/*}/completions/pyenv.${shell}"
if [ -r "$completion" ]; then
- echo "source '$completion'"
+ case "$shell" in
+ pwsh )
+ echo "iex (gc $completion -Raw)"
+ ;;
+ * )
+ echo "source '$completion'"
+ ;;
+ esac
fi
}
function print_rehash() {
if [ -z "$no_rehash" ]; then
- echo 'command pyenv rehash 2>/dev/null'
+ case "$shell" in
+ pwsh )
+ echo '& pyenv rehash 2>/dev/null'
+ ;;
+ * )
+ echo 'command pyenv rehash 2>/dev/null'
+ ;;
+ esac
fi
}
@@ -270,6 +319,25 @@ function print_shell_function() {
end
end'
;;
+ pwsh )
+ cat <&2
false
end
+EOS
+ ;;
+ pwsh )
+ cat </dev/null; then
echo 'set -gu PYENV_VERSION_OLD "$PYENV_VERSION"'
echo "set -gx PYENV_VERSION \"$version\""
;;
+ pwsh )
+ echo '$Env:PYENV_VERSION, $Env:PYENV_VERSION_OLD = "'"${version}"'", $Env:PYENV_VERSION'
+ ;;
* )
echo 'PYENV_VERSION_OLD="${PYENV_VERSION-}"'
echo "export PYENV_VERSION=\"${version}\""
diff --git a/test/init.bats b/test/init.bats
index f5355591..06fc7ea9 100755
--- a/test/init.bats
+++ b/test/init.bats
@@ -74,6 +74,19 @@ OUT
assert_line 'pyenv init - fish | source'
}
+@test "setup shell completions (pwsh)" {
+ root="$(cd $BATS_TEST_DIRNAME/.. && pwd)"
+ run pyenv-init - pwsh
+ assert_success
+ assert_line "iex (gc ${root}/test/../libexec/../completions/pyenv.pwsh -Raw)"
+}
+
+@test "pwsh instructions" {
+ run pyenv-init pwsh
+ assert [ "$status" -eq 1 ]
+ assert_line 'iex ((pyenv init -) -join "`n")'
+}
+
@test "shell detection for installer" {
run pyenv-init --detect-shell
assert_success
@@ -100,6 +113,13 @@ OUT
assert_line "set -gx PATH '${PYENV_ROOT}/shims' \$PATH"
}
+@test "adds shims to PATH (pwsh)" {
+ export PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:/bin:/usr/local/bin"
+ run pyenv-init - pwsh
+ assert_success
+ assert_line '$Env:PATH="'${PYENV_ROOT}'/shims:$Env:PATH"'
+}
+
@test "removes existing shims from PATH" {
OLDPATH="$PATH"
export PATH="${BATS_TEST_DIRNAME}/nonexistent:${PYENV_ROOT}/shims:$PATH"
@@ -124,6 +144,19 @@ echo "\$PATH"
assert_output "${PYENV_ROOT}/shims:${BATS_TEST_DIRNAME}/nonexistent:${OLDPATH//${PYENV_ROOT}\/shims:/}"
}
+@test "removes existing shims from PATH (pwsh)" {
+ command -v pwsh >/dev/null || skip "-- pwsh not installed"
+ OLDPATH="$PATH"
+ export PATH="${BATS_TEST_DIRNAME}/nonexistent:${PYENV_ROOT}/shims:$PATH"
+ run pwsh -noni -c - </dev/null || skip "-- pwsh not installed"
+ export PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:/bin:/usr/local/bin"
+ run pwsh -noni -c - </dev/null || skip "-- pwsh not installed"
+ export PATH="${BATS_TEST_DIRNAME}/../libexec:/usr/bin:${PYENV_ROOT}/shims:/bin:/usr/local/bin"
+ run pwsh -noni -c - </dev/null || true"
assert_success
assert [ -x "${PYENV_ROOT}/shims/python" ]
}
+
+@test "sh-rehash in pwsh" {
+ create_executable "3.4" "python"
+ PYENV_SHELL=pwsh run pyenv-sh-rehash
+ assert_success ""
+ assert [ -x "${PYENV_ROOT}/shims/python" ]
+}
diff --git a/test/shell.bats b/test/shell.bats
index daa5744b..e20df561 100644
--- a/test/shell.bats
+++ b/test/shell.bats
@@ -31,6 +31,11 @@ load test_helper
assert_success 'echo "$PYENV_VERSION"'
}
+@test "shell version (pwsh)" {
+ PYENV_SHELL=pwsh PYENV_VERSION="1.2.3" run pyenv-sh-shell
+ assert_success 'echo "$PYENV_VERSION"'
+}
+
@test "shell revert" {
PYENV_SHELL=bash run pyenv-sh-shell -
assert_success
@@ -43,6 +48,12 @@ load test_helper
assert_line 0 'if set -q PYENV_VERSION_OLD'
}
+@test "shell revert (pwsh)" {
+ PYENV_SHELL=pwsh run pyenv-sh-shell -
+ assert_success
+ assert_line 0 'if ( Get-Item -Path Env:\PYENV_VERSION* ) {'
+}
+
@test "shell unset" {
PYENV_SHELL=bash run pyenv-sh-shell --unset
assert_success
@@ -61,6 +72,14 @@ set -e PYENV_VERSION
OUT
}
+@test "shell unset (pwsh)" {
+ PYENV_SHELL=pwsh run pyenv-sh-shell --unset
+ assert_success
+ assert_output <