Skip to content

Conversation

@nickgnd
Copy link
Contributor

@nickgnd nickgnd commented Oct 18, 2025

Hey 👋
I spontaneously decided to give it a try to #171 and see if i can fix Fish support. I hope this doesn't bother you, if so, feel free to close the PR.


Fish shell uses space-separated PATH variables internally (as a proper list), while other shells like bash and zsh use colon-separated strings. When Expert tried to detect the Elixir executable by running echo $PATH in Fish, it received space-separated output like: /opt/homebrew/bin /opt/homebrew/sbin /Users/username/.local/bin ...

This caused :os.find_executable/2 to fail since it expects colon-separated paths on Unix systems, preventing Fish users from using Expert properly.

Proposed Solution

This PR adds Fish-specific handling to convert the PATH to the expected colon-separated format:

  • Detects Fish shell using String.contains?(shell, "fish")
  • For Fish: uses string join ':' $PATH to convert Fish's list format to colon-separated
    • string join ... is built-in in Fish and available since version 2.3.0 (2016)
  • For other shells: continues using echo $PATH as before

💡 This approach correctly handles paths with spaces in them (e.g., /Applications/Visual Studio Code.app/bin) because it works with Fish's native list structure rather than trying to parse space-separated strings.

Testing

Tested with Fish shell + Mise on macOS, where Elixir executable is now correctly found 🚀

Let me know if the solution is good enough for you, or if is there anything missing.

Cheers ✌️

Copy link
Collaborator

@doorgan doorgan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix! I left a few nitpicky comments but I tested this and it does solve the issue. I can address them and merge this when I get back later today

{path, 0} = System.cmd(shell, ["-i", "-l", "-c", "cd #{root_path} && echo $PATH"])
# Ideally, it should contain the path to shell (e.g. `/usr/bin/fish`),
# but it might contain only the name of the shell (e.g. `fish`).
is_fish? = String.contains?(shell, "fish")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use Path.basename/1 here instead

# Fish uses space-separated PATH, so we use the built-in `string join` command
# to join the entries with colons and have a standard colon-separated PATH output
# as in bash, which is expected by `:os.find_executable/2`.
path_command = if is_fish?, do: "string join ':' $PATH", else: "echo $PATH"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we prefer something like fish_shell?, is_x? mixes both naming conventions for guards and booleans

@rktjmp
Copy link
Contributor

rktjmp commented Oct 20, 2025

Related to alternate shells, nushell (executable nu) requires echo $env.PATH | str join ':'. It also does not seem to support combining -l -c "cmd...", it drops you into a shell without running the command.

I'm not sure if this direction is opening up more issues down the line vs the previous System.get_env() call?

@doorgan doorgan force-pushed the fix/elixir-executable-detection-for-fish-shell branch from 2fcd597 to 167d9ea Compare October 20, 2025 18:10
@doorgan
Copy link
Collaborator

doorgan commented Oct 20, 2025

@rktjmp System.get_env() doesn't produce a PATH that's useful to find the right versions, for example I just tested that and in a project with .tool-versions containing elixir 1.17.1, it still uses elixir 1.17.2 which is incorrect

Unless we find a more reliable way, I'm inclined to special case nushell if it can provide the right path

Another approach I dabbled with was to have a script with a shebang #!/bin/bash with the contents of the System.cmd call here, but that isn't 100% portable either, it's worth a shot again tho

@rktjmp
Copy link
Contributor

rktjmp commented Oct 21, 2025

What version manager & platform do you use?

I'm unable to reproduce any issues using mise+neovim on linux, which isn't to say the problem doesn't exist.

cwd ~ mise.toml project .tools-version version run
~ 1.17.3-otp-27 1.17.1-otp-27 1.17.1
project 1.17.3-otp-27 1.17.1-otp-27 1.17.1
~ 1.17.3-otp-27 1.17.3-otp-27 1.17.3
project 1.17.3-otp-27 1.17.3-otp-27 1.17.3
~ 1.17.3-otp-27 not specified 1.17.3
project 1.17.3-otp-27 not specified 1.17.3
~ not specified 1.17.2-otp-27 1.17.2
project not specified 1.17.2-otp-27 1.17.2
~ 1.17.3-otp-27 1.17.2 1.17.2 (otp-25)
project 1.17.3-otp-27 1.17.2 1.17.2 (otp-25)

I don't want to gum up this PR. If you want to open an issue around version managers I can try to look at other configurations, or we can stick with the shell.

Note both current releases of nushell and elvish dont seem to set $SHELL so detecting them might be difficult (probably more of a bug on their end though).

I guess to me, if interrogating the version managers explicitly is flakey, then surely interrogating them by proxy (via cd & echo $PATH) would be too?

If it works it works though!

@doorgan
Copy link
Collaborator

doorgan commented Oct 21, 2025

What version manager & platform do you use?

I've tried with asdf and mise, the one that causes the most issues is asdf

if interrogating the version managers explicitly is flakey, then surely interrogating them by proxy (via cd & echo $PATH) would be too?

Not really, the issue we had before was that because we didn't have a PATH we'd have to rebuild it, and the apis provided by the version managers were insufficient(for example they'd only give us elixir but not erlang or rust). By getting the PATH in the project directory we can let the os find the asdf shims or the mise installation. It's also a moving target just like shells, asdf in particular changed all its apis in 0.16.

I don't want to gum up this PR. If you want to open an issue around version managers I can try to look at other configurations, or we can stick with the shell.

I'm all in for a solution that would let us stop having to worry about this for good

@doorgan doorgan merged commit 9803293 into elixir-lang:main Oct 21, 2025
92 of 95 checks passed
@rktjmp
Copy link
Contributor

rktjmp commented Oct 22, 2025

Sounds like this is the best solution 👍

@nickgnd nickgnd deleted the fix/elixir-executable-detection-for-fish-shell branch October 22, 2025 09:37
@sbaildon
Copy link

I see this PR has already landed, but if it helps at all, you can wrap $PATH in quotes to receive a colon separated list

echo "$PATH"
/Users/sbaildon/.local/bin:/nix/var/nix/profiles/default/bin:/Users/sbaildon/.local/share/cargo/bin

versus

echo $PATH
/Users/sbaildon/.local/bin /nix/var/nix/profiles/default/bin /Users/sbaildon/.local/share/cargo/bin 

@doorgan
Copy link
Collaborator

doorgan commented Oct 24, 2025

@sbaildon that's a great tip! We can add that in a new PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants