fish-shell / fish-shell

The user-friendly command line shell.
https://fishshell.com
Other
26.09k stars 1.91k forks source link

Git tab completion error when no gettext #6804

Closed johnflavin closed 4 years ago

johnflavin commented 4 years ago
> echo $version
3.1.0
> uname -a
Darwin C02VT4WSHTD6 18.7.0 Darwin Kernel Version 18.7.0: Sun Dec  1 18:59:03 PST 2019; root:xnu-4903.278.19~1/RELEASE_X86_64 x86_64
> echo $TERM
xterm-256color

Problem

When using tab completion for git and the gettext command is not found, an error is raised from fish.

This is the error message:

fish: Unknown command: gettext
/usr/local/Cellar/fish/3.1.0/share/fish/functions/_.fish (line 15):
        command gettext fish $argv
                ^
in function '_' with arguments 'Modified\ file'
    called on line 1 of file /usr/local/Cellar/fish/3.1.0/share/fish/completions/git.fish
in command substitution
    called on line 134 of file /usr/local/Cellar/fish/3.1.0/share/fish/completions/git.fish
in function '__fish_git_files' with arguments 'modified deleted'
in command substitution
fish: Unknown command: gettext
/usr/local/Cellar/fish/3.1.0/share/fish/functions/_.fish (line 15):
        command gettext fish $argv
                ^
in function '_' with arguments 'Deleted\ file'
    called on line 1 of file /usr/local/Cellar/fish/3.1.0/share/fish/completions/git.fish
in command substitution
    called on line 140 of file /usr/local/Cellar/fish/3.1.0/share/fish/completions/git.fish
in function '__fish_git_files' with arguments 'modified deleted'
in command substitution

Note that the command substitution does still work, at least it did during my testing. But the error gets printed to the screen.

Reproduction

I could reproduce this in a shell with third-party plugins turned off. However, it was a bit tricky because of interactions with conda. When I activated the fresh shell, it still had my default conda environment enabled, and that environment does have gettext. So I had to conda init, then deactivate conda, and then I could reproduce the issue.

Reproduction was being in a git repo directory and running git checkout <a letter that starts a branch name> and pressing <TAB>.

In this log, most of the lines are getting conda set up. The last command is the one that produces the error.

<my prompt> ❯ sh -c 'env HOME=$(mktemp -d) fish'
Welcome to fish, the friendly interactive shell
Type `help` for instructions on how to use fish
me@machine /U/me> conda deactivate

CommandNotFoundError: Your shell has not been properly configured to use 'conda deactivate'.
To initialize your shell, run

    $ conda init <SHELL_NAME>

Currently supported shells are:
  - bash
  - fish
  - tcsh
  - xonsh
  - zsh
  - powershell

See 'conda init --help' for more information and options.

IMPORTANT: You may need to close and restart your shell after running 'conda init'.

me@machine /U/me [1]> conda init fish
no change     /Users/me/anaconda3/envs/env/condabin/conda
no change     /Users/me/anaconda3/envs/env/bin/conda
no change     /Users/me/anaconda3/envs/env/bin/conda-env
no change     /Users/me/anaconda3/envs/env/bin/activate
no change     /Users/me/anaconda3/envs/env/bin/deactivate
no change     /Users/me/anaconda3/envs/env/etc/profile.d/conda.sh
no change     /Users/me/anaconda3/envs/env/etc/fish/conf.d/conda.fish
no change     /Users/me/anaconda3/envs/env/shell/condabin/Conda.psm1
no change     /Users/me/anaconda3/envs/env/shell/condabin/conda-hook.ps1
no change     /Users/me/anaconda3/envs/env/lib/python3.6/site-packages/xontrib/conda.xsh
no change     /Users/me/anaconda3/envs/env/etc/profile.d/conda.csh
modified      /var/folders/91/5v0zgdv56810hdtqv4z3s9rw0000gp/T/tmp.dfyvH8yu/.config/fish/config.fish

==> For changes to take effect, close and re-open your current shell. <==

me@machine /U/me>
source /var/folders/91/5v0zgdv56810hdtqv4z3s9rw0000gp/T/tmp.dfyvH8yu/.config/fish/config.fish
me@machine /U/me> conda deactivate                                         (env)
me@machine /U/me> conda deactivate                (/Users/me/anaconda3)
me@machine /U/me> which gettext
me@machine /U/me [1]> cd repo/
me@machine /U/m/repo (my-git-branch)> git checkout d<TAB>fish: Unknown command: gettext
/usr/local/Cellar/fish/3.1.0/share/fish/functions/_.fish (line 15):
        command gettext fish $argv
                ^
in function '_' with arguments 'Modified\ file'
    called on line 1 of file /usr/local/Cellar/fish/3.1.0/share/fish/completions/git.fish
in command substitution
    called on line 134 of file /usr/local/Cellar/fish/3.1.0/share/fish/completions/git.fish
