pixi icon indicating copy to clipboard operation
pixi copied to clipboard

Support `pixi shell` with fish and Windows

Open fstanis opened this issue 3 months ago • 5 comments

Checks

  • [x] I have checked that this issue has not already been reported.

  • [x] I have confirmed this bug exists on the latest version of pixi, using pixi --version.

Reproducible example

In MSYS2 bash shell:

$ pacman -S fish

$ fish
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish

$ pixi --version
pixi 0.55.0

$ pixi shell -v
 INFO pixi_core::lock_file::update: the lock-file is up-to-date
 INFO pixi_core::lock_file::update: Environment 'default' is up-to-date with lock file hash
 INFO pixi_cli::shell: Starting shell: Fish(Fish)
Error:   × Unsupported shell: Fish(Fish)

Issue description

I came across a few issues trying pixi in a MSYS2 environment on windows with fish, notably, pixi shell fails saying Unsupported shell: Fish(Fish). However, pixi shell-hook actually works fine and outputs this:

set -gx Path "D:\home\user\git\pixi-project\.pixi\envs\default;D:\home\user\git\pixi-project\.pixi\envs\default\Library/mingw-w64/bin;D:\home\user\git\pixi-project\.pixi\envs\default\Library/usr/bin;D:\home\user\git\pixi-project\.pixi\envs\default\Library/bin;D:\home\user\git\pixi-project\.pixi\envs\default\Scripts;D:\home\user\git\pixi-project\.pixi\envs\default\bin;D:\home\user\.local\bin;D:\home\user\bin;D:\Apps\Git\mingw64\bin;D:\Apps\Git\usr\local\bin;D:\Apps\Git\usr\bin;D:\Apps\Git\usr\bin;D:\Apps\Git\mingw64\bin;D:\Apps\Git\usr\bin"
set -gx CONDA_SHLVL "2"
set -gx CONDA_ENV_SHLVL_2_CONDA_PREFIX "D:\home\user\git\pixi-project\.pixi\envs\default"
set -gx CONDA_PREFIX "D:\home\user\git\pixi-project\.pixi\envs\default"
set -gx CONDA_ENV_SHLVL_2_PIXI_PROJECT_NAME "pixi-project"
set -gx PIXI_PROJECT_NAME "pixi-project"
set -gx CONDA_ENV_SHLVL_2_PIXI_PROJECT_ROOT "D:\home\user\git\pixi-project"
set -gx PIXI_PROJECT_ROOT "D:\home\user\git\pixi-project"
set -gx CONDA_ENV_SHLVL_2_PIXI_PROJECT_MANIFEST "D:\home\user\git\pixi-project\pixi.toml"
set -gx PIXI_PROJECT_MANIFEST "D:\home\user\git\pixi-project\pixi.toml"
set -gx CONDA_ENV_SHLVL_2_PIXI_PROJECT_VERSION "0.1.0"
set -gx PIXI_PROJECT_VERSION "0.1.0"
set -gx CONDA_ENV_SHLVL_2_PIXI_IN_SHELL "1"
set -gx PIXI_IN_SHELL "1"
set -gx CONDA_ENV_SHLVL_2_PIXI_EXE "D:\home\user\.pixi\bin\pixi.exe"
set -gx PIXI_EXE "D:\home\user\.pixi\bin\pixi.exe"
set -gx CONDA_ENV_SHLVL_2_CONDA_DEFAULT_ENV "pixi-project"
set -gx CONDA_DEFAULT_ENV "pixi-project"
set -gx CONDA_ENV_SHLVL_2_PIXI_ENVIRONMENT_NAME "default"
set -gx PIXI_ENVIRONMENT_NAME "default"
set -gx CONDA_ENV_SHLVL_2_PIXI_ENVIRONMENT_PLATFORMS "win-64"
set -gx PIXI_ENVIRONMENT_PLATFORMS "win-64"
set -gx CONDA_ENV_SHLVL_2_PIXI_PROMPT "(pixi-project) "
set -gx PIXI_PROMPT "(pixi-project) "

        function __pixi_add_prompt
            set_color -o green
            echo -n "(pixi-project) "
            set_color normal
        end

        if not functions -q __fish_prompt_orig
            functions -c fish_prompt __fish_prompt_orig
        end

        if functions -q fish_right_prompt
            if not functions -q __fish_right_prompt_orig
                functions -c fish_right_prompt __fish_right_prompt_orig
            end
        else
            function __fish_right_prompt_orig
                # Placeholder function for when fish_right_prompt does not exist
                echo ""
            end
        end

        function fish_prompt
            set -l last_status $status
            if set -q PIXI_LEFT_PROMPT
                __pixi_add_prompt
            end
            __fish_prompt_orig
            return $last_status
        end

        function fish_right_prompt
            if not set -q PIXI_LEFT_PROMPT
                __pixi_add_prompt
            end
            __fish_right_prompt_orig
        end    

However, there are problems with this output:

  • The first line is set -gx Path ... while it should be set -gx PATH since it's case-sensitive.
  • The path is using windows-style paths instead of linux-style (cygpath) ones.
  • The path is separated by semicolons instead of being a fish array.

In the output of pixi shell-hook -s bash, PATH is correctly capitalized and uses linux-style paths:

