1{
2 lib,
3 config,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.programs.direnv;
9 enabledOption =
10 x:
11 lib.mkEnableOption x
12 // {
13 default = true;
14 example = false;
15 };
16 format = pkgs.formats.toml { };
17in
18{
19 options.programs.direnv = {
20
21 enable = lib.mkEnableOption ''
22 direnv integration. Takes care of both installation and
23 setting up the sourcing of the shell. Additionally enables nix-direnv
24 integration. Note that you need to logout and login for this change to apply
25 '';
26
27 package = lib.mkPackageOption pkgs "direnv" { };
28
29 finalPackage = lib.mkOption {
30 type = lib.types.package;
31 readOnly = true;
32 description = "The wrapped direnv package.";
33 };
34
35 enableBashIntegration = enabledOption ''
36 Bash integration
37 '';
38 enableZshIntegration = enabledOption ''
39 Zsh integration
40 '';
41 enableFishIntegration = enabledOption ''
42 Fish integration
43 '';
44 enableXonshIntegration = enabledOption ''
45 Xonsh integration
46 '';
47
48 direnvrcExtra = lib.mkOption {
49 type = lib.types.lines;
50 default = "";
51 example = ''
52 export FOO="foo"
53 echo "loaded direnv!"
54 '';
55 description = ''
56 Extra lines to append to the sourced direnvrc
57 '';
58 };
59
60 silent = lib.mkEnableOption ''
61 the hiding of direnv logging
62 '';
63
64 loadInNixShell = enabledOption ''
65 loading direnv in `nix-shell` `nix shell` or `nix develop`
66 '';
67
68 nix-direnv = {
69 enable = enabledOption ''
70 a faster, persistent implementation of use_nix and use_flake, to replace the builtin one
71 '';
72
73 package = lib.mkOption {
74 default = pkgs.nix-direnv.override { nix = config.nix.package; };
75 defaultText = "pkgs.nix-direnv";
76 type = lib.types.package;
77 description = ''
78 The nix-direnv package to use
79 '';
80 };
81 };
82
83 settings = lib.mkOption {
84 inherit (format) type;
85 default = { };
86 example = lib.literalExpression ''
87 {
88 global = {
89 log_format = "-";
90 log_filter = "^$";
91 };
92 }
93 '';
94 description = ''
95 Direnv configuration. Refer to {manpage}`direnv.toml(1)`.
96 '';
97 };
98 };
99
100 config = lib.mkIf cfg.enable {
101 programs = {
102 direnv = {
103 finalPackage = pkgs.symlinkJoin {
104 inherit (cfg.package) name;
105 paths = [ cfg.package ];
106 # direnv has a fish library which automatically sources direnv for some reason
107 postBuild = ''
108 rm -rf "$out/share/fish"
109 '';
110 meta.mainProgram = "direnv";
111 };
112 settings = lib.mkIf cfg.silent {
113 global = {
114 log_format = lib.mkDefault "-";
115 log_filter = lib.mkDefault "^$";
116 };
117 };
118 };
119
120 zsh.interactiveShellInit = lib.mkIf cfg.enableZshIntegration ''
121 if ${lib.boolToString cfg.loadInNixShell} || printenv PATH | grep -vqc '/nix/store'; then
122 eval "$(${lib.getExe cfg.finalPackage} hook zsh)"
123 fi
124 '';
125
126 #$NIX_GCROOT for "nix develop" https://github.com/NixOS/nix/blob/6db66ebfc55769edd0c6bc70fcbd76246d4d26e0/src/nix/develop.cc#L530
127 #$IN_NIX_SHELL for "nix-shell"
128 bash.interactiveShellInit = lib.mkIf cfg.enableBashIntegration ''
129 if ${lib.boolToString cfg.loadInNixShell} || [ -z "$IN_NIX_SHELL$NIX_GCROOT$(printenv PATH | grep '/nix/store')" ] ; then
130 eval "$(${lib.getExe cfg.finalPackage} hook bash)"
131 fi
132 '';
133
134 fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration ''
135 if ${lib.boolToString cfg.loadInNixShell}; or printenv PATH | grep -vqc '/nix/store';
136 ${lib.getExe cfg.finalPackage} hook fish | source
137 end
138 '';
139
140 xonsh = lib.mkIf cfg.enableXonshIntegration {
141 extraPackages = ps: [ ps.xonsh.xontribs.xonsh-direnv ];
142 config = ''
143 if ${
144 if cfg.loadInNixShell then
145 "True"
146 else
147 "not any(map(lambda s: s.startswith('/nix/store'), __xonsh__.env.get('PATH')))"
148 }:
149 xontrib load direnv
150 '';
151 };
152 };
153
154 environment = {
155 systemPackages = [
156 cfg.finalPackage
157 ];
158
159 variables.DIRENV_CONFIG = "/etc/direnv";
160
161 etc = {
162 "direnv/direnv.toml" = lib.mkIf (cfg.settings != { }) {
163 source = format.generate "direnv.toml" cfg.settings;
164 };
165 "direnv/direnvrc".text = ''
166 ${lib.optionalString cfg.nix-direnv.enable ''
167 #Load nix-direnv
168 source ${cfg.nix-direnv.package}/share/nix-direnv/direnvrc
169 ''}
170
171 #Load direnvrcExtra
172 ${cfg.direnvrcExtra}
173
174 #Load user-configuration if present (~/.direnvrc or ~/.config/direnv/direnvrc)
175 direnv_config_dir_home="''${DIRENV_CONFIG_HOME:-''${XDG_CONFIG_HOME:-$HOME/.config}/direnv}"
176 if [[ -f $direnv_config_dir_home/direnvrc ]]; then
177 source "$direnv_config_dir_home/direnvrc" >&2
178 elif [[ -f $HOME/.direnvrc ]]; then
179 source "$HOME/.direnvrc" >&2
180 fi
181
182 unset direnv_config_dir_home
183 '';
184
185 "direnv/lib/zz-user.sh".text = ''
186 direnv_config_dir_home="''${DIRENV_CONFIG_HOME:-''${XDG_CONFIG_HOME:-$HOME/.config}/direnv}"
187
188 for lib in "$direnv_config_dir_home/lib/"*.sh; do
189 source "$lib"
190 done
191
192 unset direnv_config_dir_home
193 '';
194 };
195 };
196 };
197 meta.maintainers = with lib.maintainers; [ gerg-l ];
198}