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