Bash-completion issues (on macOS)

I’m trying to transition my pkgs from brew to nix using nix-env -I. I installed the bash-completion pkg via nix-env. At runtime, it appears to correctly locate user completions under ~/.local/share/bash-completion/completions as well as its own plethora of bundled completion scripts. However, after installing a pkg (with nix-env -I) which installs its own completion script (e.g. as git does when installed this way), these new scripts aren’t getting sourced/found by bash-completion at runtime, and as a result there is no completion for the git command. This is strange because the file ~/.nix-profile/share/bash-completion/completions/git exists?

In my .bashrc, I am using this:

# Bash Completions
if [ -n "$BASH" ]; then
    # [[ -r "$HOMEBREW_PREFIX/etc/profile.d/bash_completion.sh" ]] \
        # && . "$HOMEBREW_PREFIX/etc/profile.d/bash_completion.sh"
    [[ -r ~/.nix-profile/etc/profile.d/bash_completion.sh ]] \
        && . ~/.nix-profile/etc/profile.d/bash_completion.sh
fi

that file getting sourced is this:

# shellcheck shell=sh disable=SC1091,SC2039,SC2166
# Check for interactive bash and that we haven't already been sourced.
if [ "x${BASH_VERSION-}" != x -a "x${PS1-}" != x -a "x${BASH_COMPLETION_VERSINFO-}" = x ]; then

    # Check for recent enough version of bash.
    if [ "${BASH_VERSINFO[0]}" -gt 4 ] ||
        [ "${BASH_VERSINFO[0]}" -eq 4 -a "${BASH_VERSINFO[1]}" -ge 2 ]; then
        [ -r "${XDG_CONFIG_HOME:-$HOME/.config}/bash_completion" ] &&
            . "${XDG_CONFIG_HOME:-$HOME/.config}/bash_completion"
        if shopt -q progcomp && [ -r /nix/store/jyrf6lp9qfnh1iw2lilp5krgh1kxr27y-bash-completion-2.11/share/bash-completion/bash_completion ]; then
            # Source completion code.
            . /nix/store/jyrf6lp9qfnh1iw2lilp5krgh1kxr27y-bash-completion-2.11/share/bash-completion/bash_completion
        fi
    fi

fi

I was able to fix it for the most part, although I’m not sure if it’s the correct/best solution.

I ended up putting this directly into my ~/.bashrc instead:

# shellcheck shell=sh disable=SC1091,SC2039,SC2166
# Check for interactive bash and that we haven't already been sourced.
if [ "x${BASH_VERSION-}" != x -a "x${PS1-}" != x -a "x${BASH_COMPLETION_VERSINFO-}" = x ]; then

    # Check for recent enough version of bash.
    if [ "${BASH_VERSINFO[0]}" -gt 4 ] ||
        [ "${BASH_VERSINFO[0]}" -eq 4 -a "${BASH_VERSINFO[1]}" -ge 2 ]; then
        [ -r "${XDG_CONFIG_HOME:-$HOME/.config}/bash_completion" ] &&
            . "${XDG_CONFIG_HOME:-$HOME/.config}/bash_completion"
        if shopt -q progcomp && [ -r /nix/store/jyrf6lp9qfnh1iw2lilp5krgh1kxr27y-bash-completion-2.11/share/bash-completion/bash_completion ]; then
            # Source completion code.
-            . /nix/store/jyrf6lp9qfnh1iw2lilp5krgh1kxr27y-bash-completion-2.11/share/bash-completion/bash_completion
+            . ~/.nix-profile/share/bash-completion/bash_completion
        fi
    fi
fi

It appears that when bash_completion is sourced via the store path, it will only use its static/bundled completions dir instead of the correct one at ~/.nix-profile/share/bash-completion/completions. The latter is the correct one because it is the one which receives updates when new packages are installed with nix-env, while the former does not. For whatever reason, when sourcing it as ~/.nix-profile/share/bash-completion/bash_completion it uses the correct completions dir, but not when sourcing it via the store path. I assume that the bash_completion script is using a relative path to locate its main completions dir.

I’m sharing all of this just in case it helps someone else out, or if someone knows of a better solution or a more proper way to set this up? I’m not really sure why nix is creating ~/.nix-profile/etc/profile.d/bash_completion.sh and patching it to use the static dir (at the store path, which does not receive installed completion scripts from newly installed pkgs) by default.

2 Likes