export PATH="/d/home/user/git/pixi-project/.pixi/envs/default:/d/home/user/git/pixi-project/.pixi/envs/default/Library/mingw-w64/bin:/d/home/user/git/pixi-project/.pixi/envs/default/Library/usr/bin:/d/home/user/git/pixi-project/.pixi/envs/default/Library/bin:/d/home/user/git/pixi-project/.pixi/envs/default/Scripts:/d/home/user/git/pixi-project/.pixi/envs/default/bin:/d/home/user/.local/bin:/d/home/user/bin:/mingw64/bin:/usr/local/bin:/usr/bin:/usr/bin:/mingw64/bin:/usr/bin"
export CONDA_SHLVL=2
export CONDA_ENV_SHLVL_2_CONDA_PREFIX="D:\\home\\user\\git\\pixi-project\\.pixi\\envs\\default"
export CONDA_PREFIX="D:\\home\\user\\git\\pixi-project\\.pixi\\envs\\default"
export CONDA_ENV_SHLVL_2_PIXI_EXE="D:\\home\\user\\.pixi\\bin\\pixi.exe"
export PIXI_EXE="D:\\home\\user\\.pixi\\bin\\pixi.exe"
export CONDA_ENV_SHLVL_2_PIXI_PROJECT_VERSION=0.1.0
export PIXI_PROJECT_VERSION=0.1.0
export CONDA_ENV_SHLVL_2_PIXI_PROJECT_ROOT="D:\\home\\user\\git\\pixi-project"
export PIXI_PROJECT_ROOT="D:\\home\\user\\git\\pixi-project"
export CONDA_ENV_SHLVL_2_PIXI_PROJECT_MANIFEST="D:\\home\\user\\git\\pixi-project\\pixi.toml"
export PIXI_PROJECT_MANIFEST="D:\\home\\user\\git\\pixi-project\\pixi.toml"
export CONDA_ENV_SHLVL_2_PIXI_PROJECT_NAME=pixi-project
export PIXI_PROJECT_NAME=pixi-project
export CONDA_ENV_SHLVL_2_PIXI_IN_SHELL=1
export PIXI_IN_SHELL=1
export CONDA_ENV_SHLVL_2_CONDA_DEFAULT_ENV=pixi-project
export CONDA_DEFAULT_ENV=pixi-project
export CONDA_ENV_SHLVL_2_PIXI_ENVIRONMENT_NAME=default
export PIXI_ENVIRONMENT_NAME=default
export CONDA_ENV_SHLVL_2_PIXI_ENVIRONMENT_PLATFORMS=win-64
export PIXI_ENVIRONMENT_PLATFORMS=win-64
export CONDA_ENV_SHLVL_2_PIXI_PROMPT='(pixi-project) '
export PIXI_PROMPT='(pixi-project) '

# shellcheck shell=bash
pixi() {
    local first_arg="${1-}"

    "${PIXI_EXE-}" "$@" || return $?

    case "${first_arg-}" in
    add | a | remove | rm | install | i)
        eval "$("$PIXI_EXE" shell-hook --change-ps1 false)"
        hash -r
        ;;
    esac || :

    return 0
}

export PS1="(pixi-project) ${PS1:-}"

Expected behavior

pixi shell working on fish in MSYS2.

Things work fine if I run set -gx PATH (string split ';' $Path | while read -l item; cygpath $item; end) to correct the PATH based on Path.

fstanis avatar Sep 25 '25 13:09 fstanis

I found the culprit for pixi shell not working:

https://github.com/prefix-dev/pixi/blob/e426c7f5830ebd8718278c24aa4c2641aabe6884/crates/pixi_cli/src/shell.rs#L387-L398

It seems start_winbash can be slightly modified to also accept fish (and possibly other shells?). I'm not sure why pixi shell-hook works though.

fstanis avatar Sep 26 '25 09:09 fstanis

Thanks for the report, looking at the code we indeed don't support fish on Windows yet. We should implement that functionality!

https://github.com/prefix-dev/pixi/blob/3e7973862158c32c7aa4103e366a904620737172/crates/pixi_cli/src/shell.rs#L387-L398

Hofer-Julian avatar Sep 30 '25 15:09 Hofer-Julian

I looked more into this, it seems the current Windows behavior, unlike unix, is to start bash as a new process. This works for switching from e.g. cmd to bash, but is tricky to do for other shells since it relies on --init-file which only bash supports to my knowledge. This also causes #4768 when started from bash because the new process doesn't inherit the current shell's path, so it just uses whatever "bash.exe" is in Windows's default PATH.

@mwiebe, mind chiming in since you implemented this in #3981? Do you think it'd make sense to use the same unix logic on Windows if we're already in a unix-compatible shell and use start_winbash otherwise?

Edit: actually, I'm not sure if it's ever possible for pixi shell to start a unix-compatible shell from a non-unix-compatible shell, I originally thought you can specify the shell using -s like in pixi shell-hook.

fstanis avatar Oct 16 '25 12:10 fstanis

I understand that both Unix and Windows start bash as a subprocess, but the Unix code depends on feeding the shell-hook to the subprocess via the PTY it launched it with. The Windows code doesn't use a PTY and doesn't have the ability to feed the shell-hook that way. Since bath has the --init-file, I was able to get it working on Windows using that option. I'm not sure what the best way to support other shells is, I understand Windows 11 has added some PTY support, but I don't know details about it.

One possibility of a workaround is to fix the shell-hook code to be correct, and then write a shell function like pixivate to use it. Not quite as seamless, but that could work.

mwiebe avatar Oct 19 '25 02:10 mwiebe

Got it, thank you for clarifying!

fstanis avatar Oct 20 '25 16:10 fstanis