How do I enable zsh package suggestions as in Ubuntu bash?

I'm slowly transitioning to zsh from bash and am loving almost every part of it, but there are two things I'm really missing. One of them is snap completions, see here: Enable snap TAB-completion for zsh

The other is that sort of thing where you type a command into the Ubuntu terminal and instead of going 'oh no! command not found!' right away, you get something like this:

user@computer:~$ inkscape

Command 'inkscape' not found, but can be installed with:

sudo snap install inkscape  # version 0.92.4, or
sudo apt  install inkscape  # version 0.92.4-5ubuntu5

See 'snap info inkscape' for additional versions.

Is there some way to enable this in zsh? I really would like to stop having to switch back to bash just to use this and snap autocompletion.

Thanks!


Solution 1:

For apt package suggestions we may do it with following:

$ sudo apt install command-not-found
$ echo "source /etc/zsh_command_not_found" >> ~/.zshrc
$ exec zsh

Solution 2:

The magic happens under the hood in bash using a function called command_not_found_handle:

$ declare -f command_not_found_handle
command_not_found_handle () 
{ 
    if [ -x /usr/lib/command-not-found ]; then
        /usr/lib/command-not-found -- "$1";
        return $?;
    else
        if [ -x /usr/share/command-not-found/command-not-found ]; then
            /usr/share/command-not-found/command-not-found -- "$1";
            return $?;
        else
            printf "%s: command not found\n" "$1" 1>&2;
            return 127;
        fi;
    fi
}

zsh has a very similarly named command_not_found_handler:

  • Intercept “command not found” error in zsh

which (at least in my 18.04 installation) appears to be unset by default. Although there may be better solutions, I don't see any reason why you shouldn't simply copy the bash function to zsh (with an appropriate change of name of course):

command_not_found_handler () {
    if [ -x /usr/lib/command-not-found ]
    then
        /usr/lib/command-not-found -- "$1"
        return $?
    else
        if [ -x /usr/share/command-not-found/command-not-found ]
        then
            /usr/share/command-not-found/command-not-found -- "$1"
            return $?
        else
            printf "%s: command not found\n" "$1" >&2
            return 127
        fi
    fi
}

You can place the definition in your ~/.zshrc or other appropriate initialization file.

Solution 3:

if you are using oh-my-zsh, it comes with plugin called command-not-found, you can enable it by editing ~/.zshrc, add command-not-found in plugins list.

e.g. plugins=(command-not-found)