Kieran's opinionated (and probably slightly dumb) nix config
1{
2 lib,
3 config,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.atelier.apps.tuigreet;
9 tuigreetBin = "${pkgs.greetd.tuigreet}/bin/tuigreet";
10 msg = cfg.greeting;
11 baseArgs =
12 [ ]
13 ++ lib.optionals cfg.time [ "--time" ]
14 ++ lib.optionals cfg.issue [ "--issue" ]
15 ++ lib.optionals (msg != null && msg != "") [
16 "-g"
17 msg
18 ]
19 ++ lib.optionals (cfg.timeFormat != null) [
20 "--time-format"
21 cfg.timeFormat
22 ]
23 ++ lib.optionals (cfg.width != null) [
24 "--width"
25 (toString cfg.width)
26 ]
27 ++ lib.optionals (cfg.theme != null) [
28 "--theme"
29 cfg.theme
30 ]
31 ++ lib.optionals cfg.asterisks [ "--asterisks" ]
32 ++ lib.optionals (cfg.asterisksChar != null) [
33 "--asterisks-char"
34 cfg.asterisksChar
35 ]
36 ++ lib.optionals (cfg.windowPadding != null) [
37 "--window-padding"
38 (toString cfg.windowPadding)
39 ]
40 ++ lib.optionals (cfg.containerPadding != null) [
41 "--container-padding"
42 (toString cfg.containerPadding)
43 ]
44 ++ lib.optionals (cfg.promptPadding != null) [
45 "--prompt-padding"
46 (toString cfg.promptPadding)
47 ]
48 ++ lib.optionals (cfg.greetAlign != null) [
49 "--greet-align"
50 cfg.greetAlign
51 ]
52 ++ lib.optionals cfg.remember [ "--remember" ]
53 ++ lib.optionals cfg.rememberSession [ "--remember-session" ]
54 ++ lib.optionals cfg.rememberUserSession [ "--remember-user-session" ]
55 ++ lib.optionals cfg.userMenu [ "--user-menu" ]
56 ++ lib.optionals (cfg.userMenuMinUid != null) [
57 "--user-menu-min-uid"
58 (toString cfg.userMenuMinUid)
59 ]
60 ++ lib.optionals (cfg.userMenuMaxUid != null) [
61 "--user-menu-max-uid"
62 (toString cfg.userMenuMaxUid)
63 ]
64 ++ lib.concatMap (e: [
65 "--env"
66 e
67 ]) cfg.env
68 ++ lib.optionals (cfg.sessions != null && cfg.sessions != [ ]) [
69 "--sessions"
70 (lib.concatStringsSep ":" cfg.sessions)
71 ]
72 ++ lib.optionals (cfg.xsessions != null && cfg.xsessions != [ ]) [
73 "--xsessions"
74 (lib.concatStringsSep ":" cfg.xsessions)
75 ]
76 ++ lib.optionals (cfg.sessionWrapper != null && cfg.sessionWrapper != [ ]) [
77 "--session-wrapper"
78 (lib.escapeShellArg (lib.concatStringsSep " " cfg.sessionWrapper))
79 ]
80 ++ lib.optionals (cfg.xsessionWrapper != null && cfg.xsessionWrapper != [ ]) [
81 "--xsession-wrapper"
82 (lib.escapeShellArg (lib.concatStringsSep " " cfg.xsessionWrapper))
83 ]
84 ++ lib.optionals cfg.noXsessionWrapper [ "--no-xsession-wrapper" ]
85 ++ lib.optionals (cfg.powerShutdown != null && cfg.powerShutdown != [ ]) [
86 "--power-shutdown"
87 (lib.escapeShellArg (lib.concatStringsSep " " cfg.powerShutdown))
88 ]
89 ++ lib.optionals (cfg.powerReboot != null && cfg.powerReboot != [ ]) [
90 "--power-reboot"
91 (lib.escapeShellArg (lib.concatStringsSep " " cfg.powerReboot))
92 ]
93 ++ lib.optionals cfg.powerNoSetsid [ "--power-no-setsid" ]
94 ++ lib.optionals (cfg.kbCommand != null) [
95 "--kb-command"
96 (toString cfg.kbCommand)
97 ]
98 ++ lib.optionals (cfg.kbSessions != null) [
99 "--kb-sessions"
100 (toString cfg.kbSessions)
101 ]
102 ++ lib.optionals (cfg.kbPower != null) [
103 "--kb-power"
104 (toString cfg.kbPower)
105 ]
106 ++ cfg.extraArgs;
107 cmd = lib.concatStringsSep " " (
108 [ tuigreetBin ]
109 ++ baseArgs
110 ++ [
111 "--cmd"
112 cfg.command
113 ]
114 ++ lib.optional (cfg.debugFile != null) ("--debug " + cfg.debugFile)
115 );
116in
117{
118 options.atelier.apps.tuigreet = {
119 enable = lib.mkEnableOption "Enable greetd with tuigreet";
120
121 command = lib.mkOption {
122 type = lib.types.str;
123 default = "Hyprland";
124 description = "Command to launch after login (e.g., Hyprland, niri, sway, etc.)";
125 };
126
127 extraArgs = lib.mkOption {
128 type = lib.types.listOf lib.types.str;
129 default = [ ];
130 description = "Extra arguments passed to tuigreet (appended).";
131 };
132
133 greeting = lib.mkOption {
134 type = lib.types.nullOr lib.types.str;
135 default = "WARNING: UNAUTHORIZED ACCESS WILL RESULT IN TERMINATION OF SESSION. IDENTIFY YOURSELF";
136 description = "Greeting text shown above login prompt (-g/--greeting).";
137 };
138
139 time = lib.mkOption {
140 type = lib.types.bool;
141 default = true;
142 description = "Show time";
143 };
144 issue = lib.mkOption {
145 type = lib.types.bool;
146 default = false;
147 description = "Show /etc/issue";
148 };
149 timeFormat = lib.mkOption {
150 type = lib.types.nullOr lib.types.str;
151 default = null;
152 };
153 width = lib.mkOption {
154 type = lib.types.nullOr lib.types.ints.positive;
155 default = null;
156 };
157 theme = lib.mkOption {
158 type = lib.types.nullOr lib.types.str;
159 default = null;
160 };
161 asterisks = lib.mkOption {
162 type = lib.types.bool;
163 default = false;
164 };
165 asterisksChar = lib.mkOption {
166 type = lib.types.nullOr lib.types.str;
167 default = null;
168 };
169 windowPadding = lib.mkOption {
170 type = lib.types.nullOr lib.types.ints.unsigned;
171 default = null;
172 };
173 containerPadding = lib.mkOption {
174 type = lib.types.nullOr lib.types.ints.unsigned;
175 default = null;
176 };
177 promptPadding = lib.mkOption {
178 type = lib.types.nullOr lib.types.ints.unsigned;
179 default = null;
180 };
181 greetAlign = lib.mkOption {
182 type = lib.types.nullOr (
183 lib.types.enum [
184 "left"
185 "center"
186 "right"
187 ]
188 );
189 default = null;
190 };
191
192 remember = lib.mkOption {
193 type = lib.types.bool;
194 default = true;
195 };
196 rememberSession = lib.mkOption {
197 type = lib.types.bool;
198 default = false;
199 };
200 rememberUserSession = lib.mkOption {
201 type = lib.types.bool;
202 default = false;
203 };
204 userMenu = lib.mkOption {
205 type = lib.types.bool;
206 default = false;
207 };
208 userMenuMinUid = lib.mkOption {
209 type = lib.types.nullOr lib.types.ints.positive;
210 default = null;
211 };
212 userMenuMaxUid = lib.mkOption {
213 type = lib.types.nullOr lib.types.ints.positive;
214 default = null;
215 };
216
217 env = lib.mkOption {
218 type = lib.types.listOf lib.types.str;
219 default = [ ];
220 };
221 sessions = lib.mkOption {
222 type = lib.types.listOf lib.types.str;
223 default = [ ];
224 };
225 xsessions = lib.mkOption {
226 type = lib.types.listOf lib.types.str;
227 default = [ ];
228 };
229
230 sessionWrapper = lib.mkOption {
231 type = lib.types.listOf lib.types.str;
232 default = [ ];
233 };
234 xsessionWrapper = lib.mkOption {
235 type = lib.types.listOf lib.types.str;
236 default = [ ];
237 };
238 noXsessionWrapper = lib.mkOption {
239 type = lib.types.bool;
240 default = false;
241 };
242
243 powerShutdown = lib.mkOption {
244 type = lib.types.listOf lib.types.str;
245 default = [ ];
246 };
247 powerReboot = lib.mkOption {
248 type = lib.types.listOf lib.types.str;
249 default = [ ];
250 };
251 powerNoSetsid = lib.mkOption {
252 type = lib.types.bool;
253 default = false;
254 };
255
256 kbCommand = lib.mkOption {
257 type = lib.types.nullOr (lib.types.ints.between 1 12);
258 default = null;
259 };
260 kbSessions = lib.mkOption {
261 type = lib.types.nullOr (lib.types.ints.between 1 12);
262 default = null;
263 };
264 kbPower = lib.mkOption {
265 type = lib.types.nullOr (lib.types.ints.between 1 12);
266 default = null;
267 };
268
269 debugFile = lib.mkOption {
270 type = lib.types.nullOr lib.types.str;
271 default = null;
272 };
273 };
274
275 config = lib.mkIf cfg.enable {
276 services.greetd = {
277 enable = true;
278 settings = {
279 default_session = {
280 command = cmd;
281 user = "greeter";
282 };
283 };
284 };
285
286 systemd.services.greetd.serviceConfig = {
287 Type = "idle";
288 StandardInput = "tty";
289 StandardOutput = "tty";
290 StandardError = "journal";
291 TTYReset = true;
292 TTYVHangup = true;
293 TTYVTDisallocate = true;
294 };
295 };
296}