Solveddirenv fish: direnv is no longer triggered on shell creation
✔️Accepted Answer
I'm chiming in as a fish user, but I didn't know about the directory arrow shortcuts before reading this issue. I also would vote for option 2. My mental model of direnv has been "inside of this directory, I have this environment". I would even vote for 1, but I think consistency with other shells is desirable. In any case, using the directory history navigation feels like a shortcut for "cd", and so treating it just like that seems most consistent. The only case it seems like it would matter is if the prompt were derived from direnv-exported variables, in which case it feels like 2 is the right behavior and 3 is wrong.
That said, all options fix the thing I care about: we need to run direnv on shell load. Easy enough to work around in config.fish
:
direnv hook fish | source
direnv export fish | source
Other Answers:
So looking at this in relation to #614, I think that probably the solution for this would be to change the fish hook so that it executes --on-event fish_prompt
again, but also --on-variable PWD
. In my experiments, this combination means that it will run when you use alt-arrows to change directory, as well as at the initial prompt.
It does have the slight downside of running the hook twice when you manually cd, (once when the directory changes, and once when it comes back to a prompt), but the prompt is needed for it to work the first time, when the new shell begins.
Now, that actually could be fixed by running the hook immediately upon hook installation, and perhaps that is what we should do for fish. That is, normally only run the hook when PWD changes, and just kick it once on installation to avoid the other issue(s).
One minor drawback to that is that you would no longer be able to pre-empt direnv in a compound command. That is, a command like cd /somedir; something
would now load the correct direnv for /somedir
before something
ran, whereas now you only get the new environment after something
ran.
Otherwise, the only way to get this working is to do something like a prompt hook that triggers a PWD hook (to handle alt-arrow history) and then a pre-exec hook that disables the PWD hook so that it doesn't run mid-commandline. (That's actually easier to make happen than it sounds; fish is actually pretty nice in this one area.)
Okay, so I've experimented a bit with two variations on this. In one, direnv acts like in any other shell, except that reloads are immediately triggered whenever you us the history arrows. In another, it's almost the same, except that if you use the history arrows you instead get the reload triggered once you actually enter a command (via pre-exec). In short, there are three possibly-viable ways to handle it:
- Option 1: trigger any time the directory changes, plus first installation of the hook
- Pros: seamless and simple
- Cons: absolutely no escape from direnv, even in compounds; behavior is vastly different from other shells
- Option 2: trigger at prompt, plus immediately during arrow-based directory changes
- Pros: more like other shells, except for the added feature
- Cons: if you have something complex and slow it might take a while??
- Option 3: trigger at prompt, but also before executing a command if you've used the arrows to change directories
- Pros: doesn't run direnv till you stop hopping around
- Cons: seems prone to surprises if you arrow to a different directory, then have "surprise! you thought you were ready to run your command, but now it is I, direnv!" interrupt
I'm personally inclined to option 2, though you can argue that some of my cons could be considered pros and vice versa. I do have a draft version of option 2 working in my fish shell right now (as ~/.config/fish/conf.d/direnv.fish
, that looks like this:
# Replaces 'eval (direnv hook fish)'
function __direnv_export_eval --on-event fish_prompt;
# Run on each prompt to update the state
/absolute/path/to/direnv export fish | source;
# Handle cd history arrows between now and the next prompt
function __direnv_cd_hook --on-variable PWD;
# ensure any output overwrites the prompt instead of going after it
echo -ne '\r'
# run the outer function to apply any changes
__direnv_export_eval
end
function __direnv_disable_cd --on-event fish_preexec;
# Once we're running commands, stop monitoring cd changes
# until we get to the prompt again
functions --erase __direnv_cd_hook
end
end
So it's something y'all can try out and see what you think. (If you want to see what option 1 is like, you can remove the __direnv_disable_cd
function, and maybe the echo
. Option 3 is harder to implement, though I did try it at one point.)
Describe the bug
direnv does not execute on creation of a new fish shell (or tmux pane or window, etc.) -- I have to hit 'enter' once to trigger it. Triggers fine when changing directories.
To Reproduce
Steps to reproduce the behavior:
bash
cd
into a directory with a whitelisted.envrc
filefish
Steps to reproduce the behaviour via tmux:
cd
into a directory with a whitelisted.envrc
fileExpected behavior
direnv should immediately trigger and load the environment in the new fish shell / tmux pane/window. It does not.
Environment
Additional context
This issue was essentially caused by #512, which solved a smaller issue (direnv not un/loading when changing directories using alt-left/right), and then later this was not fixed by #549, which solved a larger issue cased by #512 (a general 1-command "lag" on direnv activation when using fish).
Incidentally: that first issue is also back after #549; direnv no longer un/loads when changing directories in fish using alt-left/right. I feel like you need regression tests, although unhelpfully I have no clue how you'd instrument them for something like this :P.
if
fish_preexec
is the only thing that fires on changing directories with alt-left/right, andfish_prompt
is the only thing that fires on creation of a new shell, then it seems like perhaps both need to be hooked?