I’m using neovim (nvim) and seeing shell completion doesn’t exist (in bash, try: nvim -[tab] and nothing happens). How do I neovim’s completion scripts sourced? Sorry I couldn’t find this answered before!
I’m new to nixos and struggling to understand where any given package’s shell completions live, so I welcome a more general answer too.
to this broader point: I’m hitting this with yet another command: gradle; I have gradle-completion installed via configuration.nix but no completion seems to be happening. I’m trying to debug… I see that https://pkgs.on-nix.com/nixpkgs/gradle-completion shows there should be something under an “out” dir at /share/bash-completion/completions/gradle - but where is that out dir? And should it already be sourced by something for me or do I need nixos specific sourcing logic in my bashrc?
I found and installed bashInteractive, bash-completion, nix-bash-completions but still no changes and I’m not clear on if bashInteractive is really supposed to be solving anything I’m confused about here…
Bash completions are enabled with the programs.bash.enableCompletion option. It should be enabled by default. You can see the implementation if you click the source link on the search page - it disables completions in bash versions that don’t support it. Maybe get rid of the additional bash packages, just in case
Is your shell running in interactive mode? You won’t get completions if you run a non-interactive shell. Doing some funky things with your bash configuration may also break them, I’d suggest trying this with no configuration first. Try:
bash --norc -i
The way packages work in NixOS is that they’re all installed in their own independent directories under /nix/store. Various parts of NixOS will look at the subdirectories in their package directories, and do things with them - bin directories in packages are added to your PATH, and indeed, completion scripts in that subdirectory should be automatically found by bash.
I’ve found this to work for me more often than with other distros If you can’t figure it out, share your config (including bash config), maybe someone here can spot it.
The fact that nix packages work this way means you can have multiple versions of the same package installed, in theory without interference (but well, running two graphics drivers is impossible due to physical limitations, to run two versions of Xorg you need at least two ttys… It works well for things like python, though).
tl;dr still no luck even with --norc -i; maybe understanding how it usually works correctly in nixos will give me something to debug Couple questions below…
Can you clarify which packages you’re saying I might try to get rid of? Comment out all the bash* ones except bash itself in my system packages?
Is your shell running in interactive mode?
Yes, otherwise most of the output from my own bashrc wouldn’t run (since [[ ${-} = ${-/i/} ]] && return has been the first line of my bashrc for years).
Doing some funky things with your bash configuration may also break them, I’d suggest trying this with no configuration first. Try: bash --norc -i
Oh good idea - I definitely have some highly customized bashrc. Unfortunately this^ test with --norc didn’t change anything. To clarify here’s a list of programs I’m using in my “does completion work yet?”-test:
less
nvim
gradle (particularly since I have gradle and gradle-completion packages)
Can you confirm these^ work for you? (or if you have none of htem installed - is there a program you do have that I can use as my litmus test?) Just asking in case there’s actually just something wonky or custom about my selections.
and indeed, completion scripts in that subdirectory should be automatically found by bash.
So the exact mechanics of this - “should be automatically found by bash” - is what I’d like to learn. There must be some standard very specific to nixos that makes it so things “should” work across packages - do you know what that standard is?
I’ve found this to work for me more often than with other distros
haha, fwiw this statement is super valuable - it at least tells me something is just wonky on my end and it’s fixable. My understanding of why this always works for me on Debian is:
package provides a program named $program-name, eg: say nvim (provided by the neovim package)
package installation installs its completion script in a common directory, specifically here: /usr/share/bash-completion/completions/$program-name
your bashrc (or system’s bashrc) loops over every top-level file in /usr/share/bash-completion/completions/ and sources it.
With nixos however, I don’t know what the analog expectation is - understanding how nixos does it might give me a first-step in debugging my install. The only concrete thing I’ve gotten completion for is a very hand-done step end-users have to do for fzf (sourcing a very app-specific way with this fzf-share hack: https://nixos.wiki/wiki/Fzf#bash)
So I left onlybash in my system package listing and now less actually autocompletes but nothing else in my litmus test does … hopefully helpful debugging signal.
I’m not familiar enough with the completion stuff to know if this is meaningful, but I assume they have to get sourced somewhere in the chain, so one possibility–if you’ve customized any of your other ~bashrc/profile stuff–might be that a statement in those is returning early and keeping the completions from getting sourced?
thanks abathur. I think this was TLATER’s idea when suggesting bash --norc -i (the --norc ensures my own bashrc doesn’t even run - so I don’t even need to go putting an early return at the top, because it won’t be used).
This has me thinking though: could it be more than bashrc? My understanding is that my ~/.bashrc is the only entry point, but it’s possible that there’s another config file somewhere in my ecosystem that’s causing an issue?
… As a clean-slate, let me go boot into the 22.05 gnome Live ISO and see what happens…
So to confirm this I spun up one of my servers’ configs in a VM built using nixos-rebuild build-vm. It has a very minimal config for my user (basically only giving them wheel permissions) and no bash or other interactive configuration - it’s a headless server
Trying with less -<tab><tab><tab> (the dash so it doesn’t just complete files) completes for me.
I don’t have gradle installed by default, but using nix profile install nixpkgs#gradle nixpkgs#gradle-completion (note: I don’t recommend using nix profile or nix-env when you’re not in an experimental VM environment, and don’t exactly know the implications of installing things nondeclaratively in your profile) to install it, I get completions for options if I use gradle -<tab><tab><tab>.
I think I am reasonably confident now that I wasn’t lying, and this is supposed to just work™. But hey, I’ve seen often enough that even NixOS doesn’t always save us from the frailty of software.
Pretty much. But yes, there is still /etc/bashrc, and all the other config that is probably created via your NixOS configuration. Can you usefully share your config?
I’d seen a nice summary of how the completion works before, but can’t find it anymore. I’ll see if I can dig it up some other time!
Ah. Caught me not reading the whole backlog. Not sure. I know there’s a profile, and the corresponding --no-profile flag, but there’s some sort of complexity around their use and the login/interactive shell bits on macOS and Linux that I can never keep straight…
# Check whether we're running a version of Bash that has support for
# programmable completion. If we do, enable all modules installed in
# the system and user profile in obsolete /etc/bash_completion.d/
# directories. Bash loads completions in all
# $XDG_DATA_DIRS/bash-completion/completions/
# on demand, so they do not need to be sourced here.
if shopt -q progcomp &>/dev/null; then
. "/nix/store/bcjj9j8xqbwqx4fcsxydya671pgl5nzq-bash-completion-2.11/etc/profile.d/bash_completion.sh"
nullglobStatus=$(shopt -p nullglob)
shopt -s nullglob
for p in $NIX_PROFILES; do
for m in "$p/etc/bash_completion.d/"*; do
. "$m"
done
done
eval "$nullglobStatus"
unset nullglobStatus p m
fi
So nix package completions will happen automatically by the package adding itself to $XDG_DATA_DIRS with its completions in its bash-completion/completions/ dir. (I’ve not actually confirmed this happens; but I trust the comment. Completions work for me.)
progcomp wouldn’t be true in the non-interactive bash, I think, but it sounded like that thread got pulled earlier. set -x should make it clear if that step is falling over or never happening, I imagine.
I felt guilty, so I confirmed it works as described. To do that I
echo $XDG_DATA_DIRS # notice it contains `/run/current-system/sw/share`
ls -al /run/current-system/sw/share/bash-completion/completions/nix
# responds `/nix/store/rrgcc6kzvx9d85b448jga7sdv0z2fzmr-nix-2.9.1/share/bash-completion/completions/nix` or similar
Explore the package dirs /nix/store/rrgcc6kzvx9d85b448jga7sdv0z2fzmr-nix-2.9.1/.
I’m surprised how a lot of stuff is just bash’s own _longopt man-page-scraping hack.
I’m going to go poke at my Debian machine and see what other programs are completed differently. I mean … something must be different because I started this rabbit hole of thinking about completion quality because I was trying on nixos… I can’t remember the last time I cared about (or learned so much about) completion
I’ll reply to some of the other comments in a bit (thanks everyone)… just wanted to share this tiny bit of progress.
whoa, thanks a lot for finding this! this is very much a mystery I wanted to solve. I unfortunately never thought to read the system-rc scripts because I somehow had the notion they’re be skipped if a user’s own rc is defined. (I think I just assumed it was “magic, elsewhere” that was giving default behaviors )
tl;dr I’m more convinced that I was just confused and maybe nothing’s broken; will get back about comparing with my non-nixos machine to see if there’s anything interesting to share+learn there.
Okay so I’ve learned some things worth sharing… at least for future-me:
my gradle completion is working (I don’t know why it didn’t work on my previous test).
some things I thought were broken were just fzf’s over-zelous completion script (complete -p less outputs fzf function now instead of _longopts; it seemed broken because fzf’s func only completes filenames now so CLI flags that _longopts revealed have disappeared).
there’s a lot of completion scripts installed by nix packages in the places @ericgundrum revealed. See script and sample outputs below. This was quite interesting to me.
Thanks for sticking with me TLATER (and everyone) despite my tail-chasing - I’ve learned a bunch.
inspecting installed completions
Following up on ericgundrum’s hint, here’s some interesting output show that a lot of packages indeed reveal their completion sources via $XDG_DATA_DIRS’s subpaths.
quick forloop to inspect with
here's a tiny script that searches the $XDG_DATA_DIRS and $NIX_PROFILES subpaths
#!/usr/bin/env bash
function listColonDelimitedMembers() { echo "$1" | sed --expression 's,:,\n,g'; }
# per helpful comment here:
# https://discourse.nixos.org/t/whats-the-nix-way-of-bash-completion-for-packages/20209/12
#
# Lists all paths existing system-wide Bash scripts (at least on nixos) will
# look for bash-completion scripts (and _source_ those scripts) before user's
# settings are invoked.
function listPotentialCompletionPaths() {
# use printf-overloading atop bash's word-splitting
printf 'NIX_PROFILES %s/etc/bash_completion.d\n' $NIX_PROFILES
# These paths _maybe_ even applicable outside nixos.
listColonDelimitedMembers "$XDG_DATA_DIRS" |
sed --regexp-extended \
--expression 's,^,XDG_DATA_DIRS ,' \
--expression 's,/?$,/bash-completion/completions,g'
}
while read src dir; do
if [[ ! -e "$dir" ]]; then
# printf 'SKIPPING $%s-entry:\t%s\n\n' "$src" "$dir"
continue
fi
printf 'LISTING extant $%s-dir:\t%s\n\t\t%s\n' \
"$src" "$dir" "$(readlink --canonicalize "$dir")"
find -L "$dir" -mindepth 1 -maxdepth 1 -type f -printf '%P\n' |
sort |
column
echo
done < <(listPotentialCompletionPaths | sort | uniq)
contents of /etc/nixos/configuration.nix providing said packages
here's the system config file with "always-installed programs" I mentioned
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).
{ config, pkgs, ... }:
{
imports =
[ # Include the results of the hardware scan.
./hardware-configuration.nix
];
# Bootloader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
boot.loader.efi.efiSysMountPoint = "/boot/efi";
# Setup keyfile
boot.initrd.secrets = {
"/crypto_keyfile.bin" = null;
};
# Enable swap on luks
boot.initrd.luks.devices."luks-my-disk-uuid-was-here".device = "/dev/disk/by-uuid/my-disk-uuid-was-here";
boot.initrd.luks.devices."luks-my-disk-uuid-was-here".keyFile = "/crypto_keyfile.bin";
networking.hostName = "nixos"; # Define your hostname.
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
# Configure network proxy if necessary
# networking.proxy.default = "http://user:password@proxy:port/";
# networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
# Enable networking
networking.networkmanager.enable = true;
# Set your time zone.
time.timeZone = "America/New_York";
# Select internationalisation properties.
i18n.defaultLocale = "en_US.utf8";
# Enable the X11 windowing system.
services.xserver.enable = true;
# Enable the GNOME Desktop Environment.
services.xserver.displayManager.gdm.enable = true;
services.xserver.desktopManager.gnome.enable = true;
# Configure keymap in X11
services.xserver = {
layout = "us";
xkbVariant = "";
};
# Enable CUPS to print documents.
services.printing.enable = true;
# Enable sound with pipewire.
sound.enable = true;
hardware.pulseaudio.enable = false;
security.rtkit.enable = true;
services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
# If you want to use JACK applications, uncomment this
#jack.enable = true;
# use the example session manager (no others are packaged yet so this is enabled by default,
# no need to redefine it in your config for now)
#media-session.enable = true;
};
# Enable touchpad support (enabled default in most desktopManager).
# services.xserver.libinput.enable = true;
# Define a user account. Don't forget to set a password with ‘passwd’.
users.users.qsu = {
isNormalUser = true;
description = "qsu";
extraGroups = [ "networkmanager" "wheel" ];
packages = with pkgs; [
firefox
# thunderbird
deno
sassc
inotify-tools
zathura
thunderbird
bitwarden-cli
nethack
feh
syncthing
exiftool
tmux
fzf
valgrind
deno
go
youtube-dl
colordiff
rustc
rustfmt
cargo
clippy
rusty-man
rls
];
};
# Allow unfree packages
nixpkgs.config.allowUnfree = true;
# List packages installed in system profile. To search, run:
# $ nix search wget
environment.systemPackages = with pkgs; [
# vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
# wget
curl
git
alacritty
nano
bitwarden
keepassxc
bash-completion
bashInteractive
nix-bash-completions
neovim
corefonts
];
# Some programs need SUID wrappers, can be configured further or are
# started in user sessions.
# programs.mtr.enable = true;
# programs.gnupg.agent = {
# enable = true;
# enableSSHSupport = true;
# };
# List services that you want to enable:
# Enable the OpenSSH daemon.
# services.openssh.enable = true;
# Open ports in the firewall.
# networking.firewall.allowedTCPPorts = [ ... ];
# networking.firewall.allowedUDPPorts = [ ... ];
# Or disable the firewall altogether.
# networking.firewall.enable = false;
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. It‘s perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "22.05"; # Did you read the comment?
}
Also, ha! just checked my previous (non-nix) daily laptop: nope nvim doesn’t complete there either … no idea how I became convinced it did. Anyway… this is has still been educational!