Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Command-not-found utility for fish #126

Open
anka-213 opened this issue Aug 8, 2020 · 3 comments · May be fixed by #227
Open

Command-not-found utility for fish #126

anka-213 opened this issue Aug 8, 2020 · 3 comments · May be fixed by #227

Comments

@anka-213
Copy link
Contributor

anka-213 commented Aug 8, 2020

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

function __fish_command_not_found_handler --on-event fish_command_not_found
	/path/to/command-not-found $argv
end

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:

#!/usr/bin/env bash

source /nix/store/kk3d66hmjxsn32qdnak6p7w8s77gig8r-nix-index-0.1.2/etc/profile.d/command-not-found.sh

command_not_found_handle $@

but this version is extremely fragile and should be nixified.

@kamaln7
Copy link

kamaln7 commented Jan 20, 2021

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.

@malob
Copy link

malob commented Feb 1, 2021

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

@lilyball
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants