Skip to content

fish_command_not_found is undefined on macOS #7777

@gpanders

Description

@gpanders

Hello!

The new fish_command_not_found function in fish 3.2.0 doesn't seem to have a "default" value if none of the if branches match:

fish_command_not_found.fish:

# If an old handler already exists, defer to that.
if functions -q __fish_command_not_found_handler
    function fish_command_not_found
        # The fish_command_not_found event was removed in fish 3.2.0,
        # and future versions of fish will just call a function called "fish_command_not_found".
        # You have defined a custom handler, we suggest renaming it to "fish_command_not_found".
        __fish_command_not_found_handler $argv
    end
    # First check if we are on OpenSUSE since SUSE's handler has no options
    # but the same name and path as Ubuntu's.
else if contains -- suse $os || contains -- sles $os && type -q command-not-found
    # ...
    # Lots of 'else if' heuristics for different OS's
    # ...
else if type -q pacman
    function fish_command_not_found
        set -l paths $argv[1]
        # If we've not been given an absolute path, try $PATH as the starting point,
        # otherwise pacman will try *every path*, and e.g. bash-completion
        # isn't helpful.
        string match -q '/*' -- $argv[1]; or set paths $PATH/$argv[1]
        # Pacman only prints the path, so we still need to print the error.
        __fish_default_command_not_found_handler $argv[1]
        pacman -F $paths
    end
end

If none of these conditions match (which they don't on e.g. macOS), then fish_command_not_found doesn't work:

$ fish_command_not_found hi
fish: Unknown command: fish_command_not_found

(The irony of the 'Unknown command' for fish_command_not_found is amusing).

I would expect the fish_command_not_found function file to end with this:

...
else if type -q pacman
    function fish_command_not_found
        set -l paths $argv[1]
        # If we've not been given an absolute path, try $PATH as the starting point,
        # otherwise pacman will try *every path*, and e.g. bash-completion
        # isn't helpful.
        string match -q '/*' -- $argv[1]; or set paths $PATH/$argv[1]
        # Pacman only prints the path, so we still need to print the error.
        __fish_default_command_not_found_handler $argv[1]
        pacman -F $paths
    end
else
    function fish_command_not_found
        __fish_default_command_not_found_handler $argv[1]
    end
end

Is there a reason it's not done this way?

If it's helpful, I can provide the use case that led me to this problem. I have some functions defined that lazy-load other programs (i.e. ones that need to initialize the shell in some way before they can work properly, but I don't want to pay that initialization cost on every shell, just when I need to use it).

Example:

function conda -d "Lazy load conda"
    functions -e conda
    if command -sq conda
        source (command conda info --root)/etc/fish/conf.d/conda.fish
        conda $argv
    else
        if functions -q fish_command_not_found
            fish_command_not_found conda
        else
            __fish_default_command_not_found_handler conda
        end
        return 127
    end
end

If command -sq conda is false, I'd like to be able to just call fish_command_not_found conda, but this doesn't work for the reasons I pointed out above. Instead, I have to check for the existence of fish_command_not_found, and if it doesn't exist, fallback to __fish_default_command_not_found_handler, which is ugly, redundant, and relies on fish internals instead of using the proper abstractions.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions