Fish shell has different PATH than neovim
TL;DR: neovim triggers shell commands in a non-interactive subshell that is initialised from scratch from your fish.confg
(or other shell setup script). Ensure you set the $PATH
the same way for both the interactive and the non-interactive shell.
Today, I found a strange thing. I added a yaml formatter to my neovim config (I use mhartington/formatter.nvim
). The formatter runs python3 -m pyaml
to format the file. So I installed pip3 install pyaml
to have the module.
When I ran the formatter from within neovim, I saw an error Failed to run formatter python3: /opt/homebrew/python3... no module named pyaml
.
That is strange because I don’t use homebrew python3
. I install python using the asdf VM.
It seems that my fish shell and my neovim have a different path
- Fish:
which python3
returns/Users/tomas/.asdf/shims/python3
- neovim:
!:which python3
returns/opt/homebrew/bin/python3
- and the
echo $PATH
(in fish) and:!echo $PATH
(in neovim) also return different value.
How could this be?
I looked through fish and neovim documentation, trying to find evidence that fish doesn’t send the $PATH
variable to its subprocess or that neovim ignores it.
In the end, I found the issue by running :echo $PATH
and :!echo $PATH
in neovim and noticing that the value is different. The first command returns the same value as the fish shell, and the second returns a different path.
Learning: When you run :!
in neovim, it creates a subshell. It’s still fish :!echo $SHELL
returns /opt/homebrew/bin/fish
but the initialisation is different (non-interactive).
See, I tried to be smart and efficient and guarded most of my config.fish
shell setup with if status is-interactive
. That means I don’t set up autocompletion and other interactive-only features when I run scripts. But one of the setup steps in this interactive-only section was to initialise asdf. When I moved the asdf setup from the interactive-only section, the :echo $PATH
and :!echo $PATH
commands in neovim had identical output.
This is the fix commit in my dotfiles.