1# This module provides suggestions of packages to install if the user
2# tries to run a missing command in Bash. This is implemented using a
3# SQLite database that maps program names to Nix package names (e.g.,
4# "pdflatex" is mapped to "tetex").
5
6{ config, lib, pkgs, ... }:
7
8let
9 cfg = config.programs.command-not-found;
10 commandNotFound = pkgs.substituteAll {
11 name = "command-not-found";
12 dir = "bin";
13 src = ./command-not-found.pl;
14 isExecutable = true;
15 inherit (cfg) dbPath;
16 perl = pkgs.perl.withPackages (p: [ p.DBDSQLite p.StringShellQuote ]);
17 };
18
19in
20
21{
22 options.programs.command-not-found = {
23
24 enable = lib.mkOption {
25 type = lib.types.bool;
26 default = true;
27 description = ''
28 Whether interactive shells should show which Nix package (if
29 any) provides a missing command.
30 '';
31 };
32
33 dbPath = lib.mkOption {
34 default = "/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite" ;
35 description = ''
36 Absolute path to programs.sqlite.
37
38 By default this file will be provided by your channel
39 (nixexprs.tar.xz).
40 '';
41 type = lib.types.path;
42 };
43 };
44
45 config = lib.mkIf cfg.enable {
46 programs.bash.interactiveShellInit =
47 ''
48 # This function is called whenever a command is not found.
49 command_not_found_handle() {
50 local p='${commandNotFound}/bin/command-not-found'
51 if [ -x "$p" ] && [ -f '${cfg.dbPath}' ]; then
52 # Run the helper program.
53 "$p" "$@"
54 # Retry the command if we just installed it.
55 if [ $? = 126 ]; then
56 "$@"
57 else
58 return 127
59 fi
60 else
61 echo "$1: command not found" >&2
62 return 127
63 fi
64 }
65 '';
66
67 programs.zsh.interactiveShellInit =
68 ''
69 # This function is called whenever a command is not found.
70 command_not_found_handler() {
71 local p='${commandNotFound}/bin/command-not-found'
72 if [ -x "$p" ] && [ -f '${cfg.dbPath}' ]; then
73 # Run the helper program.
74 "$p" "$@"
75
76 # Retry the command if we just installed it.
77 if [ $? = 126 ]; then
78 "$@"
79 else
80 return 127
81 fi
82 else
83 # Indicate than there was an error so ZSH falls back to its default handler
84 echo "$1: command not found" >&2
85 return 127
86 fi
87 }
88 '';
89
90 environment.systemPackages = [ commandNotFound ];
91 };
92
93}