Open anka-213 opened 3 years ago
Thanks @anka-213! The function:
function __fish_command_not_found_handler --on-event fish_command_not_found
/path/to/command-not-found $argv
end
can be added to either ~/.config/fish/config.fish
or in its own file at ~/.config/fish/functions/any_name_you_want.fish
. I use home-manager to manage my homedir, like this:
user: { pkgs, ... }:
{
home-manager.users."${user}" = {
# ...
home.file = {
".config" = {
source = ../../dotfiles/.config;
recursive = true;
};
"bin/nix-command-not-found" = {
text = ''
#!/usr/bin/env bash
source ${pkgs.nix-index}/etc/profile.d/command-not-found.sh
command_not_found_handle "$@"
'';
executable = true;
};
# ...
};
};
}
The ../../dotfiles/.config
path references the .config
directory in my git repo where I keep my nix config. I have the function in .config/fish/functions/command_not_found.fish
:
function __fish_command_not_found_handler --on-event fish_command_not_found
~/bin/command-not-found $argv
end
I also added nix-index
to the system packages in environment.systemPackages
.
I'm using a similar workaround right now. It would be nice if nix-index
provided a native Fish version though. Maybe the easiest way would be to use Babelfish? Version 1.1.0, works on command-not-found.sh
. Here's the output from Babelfish, with the first line changed to have the correct function name and event handler, and @out@
substituted back in instead of the store path for nix-index
.
function __fish_command_not_found_handler --on-event fish_command_not_found
# TODO: use "command not found" gettext translations
# taken from http://www.linuxjournal.com/content/bash-command-not-found
# - do not run when inside Midnight Commander or within a Pipe
if [ -n "$MC_SID" ] || ! [ -t 1 ]
echo $argv[1]': command not found' >&2
return 127
end
# nixpkgs should always be available even in NixOS
set toplevel 'nixpkgs'
set cmd $argv[1]
set attrs (@out@/bin/nix-locate --minimal --no-group --type x --type s --top-level --whole-name --at-root '/bin/'"$cmd" | string collect; or echo)
set len (echo -n "$attrs" | grep -c '^' | string collect; or echo)
switch "$len"
case '0'
echo "$cmd"': command not found' >&2
case '1'
# if only 1 package provides this, then we can invoke it
# without asking the users if they have opted in with one
# of 2 environment variables
# they are based on the ones found in
# command-not-found.sh:
# NIX_AUTO_INSTALL : install the missing command into the
# user’s environment
# NIX_AUTO_RUN : run the command transparently inside of
# nix shell
# these will not return 127 if they worked correctly
if ! [ -z "$NIX_AUTO_INSTALL" ]
cat >&2 <(echo 'The program \''"$cmd"'\' is currently not installed. It is provided by
the package \''"$toplevel"'.'"$attrs"'\', which I will now install for you.
'| psub)
nix-env -iA $toplevel.$attrs
if [ "$status" -eq 0 ]
# TODO: handle pipes correctly if AUTO_RUN/INSTALL is possible
$argv
return $status
else
cat >&2 <(echo 'Failed to install '"$toplevel"'.attrs.
'"$cmd"': command not found
'| psub)
end
else if ! [ -z "$NIX_AUTO_RUN" ]
nix-build --no-out-link -A $attrs '<'"$toplevel"'>'
if [ "$status" -eq 0 ]
# how nix-shell handles commands is weird
# $(echo $@) is need to handle this
nix-shell -p $attrs --run (echo $argv | string collect; or echo)
return $status
else
cat >&2 <(echo 'Failed to install '"$toplevel"'.attrs.
'"$cmd"': command not found
'| psub)
end
else
cat >&2 <(echo 'The program \''"$cmd"'\' is currently not installed. You can install it
by typing:
nix-env -iA '"$toplevel"'.'"$attrs"'
'| psub)
end
case '*'
cat >&2 <(echo 'The program \''"$cmd"'\' is currently not installed. It is provided by
several packages. You can install it by typing one of the following:
'| psub)
# ensure we get each element of attrs
# in a cross platform way
while read attr
echo ' nix-env -iA '"$toplevel"'.'"$attr" >&2
end <(echo "$attrs"| psub)
end
# command not found should always exit with 127
return 127
end
nixpkgs packages babelfish
as a package. NixOS has a programs.fish.useBabelfish
option that makes it uses babelfish instead of fish-foreign-env for translating its init scripts as well, which is good precedent. It seems reasonable to me to have your default.nix
use nixpkgs.babelfish
to translate the command-not-found handler.
Here's an example of the corresponding function for nixos' command-not-found program. https://github.com/beatgammit/fish-shell/blob/793784c08778e8b3fb9d8a2a5621bd968db1dfbe/share/functions/__fish_config_interactive.fish#L229-L231
I'm not entirely sure where the function should be placed and if it should have a different name though.
I made a wrapper for the shell script to create an executable for fish to run:
but this version is extremely fragile and should be nixified.