-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
-
268
-
269
-
270
-
271
-
272
-
273
-
274
-
275
-
276
-
277
-
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
-
286
-
287
-
288
-
289
-
290
-
291
-
292
-
293
-
294
-
295
-
296
-
297
-
298
-
299
-
300
-
301
-
302
-
303
-
304
-
305
-
306
-
307
-
308
-
309
-
310
-
311
-
312
-
313
-
314
-
315
-
316
-
317
-
318
-
319
-
320
-
321
-
322
-
323
-
324
-
325
-
326
-
327
-
328
-
329
-
330
-
331
-
332
-
333
-
334
-
335
-
336
-
337
-
338
-
339
-
340
-
341
-
342
-
343
-
344
-
345
-
346
-
347
-
348
-
349
-
350
-
351
-
352
-
353
-
354
-
355
-
356
-
357
-
358
-
359
-
360
-
361
-
362
-
363
-
364
-
365
-
366
-
367
-
368
-
369
-
370
-
371
-
372
-
373
-
374
-
375
-
376
-
377
-
378
-
379
-
380
-
381
-
382
-
383
-
384
-
385
-
386
-
387
-
388
-
389
-
390
-
391
-
392
-
393
-
394
-
395
-
396
-
397
-
398
-
399
-
400
-
401
-
402
-
403
-
404
-
405
-
406
-
407
-
408
-
409
-
410
-
411
-
412
-
413
-
414
-
415
-
416
-
417
-
418
-
419
-
420
-
421
-
422
-
423
-
424
-
425
-
426
-
427
-
428
-
429
-
430
-
431
-
432
-
433
-
434
-
435
-
436
-
437
-
438
-
439
-
440
-
441
-
442
-
443
-
444
-
445
-
446
-
447
-
448
-
449
-
450
-
451
-
452
-
453
-
454
-
455
-
456
-
457
-
458
-
459
-
460
-
461
-
462
-
463
-
464
-
465
-
466
-
467
-
468
-
469
-
470
-
471
-
472
-
473
-
474
-
475
-
476
-
477
-
478
-
479
-
480
-
481
-
482
-
483
-
484
-
485
-
486
-
487
-
488
-
489
-
490
-
491
-
492
-
493
-
494
-
495
-
496
-
497
-
498
-
499
-
500
-
501
-
502
-
503
-
504
-
505
-
506
-
507
-
508
-
509
-
510
-
511
-
512
-
513
-
514
-
515
-
516
-
517
-
518
-
519
-
520
-
521
-
522
-
523
-
524
-
525
-
526
-
527
-
528
-
529
-
530
-
531
-
532
-
533
-
534
-
535
-
536
-
537
-
538
-
539
-
540
-
541
-
542
-
543
-
544
-
545
-
546
-
547
-
548
-
549
-
550
-
551
-
552
-
553
-
554
-
555
-
556
-
557
-
558
-
559
-
560
-
561
-
562
-
563
-
564
-
565
-
566
-
567
-
568
-
569
-
570
-
571
-
572
-
573
-
574
-
575
-
576
-
577
-
578
-
579
-
580
-
581
-
582
-
583
-
584
-
585
-
586
-
587
-
588
-
589
-
590
-
591
-
592
-
593
-
594
-
595
-
596
-
597
-
598
-
599
-
600
-
601
-
602
-
603
-
604
-
605
-
606
-
607
-
608
-
609
-
610
-
611
-
612
-
613
-
614
-
615
-
616
-
617
-
618
-
619
-
620
-
621
-
622
-
623
-
624
-
625
-
626
-
627
-
628
-
629
-
630
-
631
-
632
-
633
-
634
-
635
-
636
-
637
-
638
-
639
-
640
-
641
-
642
-
643
-
644
-
645
-
646
-
647
-
648
-
649
-
650
-
651
-
652
-
653
-
654
-
655
-
656
-
657
-
658
-
659
-
660
-
661
-
662
-
663
-
664
-
665
-
666
-
667
-
668
-
669
-
670
-
671
-
672
-
673
-
674
-
675
-
676
-
677
-
678
-
679
-
680
-
681
-
682
-
683
-
684
-
685
-
686
-
687
-
688
-
689
-
690
-
691
{ config, lib, pkgs, ... }:
let
cfg = config.features.wayland-de.tofi;
directionalValue = lib.types.either
lib.types.int
(lib.types.submodule {
options = {
top = lib.mkOption {
type = lib.types.int;
default = 0;
};
right = lib.mkOption {
type = lib.types.int;
default = 0;
};
bottom = lib.mkOption {
type = lib.types.int;
default = 0;
};
left = lib.mkOption {
type = lib.types.int;
default = 0;
};
};
});
percentageValue = lib.types.either
lib.types.ints.unsigned
lib.types.nonEmptyStr;
directionalValueToString = v:
if lib.isInt v then
builtins.toString v
else
with builtins; "${toString v.top}, ${toString v.right}, ${toString v.bottom}, ${toString v.left}";
in
{
options = {
features.wayland-de.tofi = {
textCursor = lib.mkOption {
description = "Show a text cursor in the input field.";
type = lib.types.nullOr lib.types.bool;
default = null;
};
history = lib.mkOption {
description = ''
Sort results by number of usages.
By default, this is only effective in the run and drun modes - see the history-file option for more information.
'';
type = lib.types.nullOr lib.types.bool;
default = null;
};
historyFile = lib.mkOption {
description = ''
Specify an alternate file to read and store history information from / to.
This shouldn't normally be needed, and is intended to facilitate the creation of custom modes.
The default value depends on the current mode.
'';
type = lib.types.nullOr lib.types.bool;
default = null;
};
fuzzyMatch = lib.mkOption {
description = ''
If true, searching is performed via a simple fuzzy matching algorithm.
If false, substring matching is used, weighted to favour matches closer to the beginning of the string.
'';
type = lib.types.nullOr lib.types.bool;
default = null;
};
font = {
family = lib.mkOption {
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
size = lib.mkOption {
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
variations = lib.mkOption {
description = ''
List of OpenType font variation settings to apply.
The format is similar to the CSS "font-variation-settings" property.
For example, "wght 900" will set the weight of a variable font to 900 (if supported by the chosen font).
'';
type = lib.types.nullOr (lib.types.listOf lib.types.nonEmptyStr);
default = null;
};
};
backgroundColor = lib.mkOption {
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
outline = {
width = lib.mkOption {
description = ''
Width of the border outlines.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
color = lib.mkOption {
description = ''
Color of the border outlines.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
};
border = {
width = lib.mkOption {
description = ''
Width of the border.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
color = lib.mkOption {
description = ''
Color of the border.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
};
textColor = lib.mkOption {
description = ''
Color of text.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
prompt = {
text = lib.mkOption {
description = ''
Prompt text.
'';
type = lib.types.nullOr lib.types.str;
default = null;
};
padding = lib.mkOption {
description = ''
Extra horizontal padding between prompt and input.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
color = lib.mkOption {
description = ''
Color of prompt text.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
background = lib.mkOption {
description = ''
Background color of prompt.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
backgroundPadding = lib.mkOption {
description = ''
Extra padding of the prompt background.
'';
type = lib.types.nullOr directionalValue;
default = null;
};
backgroundCornerRadius = lib.mkOption {
description = ''
Corner radius of the prompt background.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
};
placeholder = {
text = lib.mkOption {
description = ''
Placeholder input text.
'';
type = lib.types.nullOr lib.types.str;
default = null;
};
color = lib.mkOption {
description = ''
Color of placeholder input text.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
background = lib.mkOption {
description = ''
Background color of placeholder input text.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
backgroundPadding = lib.mkOption {
description = ''
Extra padding of the placeholder input text background.
'';
type = lib.types.nullOr directionalValue;
default = null;
};
backgroundCornerRadius = lib.mkOption {
description = ''
Corner radius of the placeholder input text background.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
};
input = {
color = lib.mkOption {
description = ''
Color of input text.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
background = lib.mkOption {
description = ''
Background color of input text.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
backgroundPadding = lib.mkOption {
description = ''
Extra padding of the input text background.
'';
type = lib.types.nullOr directionalValue;
default = null;
};
backgroundCornerRadius = lib.mkOption {
description = ''
Corner radius of the input text background.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
};
defaultResult = {
color = lib.mkOption {
description = ''
Default color of result text.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
background = lib.mkOption {
description = ''
Default background color of results.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
backgroundPadding = lib.mkOption {
description = ''
Default extra padding of result backgrounds.
'';
type = lib.types.nullOr directionalValue;
default = null;
};
backgroundCornerRadius = lib.mkOption {
description = ''
Default corner radius of result backgrounds.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
};
alternateResult = {
color = lib.mkOption {
description = ''
Color of alternate (even-numbered) result text.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
background = lib.mkOption {
description = ''
Background color of alternate (even-numbered) results.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
backgroundPadding = lib.mkOption {
description = ''
Extra padding of alternate (even-numbered) result backgrounds.
'';
type = lib.types.nullOr directionalValue;
default = null;
};
backgroundCornerRadius = lib.mkOption {
description = ''
Corner radius of alternate (even-numbered) result backgrounds.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
};
numResults = lib.mkOption {
description = ''
Maximum number of results to display.
If n = 0, tofi will draw as many results as it can fit in the window.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
selection = {
color = lib.mkOption {
description = ''
Color of selected result.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
matchColor = lib.mkOption {
description = ''
Color of the matching portion of the selected result.
This will not always be shown if the fuzzy-match option is set to true.
Any color that is fully transparent (alpha = 0) will disable this highlighting.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
background = lib.mkOption {
description = ''
Background color of selected result.
'';
type = lib.types.nullOr lib.types.nonEmptyStr;
default = null;
};
backgroundPadding = lib.mkOption {
description = ''
Extra padding of the selected result background.
'';
type = lib.types.nullOr directionalValue;
default = null;
};
backgroundCornerRadius = lib.mkOption {
description = ''
Corner radius of the selected result background.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
};
resultSpacing = lib.mkOption {
description = ''
Spacing between results. Can be negative.
'';
type = lib.types.nullOr lib.types.int;
default = null;
};
minInputWidth = lib.mkOption {
description = ''
Minimum width of input in horizontal mode.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
width = lib.mkOption {
description = ''
Width of the window.
'';
type = lib.types.nullOr percentageValue;
default = null;
};
height = lib.mkOption {
description = ''
Height of the window.
'';
type = lib.types.nullOr percentageValue;
default = null;
};
cornerRadius = lib.mkOption {
description = ''
Radius of the window corners.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
anchor = lib.mkOption {
description = ''
Location on screen to anchor the window.
'';
type = lib.types.nullOr (lib.types.enum [
"top-left"
"top"
"top-right"
"bottom-left"
"bottom"
"bottom-right"
"right"
"left"
"center"
]);
default = null;
};
exclusiveZone = lib.mkOption {
description = ''
Set the size of the exclusive zone.
A value of -1 means ignore exclusive zones completely.
A value of 0 will move tofi out of the way of other windows' exclusive zones.
A value greater than 0 will set that much space as an exclusive zone.
Values greater than 0 are only meaningful when tofi is anchored to a single edge.
'';
type = lib.types.nullOr (lib.types.either lib.types.int lib.types.nonEmptyStr);
default = null;
};
output = lib.mkOption {
description = ''
The name of the output to appear on, if multiple outputs are present.
If empty, the compositor will choose which output to display the window on (usually the currently focused output).
'';
type = lib.types.nullOr lib.types.str;
default = null;
};
scale = lib.mkOption {
description = ''
Scale the window by the output's scale factor.
'';
type = lib.types.nullOr lib.types.bool;
default = null;
};
margin = {
top = lib.mkOption {
description = ''
Offset from top of screen.
Only has an effect when anchored to the top of the screen.
'';
type = lib.types.nullOr percentageValue;
default = null;
};
bottom = lib.mkOption {
description = ''
Offset from bottom of screen.
Only has an effect when anchored to the bottom of the screen.
'';
type = lib.types.nullOr percentageValue;
default = null;
};
left = lib.mkOption {
description = ''
Offset from left of screen.
Only has an effect when anchored to the left of the screen.
'';
type = lib.types.nullOr percentageValue;
default = null;
};
right = lib.mkOption {
description = ''
Offset from right of screen.
Only has an effect when anchored to the right of the screen.
'';
type = lib.types.nullOr percentageValue;
default = null;
};
};
padding = {
top = lib.mkOption {
description = ''
Padding between top border and text.
'';
type = lib.types.nullOr percentageValue;
default = null;
};
bottom = lib.mkOption {
description = ''
Padding between bottom border and text.
'';
type = lib.types.nullOr percentageValue;
default = null;
};
left = lib.mkOption {
description = ''
Padding between left border and text.
'';
type = lib.types.nullOr percentageValue;
default = null;
};
right = lib.mkOption {
description = ''
Padding between right border and text.
'';
type = lib.types.nullOr percentageValue;
default = null;
};
};
clipToPadding = lib.mkOption {
description = ''
Whether to clip text drawing to be within the specified padding.
This is mostly important for allowing text to be inset from the border, while still allowing text backgrounds to reach right to the edge.
'';
type = lib.types.nullOr lib.types.bool;
default = null;
};
horizontal = lib.mkOption {
description = ''
List results horizontally.
'';
type = lib.types.nullOr lib.types.bool;
default = null;
};
hintFont = lib.mkOption {
description = ''
Perform font hinting.
Only applies when a path to a font has been specified via font.
Disabling font hinting speeds up text rendering appreciably, but will likely look poor at small font pixel sizes.
'';
type = lib.types.nullOr lib.types.bool;
default = null;
};
};
};
config = lib.mkIf config.features.wayland-de.enable {
home.packages = with pkgs; [
# Tiny dynamic menu for Wayland
# https://github.com/philj56/tofi
tofi
];
xdg.configFile."tofi/config" =
let
quote = str: "\"${str}\"";
map = f: x:
if isNull x then
null
else
f x;
entries = attrset:
lib.trivial.pipe attrset [
(lib.attrsets.mapAttrsToList
(name: value:
if isNull value then
null
else
"${name} = ${value}"
))
(builtins.filter builtins.isString)
(lib.strings.concatStringsSep "\n")
];
in
{
text = entries {
"text-cursor" = map lib.trivial.boolToString cfg.textCursor;
"history" = map lib.trivial.boolToString cfg.history;
"history-file" = cfg.historyFile;
"fuzzy-match" = map lib.trivial.boolToString cfg.fuzzyMatch;
"font" = map quote cfg.font.family;
"font-size" = map builtins.toString cfg.font.size;
"font-variation" = map (lib.strings.concatStringsSep ",") cfg.font.variations;
"background-color" = cfg.backgroundColor;
"outline-width" = map builtins.toString cfg.outline.width;
"outline-color" = cfg.outline.color;
"text-color" = cfg.textColor;
"border-width" = map builtins.toString cfg.border.width;
"border-color" = cfg.border.color;
"prompt-text" = map quote cfg.prompt.text;
"prompt-padding" = map builtins.toString cfg.prompt.padding;
"prompt-color" = cfg.prompt.color;
"prompt-background" = cfg.prompt.background;
"prompt-background-padding" = map directionalValueToString cfg.prompt.backgroundPadding;
"prompt-background-corner-radius" = map lib.trivial.boolToString cfg.prompt.backgroundCornerRadius;
"placeholder-text" = cfg.placeholder.text;
"placeholder-color" = cfg.placeholder.color;
"placeholder-background" = cfg.placeholder.background;
"placeholder-background-padding" = map directionalValueToString cfg.placeholder.backgroundPadding;
"placeholder-background-corner-radius" = map builtins.toString cfg.placeholder.backgroundCornerRadius;
"input-color" = cfg.input.color;
"input-background" = cfg.input.background;
"input-background-padding" = map directionalValueToString cfg.input.backgroundPadding;
"input-background-corner-radius" = map builtins.toString cfg.input.backgroundCornerRadius;
"default-result-color" = cfg.defaultResult.color;
"default-result-background" = cfg.defaultResult.background;
"default-result-background-padding" = map directionalValueToString cfg.defaultResult.backgroundPadding;
"default-result-background-corner-radius" = map builtins.toString cfg.defaultResult.backgroundCornerRadius;
"alternate-result-color" = cfg.alternateResult.color;
"alternate-result-background" = cfg.alternateResult.background;
"alternate-result-background-padding" = map directionalValueToString cfg.alternateResult.backgroundPadding;
"alternate-result-background-corner-radius" = map builtins.toString cfg.alternateResult.backgroundCornerRadius;
"num-results" = map builtins.toString cfg.numResults;
"selection-color" = cfg.selection.color;
"selection-match-color" = cfg.selection.matchColor;
"selection-background" = cfg.selection.background;
"selection-background-padding" = map directionalValueToString cfg.selection.backgroundPadding;
"selection-background-corner-radius" = map builtins.toString cfg.selection.backgroundCornerRadius;
"result-spacing" = map builtins.toString cfg.resultSpacing;
"min-input-width" = map builtins.toString cfg.minInputWidth;
"width" = map builtins.toString cfg.width;
"height" = map builtins.toString cfg.height;
"corner-radius" = map builtins.toString cfg.cornerRadius;
"anchor" = cfg.anchor;
"exclusive-zone" = map builtins.toString cfg.exclusiveZone;
"output" = cfg.output;
"scale" = map lib.trivial.boolToString cfg.scale;
"margin-top" = map builtins.toString cfg.margin.top;
"margin-bottom" = map builtins.toString cfg.margin.bottom;
"margin-left" = map builtins.toString cfg.margin.left;
"margin-right" = map builtins.toString cfg.margin.right;
"padding-top" = map builtins.toString cfg.padding.top;
"padding-bottom" = map builtins.toString cfg.padding.bottom;
"padding-left" = map builtins.toString cfg.padding.left;
"padding-right" = map builtins.toString cfg.padding.right;
"clip-to-padding" = map lib.trivial.boolToString cfg.clipToPadding;
"horizontal" = map lib.trivial.boolToString cfg.horizontal;
"hint-font" = map lib.trivial.boolToString cfg.hintFont;
};
};
};
}