in function '__fish_git_files' with arguments 'modified deleted'
in command substitution
fish: Unknown command: gettext
/usr/local/Cellar/fish/3.1.0/share/fish/functions/_.fish (line 15):
        command gettext fish $argv
                ^
in function '_' with arguments 'Deleted\ file'
    called on line 1 of file /usr/local/Cellar/fish/3.1.0/share/fish/completions/git.fish
in command substitution
    called on line 140 of file /usr/local/Cellar/fish/3.1.0/share/fish/completions/git.fish
in function '__fish_git_files' with arguments 'modified deleted'
in command substitution
faho commented 4 years ago

Wait, whatnow?

_.fish (https://github.com/fish-shell/fish-shell/blob/master/share/functions/_.fish) explicitly checks for the existence of gettext (or ggettext) before defining the function. If it isn't available it defines a wrapper around echo.

Something is *very wrong with your system.

johnflavin commented 4 years ago

I know! It's weird. I looked in _.fish and saw the lines trying to check for gettext:

if command -sq ggettext
...
else if command -sq gettext
...

When I run command -sq gettext it exits with status 1, as I would expect.

faho commented 4 years ago

I'm betting your conda environment has gettext, and then you're taking it away when deactivating it.

johnflavin commented 4 years ago

Yes, that's something I noted in the issue. When the shell is activated, it starts with a default conda environment that does have gettext. But when I switch to a different conda environment that does not have gettext (or deactivate the environment, as I did in the reproduction), that's when I see the error.

Is this function caching the results of command -sq gettext in the definition or something?

faho commented 4 years ago

Is this function caching the results of command -sq gettext in the definition or something?

It's not in the function definition. The function is conditionally defined, depending on the result.

johnflavin commented 4 years ago

Hmm. That presents an issue in my case, where I can switch from an environment where gettext is available to one where it is not.

Is there a reason not to check for the presence of gettext in the function itself (and thus checking each time it is called), rather than defining a function that assumes the function will always be available if it was once? Like, is that an expensive check?

faho commented 4 years ago

Like, is that an expensive check?

Yes. We've had performance issues with this.

Hmm. That presents an issue in my case, where I can switch from an environment where gettext is available to one where it is not.

Would it not be possible to just install gettext on the host? Or am I misunderstanding something?


One possible way to handle this is to make a _ builtin - we have access to gettext in c++, so we could just make that available. However gettext can potentially crash, I'm not sure how to handle this.

johnflavin commented 4 years ago

Here's a question that may help me remove this problem from the source. It seems that when I load a shell with a temp home, with sh -c 'env HOME=$(mktemp -d) fish', my default conda environment is still on my PATH.

> sh -c 'env HOME=$(mktemp -d) fish'
Welcome to fish, the friendly interactive shell
Type `help` for instructions on how to use fish
me@machine /U/me> echo $PATH
/Users/me/anaconda3/envs/env/bin /Users/me/anaconda3/condabin /Users/me/bin /usr/local/bin /usr/bin /bin /usr/sbin /sbin /opt/X11/bin /usr/local/sbin /usr/local/MacGPG2/bin

Can you tell me how those PATH components get configured? Like, did I (stupidly) set that as a global environment variable or something? I bet if I can figure out how that conda environment is getting in the PATH even though my home directory's config is not being loaded, I can make this problem go away.

faho commented 4 years ago

Can you tell me how those PATH components get configured?

$PATH is a global and exported environment variable. Child processes inherit it. Your terminal process also has a $PATH, as has its parent. That's unix.

johnflavin commented 4 years ago

Ok, I think I see what's happening.

When I did my reproduction, I first opened a new terminal window. That starts a shell which gets all my user configuration applied, which means it loads my default conda environment, which means that conda environment is on the PATH. That's the seed of the issue. Then when I start a new shell with an empty HOME (with sh -c 'env HOME=$(mktemp -d) fish') that PATH, which was already set up with my user stuff, gets inherited into the child shell. So the issue persists even in the "clean" shell.

Now a question about how to solve this: I still want to have a default conda environment. But if possible, I would like it to not be active when _ gets defined; that way it won't think gettext is available. Do you know when _ gets defined? Or if there is a way I can make that happen in my user config before I configure my conda environment?

faho commented 4 years ago

Do you know when _ gets defined?

It is autoloaded whenever it is first executed. So the way to load it earlier is to execute it earlier, possibly by adding a bogus call like _ >/dev/null 2>&1. Or you could call something that loads it to look up the definition like functions _.

Or you could force one definition by creating your own .fish. Try `funced , and thenfuncsave once you're happy. That'll create an.fish` that will take precedence over our default one.

johnflavin commented 4 years ago

Awesome, thanks! I added a script in my ~/.config/fish/conf.d directory that runs functions _ > /dev/null, and named it so it occurs before the script that activates my conda environment. Now I can switch conda environments at will and the git tab completion works without error.