mirror of
https://github.com/nix-community/home-manager.git
synced 2026-01-11 17:39:37 +08:00
Compare commits
544 Commits
release-17
...
release-18
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a61b83445 | ||
|
|
2ccbf43e46 | ||
|
|
5c1d10497d | ||
|
|
69851e4c35 | ||
|
|
9d23f09790 | ||
|
|
2fa6dd4cf5 | ||
|
|
d5f6e84862 | ||
|
|
0312d450e2 | ||
|
|
15ef36a7f4 | ||
|
|
78ce79e57d | ||
|
|
b8eb7a03c5 | ||
|
|
deb2868d57 | ||
|
|
6fcaef5235 | ||
|
|
6bc07d4f53 | ||
|
|
c40fa72cde | ||
|
|
594294e2ca | ||
|
|
2b19f15be3 | ||
|
|
9901509ef8 | ||
|
|
5d5bc3dc5a | ||
|
|
ec05213a41 | ||
|
|
9b82a37d28 | ||
|
|
0ac92c6a42 | ||
|
|
5342c9479b | ||
|
|
d99f0cbe62 | ||
|
|
87a897e0c9 | ||
|
|
fdda547e9e | ||
|
|
da31e466a1 | ||
|
|
fa19c18343 | ||
|
|
3c2823e3cd | ||
|
|
dd94a849df | ||
|
|
ee1bfa0d92 | ||
|
|
8980e08240 | ||
|
|
afd2d0fb84 | ||
|
|
2bdaf4ae98 | ||
|
|
1ade5cad80 | ||
|
|
cf5b16b45f | ||
|
|
45057f353c | ||
|
|
ee7631fbe3 | ||
|
|
fdb81a7ea0 | ||
|
|
1c3614cbc8 | ||
|
|
75538973db | ||
|
|
37760ed934 | ||
|
|
6924761aaf | ||
|
|
5ccc2298de | ||
|
|
0f4c798c81 | ||
|
|
f89522362f | ||
|
|
7772158ac4 | ||
|
|
fb96af9b9d | ||
|
|
c73685ec74 | ||
|
|
de2d6a5d95 | ||
|
|
3bef871dac | ||
|
|
27042d1050 | ||
|
|
a6475e3e60 | ||
|
|
17aaf04f72 | ||
|
|
708de1ac8d | ||
|
|
7d6a6cbbe3 | ||
|
|
016005a3a3 | ||
|
|
966b790859 | ||
|
|
bceb74a78c | ||
|
|
bde13d0482 | ||
|
|
6c30decf8d | ||
|
|
4bed99c71c | ||
|
|
f174f90fdf | ||
|
|
a9e218dddd | ||
|
|
3656bf1ad7 | ||
|
|
47450371d9 | ||
|
|
4bb40ac42d | ||
|
|
4c311835a7 | ||
|
|
e9942375ce | ||
|
|
e6bc17e7fb | ||
|
|
9f013a8fb8 | ||
|
|
3c429c2462 | ||
|
|
f60f0c647f | ||
|
|
6d8a296625 | ||
|
|
2d77421d7c | ||
|
|
257dcbcd8a | ||
|
|
f221e4935d | ||
|
|
29161b6e21 | ||
|
|
9e913a9a30 | ||
|
|
e57e34f799 | ||
|
|
af94896ba1 | ||
|
|
8026e4ff6f | ||
|
|
ad0b33387d | ||
|
|
c67d2a916f | ||
|
|
82ed4dae2a | ||
|
|
7e65605d8f | ||
|
|
be7017b9c8 | ||
|
|
5b66b89d6e | ||
|
|
1e7fbde1be | ||
|
|
54fc5f778b | ||
|
|
f60f9c4bb6 | ||
|
|
944c12dbbb | ||
|
|
17fd9cbbd0 | ||
|
|
dc9be1eee6 | ||
|
|
c2cff13f15 | ||
|
|
e267dfea2d | ||
|
|
461869b438 | ||
|
|
1484b1d48b | ||
|
|
d5e21feebb | ||
|
|
cb29a29055 | ||
|
|
c2646f9f2b | ||
|
|
48ba1010ab | ||
|
|
b837f8ae41 | ||
|
|
0312cb611e | ||
|
|
3b7f74ab87 | ||
|
|
c9945550de | ||
|
|
a471c62bf2 | ||
|
|
1e2d80a583 | ||
|
|
159ee7a269 | ||
|
|
ab562d4c2a | ||
|
|
3646088248 | ||
|
|
371715a51c | ||
|
|
c4a9546831 | ||
|
|
88c681606b | ||
|
|
63668b2172 | ||
|
|
0686063f62 | ||
|
|
4a574ca544 | ||
|
|
f4af8151de | ||
|
|
b535770bd4 | ||
|
|
7ab6441ab7 | ||
|
|
2297450ec8 | ||
|
|
ffdbefe22c | ||
|
|
456e2d7ed5 | ||
|
|
fa3d1f98e0 | ||
|
|
c21b69e73e | ||
|
|
9318bd3b0d | ||
|
|
59448d635c | ||
|
|
a9a4fb641f | ||
|
|
f247b3b99b | ||
|
|
fa62c5afb6 | ||
|
|
061c7b633f | ||
|
|
dacc07136c | ||
|
|
abfc37076a | ||
|
|
9a0f388f66 | ||
|
|
b08e6221e0 | ||
|
|
0efda9cd6b | ||
|
|
f4ebbcbf70 | ||
|
|
36ecad6cbe | ||
|
|
22568a3d26 | ||
|
|
8e798e4c28 | ||
|
|
736e340bde | ||
|
|
05c93ff3ae | ||
|
|
8d4c65f259 | ||
|
|
0435d9c338 | ||
|
|
15a5f3278a | ||
|
|
34bbd0ded1 | ||
|
|
c17f37857c | ||
|
|
a2e09b4c9d | ||
|
|
5013155e58 | ||
|
|
7575e119d6 | ||
|
|
3b9b897af3 | ||
|
|
0cfd21cc15 | ||
|
|
05a98b6be0 | ||
|
|
52b9363745 | ||
|
|
f947fafec9 | ||
|
|
68d3cdd722 | ||
|
|
5770dc58b9 | ||
|
|
36da7a918f | ||
|
|
782d2fab83 | ||
|
|
d9c5d3c868 | ||
|
|
9b3122e92c | ||
|
|
f44d4a1d86 | ||
|
|
33a2943e8c | ||
|
|
a1a7e7cd24 | ||
|
|
6957911657 | ||
|
|
7cc36b7703 | ||
|
|
9407b42f97 | ||
|
|
151f29a17a | ||
|
|
f7dc354f42 | ||
|
|
4d870f665b | ||
|
|
0635423e73 | ||
|
|
3f34bf4465 | ||
|
|
9f0fdc68a9 | ||
|
|
701b4130bd | ||
|
|
d27bccdff1 | ||
|
|
5ff03ce5ac | ||
|
|
6eea2a409e | ||
|
|
ea74820176 | ||
|
|
50de1a6885 | ||
|
|
055d100548 | ||
|
|
63efd26767 | ||
|
|
8d2cb0ef9b | ||
|
|
2bff6e5188 | ||
|
|
453d0494fb | ||
|
|
97c6073d39 | ||
|
|
9fe6fa7f44 | ||
|
|
7699ed3fc8 | ||
|
|
5eca556fe7 | ||
|
|
4602c00dcf | ||
|
|
629d66e0b9 | ||
|
|
859c132ee2 | ||
|
|
99a0e2469b | ||
|
|
2548c43175 | ||
|
|
90bcaaf582 | ||
|
|
da8307cd26 | ||
|
|
cfa06c3f38 | ||
|
|
906965b48b | ||
|
|
d5bbbbd41d | ||
|
|
8e05229e62 | ||
|
|
7a8d50a803 | ||
|
|
6630cfbe16 | ||
|
|
dd25fbcb4b | ||
|
|
f9ac73732b | ||
|
|
26342588ab | ||
|
|
29191eb2c7 | ||
|
|
168d546304 | ||
|
|
34133ca7f3 | ||
|
|
4b32f16747 | ||
|
|
99c900946d | ||
|
|
39213a1847 | ||
|
|
c18b1328a5 | ||
|
|
93ef6aefce | ||
|
|
2e9e1909da | ||
|
|
4f67e8d0c3 | ||
|
|
30cba446f2 | ||
|
|
dda65c0877 | ||
|
|
cf80199bfc | ||
|
|
6694330bb2 | ||
|
|
a5a49c350d | ||
|
|
6ae2d74fca | ||
|
|
29ad012763 | ||
|
|
9570cedff6 | ||
|
|
d3871ed774 | ||
|
|
34db8df6d9 | ||
|
|
092706eff8 | ||
|
|
f4a1a5e94c | ||
|
|
dadfaed829 | ||
|
|
e365943a70 | ||
|
|
86fcfc74da | ||
|
|
eecebbf186 | ||
|
|
8dc1737e39 | ||
|
|
34bb9b5766 | ||
|
|
299e01722f | ||
|
|
97ee4578c9 | ||
|
|
0d3f9ba913 | ||
|
|
6aa44d62ad | ||
|
|
5641ee3f94 | ||
|
|
2e9fbbc978 | ||
|
|
ad634c0a94 | ||
|
|
7190f46938 | ||
|
|
e27cd96494 | ||
|
|
4caa45b8bb | ||
|
|
f3473b9eba | ||
|
|
06a984e4ff | ||
|
|
53f10f4d46 | ||
|
|
ed0cd78e05 | ||
|
|
faf04b009b | ||
|
|
965bad626a | ||
|
|
69445cb4a0 | ||
|
|
30c97391d7 | ||
|
|
cacb8d410e | ||
|
|
4b388ee902 | ||
|
|
10865f9952 | ||
|
|
dfaccdd03b | ||
|
|
f812260c23 | ||
|
|
b6da6569c4 | ||
|
|
bbcef2fd33 | ||
|
|
ec3cbf81c4 | ||
|
|
1a471b0a45 | ||
|
|
73b8aa8bcc | ||
|
|
394045f68a | ||
|
|
f9af8e0390 | ||
|
|
1260349384 | ||
|
|
74f4ed5fd2 | ||
|
|
91725ddced | ||
|
|
e055e4a092 | ||
|
|
f26cc3b957 | ||
|
|
9a3b1ec222 | ||
|
|
9141d11a7d | ||
|
|
6dc4f31ba1 | ||
|
|
d294aa4356 | ||
|
|
f314ee3d6a | ||
|
|
581ad6fc29 | ||
|
|
8ff7d934b2 | ||
|
|
5bdebf5ab0 | ||
|
|
96250b7ad3 | ||
|
|
7c9278bd92 | ||
|
|
4205c91609 | ||
|
|
75c4075345 | ||
|
|
f8398339a3 | ||
|
|
9bf9e7ac5c | ||
|
|
567b21b1d6 | ||
|
|
fa7d63d9d1 | ||
|
|
46a94cce56 | ||
|
|
bc50202d0d | ||
|
|
8fc8e158e2 | ||
|
|
06e7d087f2 | ||
|
|
fbff38de33 | ||
|
|
19b4002f25 | ||
|
|
b47cc4bc66 | ||
|
|
e307ceeee7 | ||
|
|
4745c7a00d | ||
|
|
5c783e1a63 | ||
|
|
05ad0c9e06 | ||
|
|
6d7b5c9513 | ||
|
|
de001e05da | ||
|
|
08ce0579aa | ||
|
|
be60600a47 | ||
|
|
f2265b10e4 | ||
|
|
afa865587e | ||
|
|
9ea353569a | ||
|
|
1bc59f7290 | ||
|
|
563a20fc82 | ||
|
|
6cca1fc512 | ||
|
|
6833f96c14 | ||
|
|
2304c145f3 | ||
|
|
fa6f697dbb | ||
|
|
91a98f919d | ||
|
|
616dbd67f7 | ||
|
|
6fc0fd315c | ||
|
|
9de2549dfb | ||
|
|
81fb420457 | ||
|
|
8b77f1db2c | ||
|
|
a154e2ea1a | ||
|
|
5fe8d574ca | ||
|
|
a9dc7fa7cc | ||
|
|
9d3d7426aa | ||
|
|
a597c66afe | ||
|
|
21fefbc8f6 | ||
|
|
38020d9068 | ||
|
|
1b0a5eb54a | ||
|
|
071f7aea82 | ||
|
|
32b3f7f2d2 | ||
|
|
576217d33a | ||
|
|
b8b595c6b2 | ||
|
|
a93445f3fe | ||
|
|
dbcb3dd1ae | ||
|
|
d6ab6ee370 | ||
|
|
c9294e30d9 | ||
|
|
d7715f71ad | ||
|
|
b2ed0a902b | ||
|
|
18159c85b9 | ||
|
|
d7755de116 | ||
|
|
7631921366 | ||
|
|
803abb58f9 | ||
|
|
a3250dfac7 | ||
|
|
4f9158e533 | ||
|
|
e624b9aa6a | ||
|
|
2fc1b9b5e0 | ||
|
|
026375da49 | ||
|
|
58a629b02e | ||
|
|
df6590abfc | ||
|
|
33af9948e5 | ||
|
|
8ab6298f30 | ||
|
|
78c308c835 | ||
|
|
8a2bf21cee | ||
|
|
59f44c1189 | ||
|
|
02219dcd79 | ||
|
|
f0d207f380 | ||
|
|
7dd09cecda | ||
|
|
e75b68e391 | ||
|
|
8d360c5a57 | ||
|
|
f6900f0689 | ||
|
|
8759a5a63e | ||
|
|
52bdbc42bb | ||
|
|
28e00b68fd | ||
|
|
2ff09158f3 | ||
|
|
6764c26954 | ||
|
|
040159c02f | ||
|
|
61c6c83de4 | ||
|
|
0be32c9d42 | ||
|
|
aa1bf31bcb | ||
|
|
c023b0532a | ||
|
|
f8aaba6704 | ||
|
|
26cf42049d | ||
|
|
06d4f39e7b | ||
|
|
a1e36a9a37 | ||
|
|
11da41e106 | ||
|
|
7a5b9152e9 | ||
|
|
7876d533cf | ||
|
|
e99de88c5c | ||
|
|
bcb82da88f | ||
|
|
592fd61788 | ||
|
|
3c875267af | ||
|
|
455ce37398 | ||
|
|
64befb27eb | ||
|
|
177565567e | ||
|
|
8045e56df2 | ||
|
|
206a4e17b5 | ||
|
|
2785bf9cb2 | ||
|
|
bc2f2ad546 | ||
|
|
4fce730326 | ||
|
|
9206f363ff | ||
|
|
130e33a4e7 | ||
|
|
a36989a860 | ||
|
|
1946343d5b | ||
|
|
4ccf43d753 | ||
|
|
7ca68c6492 | ||
|
|
61a869a1f5 | ||
|
|
c718951e97 | ||
|
|
04ea044917 | ||
|
|
66219f23bb | ||
|
|
187a12e90a | ||
|
|
356c0bf751 | ||
|
|
7a9c873093 | ||
|
|
d7537777c3 | ||
|
|
145aefc9d1 | ||
|
|
2b2e20da24 | ||
|
|
a977c79f9f | ||
|
|
f52ec0df7c | ||
|
|
54043df8fb | ||
|
|
fad1e108d8 | ||
|
|
fc3e82584b | ||
|
|
a0afb6ec8e | ||
|
|
549deb51d6 | ||
|
|
4f842d9f1b | ||
|
|
9627fe6be6 | ||
|
|
b8ddb11796 | ||
|
|
f04cc227a6 | ||
|
|
811bc1b8e5 | ||
|
|
ccb291ce66 | ||
|
|
676f5c4b31 | ||
|
|
14083a0857 | ||
|
|
b4f5b5556f | ||
|
|
fa4f9197ee | ||
|
|
bfb5a678d2 | ||
|
|
d2572315ca | ||
|
|
467b774d13 | ||
|
|
78a1424582 | ||
|
|
82d6aa0c97 | ||
|
|
1213578eb7 | ||
|
|
268d027770 | ||
|
|
f55fbe037a | ||
|
|
3a95ff7435 | ||
|
|
d70715a635 | ||
|
|
54a9058ee0 | ||
|
|
efb5256d28 | ||
|
|
a4c0fead1f | ||
|
|
35775b3bc5 | ||
|
|
7417d8e86e | ||
|
|
df84c466c1 | ||
|
|
bf3a8c6383 | ||
|
|
5605e46acb | ||
|
|
3346c7f455 | ||
|
|
b78b2b6b35 | ||
|
|
0f43d5df6a | ||
|
|
30b9d7f00e | ||
|
|
b9f49cee45 | ||
|
|
c144580c98 | ||
|
|
2ff8c12bf9 | ||
|
|
335cffe9a9 | ||
|
|
bc40ab378c | ||
|
|
d81276607c | ||
|
|
3bc3b34d97 | ||
|
|
f0a1d69f50 | ||
|
|
0672936134 | ||
|
|
3632478b8d | ||
|
|
c07fa70d58 | ||
|
|
ee7f2413ed | ||
|
|
12ebf21be5 | ||
|
|
691eea9b45 | ||
|
|
7e6f3364bc | ||
|
|
3f430627df | ||
|
|
3160c03843 | ||
|
|
420a3f4a01 | ||
|
|
9eb48312c7 | ||
|
|
469caa1a14 | ||
|
|
3aca8a938c | ||
|
|
01d46a1751 | ||
|
|
9c859d2655 | ||
|
|
fb5dbe13c2 | ||
|
|
e4c359d8b9 | ||
|
|
52256d7a73 | ||
|
|
aa974c0dc3 | ||
|
|
23d3539fcb | ||
|
|
bcff7274f4 | ||
|
|
e9deaf2ca5 | ||
|
|
e1bceb2adb | ||
|
|
34428fc709 | ||
|
|
393274d142 | ||
|
|
a8e08d14bb | ||
|
|
bf9b9026d9 | ||
|
|
0f096f9ad4 | ||
|
|
db55e596d2 | ||
|
|
82c5aa82d2 | ||
|
|
742d1889c5 | ||
|
|
61042c7606 | ||
|
|
3e4f7228a0 | ||
|
|
76e0e09aca | ||
|
|
e4deffcbe8 | ||
|
|
de5f902487 | ||
|
|
cab9237d95 | ||
|
|
6ecf9e091c | ||
|
|
aa69598b57 | ||
|
|
f47084968d | ||
|
|
6a8e8e92a7 | ||
|
|
c7edde6ca4 | ||
|
|
379e2c694b | ||
|
|
29d5f5d760 | ||
|
|
258bc85b9c | ||
|
|
fc1d4f5362 | ||
|
|
cda222d2ec | ||
|
|
07b4228988 | ||
|
|
ad1eee7aa5 | ||
|
|
9c1b3735b4 | ||
|
|
ab0338f6ae | ||
|
|
39fc16954b | ||
|
|
f5289c546e | ||
|
|
721f924e15 | ||
|
|
6611c16099 | ||
|
|
2c5151726c | ||
|
|
5eff7f38df | ||
|
|
e9ca4305a6 | ||
|
|
125deafc84 | ||
|
|
1445673e18 | ||
|
|
4a17d8ef97 | ||
|
|
b4fff6b9b7 | ||
|
|
2245b0ac94 | ||
|
|
e561beab44 | ||
|
|
3bcd9d747b | ||
|
|
85a71a3923 | ||
|
|
a30751464a | ||
|
|
1678548353 | ||
|
|
7218c45443 | ||
|
|
bd914d49f1 | ||
|
|
fed112e497 | ||
|
|
c3be4c4629 | ||
|
|
286d678785 | ||
|
|
42ae135d38 | ||
|
|
42f5d4404d | ||
|
|
5c098dc7ad | ||
|
|
3dba6fc95c | ||
|
|
1eee82272a | ||
|
|
da5b7bea78 | ||
|
|
910cdc0537 | ||
|
|
02a501705a | ||
|
|
a9d9fb5d75 | ||
|
|
ffbc7e723d | ||
|
|
3ef56576d3 | ||
|
|
cde8e02bf2 | ||
|
|
1d24e96074 | ||
|
|
be432c8654 | ||
|
|
3778a69fbe | ||
|
|
d807a5c314 | ||
|
|
5862a05fb1 | ||
|
|
dba14bfe90 | ||
|
|
2e257f40e6 | ||
|
|
cdb2bec909 | ||
|
|
dd5061d73b | ||
|
|
7a18a0fb34 | ||
|
|
28d3f74614 | ||
|
|
98c7b23178 | ||
|
|
89dc8c2004 | ||
|
|
e274fc732b |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/result*
|
||||
14
.gitlab-ci.yml
Normal file
14
.gitlab-ci.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
image: nixos/nix:latest
|
||||
|
||||
pages:
|
||||
script:
|
||||
- mkdir -p ~/.config/nixpkgs
|
||||
- echo '{ manual.html.enable = true; }' > ~/.config/nixpkgs/home.nix
|
||||
- nix-shell . -A install
|
||||
- mkdir public
|
||||
- cp -r ~/.nix-profile/share/doc/home-manager/* public/
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
only:
|
||||
- master
|
||||
12
.travis.yml
Normal file
12
.travis.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
language: nix
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
before_script:
|
||||
- mkdir -m 0755 -p /nix/var/nix/{profiles,gcroots}/per-user/$USER
|
||||
|
||||
script:
|
||||
- nix-shell . -A install
|
||||
- nix-shell tests -A run.all
|
||||
158
CONTRIBUTING.md
Normal file
158
CONTRIBUTING.md
Normal file
@@ -0,0 +1,158 @@
|
||||
Contributing
|
||||
============
|
||||
|
||||
Thanks for wanting to contribute to Home Manager! These are some
|
||||
guidelines to make the process as smooth as possible for both you and
|
||||
the Home Manager developers.
|
||||
|
||||
If you are only looking to report a problem then it is sufficient to
|
||||
read through the following section on reporting issues. If you instead
|
||||
want to directly contribute improvements and additions then please
|
||||
have a look at everything here.
|
||||
|
||||
Reporting an issue
|
||||
------------------
|
||||
|
||||
If you notice a problem with Home Manager and want to report it then
|
||||
have a look among the already [open issues][], if you find one
|
||||
matching yours then feel free to comment on it to add any additional
|
||||
information you may have.
|
||||
|
||||
If no matching issue exists then go to the [new issue][] page and
|
||||
write a description of your problem. Include as much information as
|
||||
you can, ideally also include relevant excerpts from your Home Manager
|
||||
configuration.
|
||||
|
||||
Contributing code
|
||||
-----------------
|
||||
|
||||
If you want to contribute code to improve Home Manager then please
|
||||
follow these guidelines.
|
||||
|
||||
### Fork and create a pull request ###
|
||||
|
||||
If you have not previously forked Home Manager then you need to do
|
||||
that first. Have a look at GitHub's "[Fork A Repo][]" for instructions
|
||||
on how to do this.
|
||||
|
||||
Once you have a fork of Home Manager you should create a branch
|
||||
starting at the most recent `master`. Give your branch a reasonably
|
||||
descriptive name. Perform your changes on this branch and when you are
|
||||
happy with the result push the branch to GitHub and
|
||||
[create a pull request][].
|
||||
|
||||
Assuming your clone is at `$HOME/devel/home-manager` then you can make
|
||||
the `home-manager` command use it by either
|
||||
|
||||
1. overriding the default path by using the `-I` command line option:
|
||||
|
||||
home-manager -I home-manager=$HOME/devel/home-manager
|
||||
|
||||
or
|
||||
|
||||
2. changing the default path by ensuring your configuration includes
|
||||
|
||||
programs.home-manager.enable = true;
|
||||
programs.home-manager.path = "$HOME/devel/home-manager";
|
||||
|
||||
and running `home-manager switch` to activate the change.
|
||||
Afterwards, `home-manager build` and `home-manager switch` will
|
||||
use your cloned repository.
|
||||
|
||||
The first option is good if you only temporarily want to use your
|
||||
clone.
|
||||
|
||||
### Commits ###
|
||||
|
||||
The commits in your pull request should be reasonably self-contained,
|
||||
that is, each commit should make sense in isolation. In particular,
|
||||
you will be asked to amend any commit that introduces syntax errors or
|
||||
similar problems even if they are fixed in a later commit.
|
||||
|
||||
The commit messages should follow the format
|
||||
|
||||
{component}: {description}
|
||||
|
||||
{long description}
|
||||
|
||||
where `{component}` refers to the code component (or module) your
|
||||
change affects, `{description}` is a brief description of your change,
|
||||
and `{long description}` is an optional clarifying description. Note,
|
||||
`{description}` should start with a lower case letter. As a rare
|
||||
exception, if there is no clear component, or your change affects many
|
||||
components, then the `{component}` part is optional.
|
||||
|
||||
When adding a new module, say `foo.nix`, we use the fixed commit
|
||||
format `foo: add module`. You can, of course, still include a long
|
||||
description if you wish.
|
||||
|
||||
In addition to the above commit message guidelines, try to follow the
|
||||
[seven rules][] as much as possible.
|
||||
|
||||
### Style guidelines ###
|
||||
|
||||
The code in Home Manager should follow the [Nixpkgs syntax
|
||||
guidelines][]. Note, we prefer `lowerCamelCase` for variable and
|
||||
attribute names with the accepted exception of variables directly
|
||||
referencing packages in Nixpkgs which use a hyphenated style. For
|
||||
example, the Home Manager option `services.gpg-agent.enableSshSupport`
|
||||
references the `gpg-agent` package in Nixpkgs.
|
||||
|
||||
### News ###
|
||||
|
||||
Home Manager includes a system for presenting news to the user. When
|
||||
making a change you, therefore, have the option to also include an
|
||||
associated news entry. In general, a news entry should only be added
|
||||
for truly noteworthy news. For example, a bug fix or new option does
|
||||
generally not need a news entry.
|
||||
|
||||
If you do have a change worthy of a news entry then please add one in
|
||||
[`news.nix`][] but you should follow some basic guidelines:
|
||||
|
||||
- The entry timestamp should be in ISO-8601 format having "+00:00" as
|
||||
time zone. For example, "2017-09-13T17:10:14+00:00". A suitable
|
||||
timestamp can be produced by the command
|
||||
|
||||
date --iso-8601=second --universal
|
||||
|
||||
- The entry condition should be as specific as possible. For example,
|
||||
if you are changing or deprecating a specific option then you could
|
||||
restrict the news to those users who actually use this option.
|
||||
|
||||
- Wrap the news message so that it will fit in the typical terminal,
|
||||
that is, at most 80 characters wide. Ideally a bit less.
|
||||
|
||||
- Unlike commit messages, news will be read without any connection to
|
||||
the Home Manager source code. It is therefore important to make the
|
||||
message understandable in isolation and to those who do not have
|
||||
knowledge of the Home Manager internals. To this end it should be
|
||||
written in more descriptive, prose like way.
|
||||
|
||||
- If you refer to an option then write its full attribute path. That
|
||||
is, instead of writing
|
||||
|
||||
> The option 'foo' has been deprecated, please use 'bar' instead.
|
||||
|
||||
it should read
|
||||
|
||||
> The option 'services.myservice.foo' has been deprecated, please
|
||||
> use 'services.myservice.bar' instead.
|
||||
|
||||
- A new module, say `foo.nix`, should always include a news entry
|
||||
(without any condition) that has a message along the lines of
|
||||
|
||||
> A new service is available: 'services.foo'.
|
||||
|
||||
or
|
||||
|
||||
> A new program configuration is available: 'program.foo'.
|
||||
|
||||
depending on the type of module.
|
||||
|
||||
[open issues]: https://github.com/rycee/home-manager/issues
|
||||
[new issue]: https://github.com/rycee/home-manager/issues/new
|
||||
[Fork A Repo]: https://help.github.com/articles/fork-a-repo/
|
||||
[create a pull request]: https://help.github.com/articles/creating-a-pull-request/
|
||||
[seven rules]: https://chris.beams.io/posts/git-commit/#seven-rules
|
||||
[`news.nix`]: https://github.com/rycee/home-manager/blob/master/modules/misc/news.nix
|
||||
[Nixpkgs syntax guidelines]: https://nixos.org/nixpkgs/manual/#sec-syntax
|
||||
121
FAQ.md
Normal file
121
FAQ.md
Normal file
@@ -0,0 +1,121 @@
|
||||
Frequently Asked Questions (FAQ)
|
||||
================================
|
||||
|
||||
Why is there a collision error when switching generation?
|
||||
---------------------------------------------------------
|
||||
|
||||
Home Manager currently installs packages into the user environment,
|
||||
precisely as if the packages were installed through
|
||||
`nix-env --install`. This means that you will get a collision error if
|
||||
your Home Manager configuration attempts to install a package that you
|
||||
already have installed manually, that is, packages that shows up when
|
||||
you run `nix-env --query`.
|
||||
|
||||
For example, imagine you have the `hello` package installed in your
|
||||
environment
|
||||
|
||||
```console
|
||||
$ nix-env --query
|
||||
hello-2.10
|
||||
```
|
||||
|
||||
and your Home Manager configuration contains
|
||||
|
||||
home.packages = [ pkgs.hello ];
|
||||
|
||||
Then attempting to switch to this configuration will result in an
|
||||
error similar to
|
||||
|
||||
```console
|
||||
$ home-manager switch
|
||||
these derivations will be built:
|
||||
/nix/store/xg69wsnd1rp8xgs9qfsjal017nf0ldhm-home-manager-path.drv
|
||||
[…]
|
||||
Activating installPackages
|
||||
replacing old ‘home-manager-path’
|
||||
installing ‘home-manager-path’
|
||||
building path(s) ‘/nix/store/b5c0asjz9f06l52l9812w6k39ifr49jj-user-environment’
|
||||
Wide character in die at /nix/store/64jc9gd2rkbgdb4yjx3nrgc91bpjj5ky-buildenv.pl line 79.
|
||||
collision between ‘/nix/store/fmwa4axzghz11cnln5absh31nbhs9lq1-home-manager-path/bin/hello’ and ‘/nix/store/c2wyl8b9p4afivpcz8jplc9kis8rj36d-hello-2.10/bin/hello’; use ‘nix-env --set-flag priority NUMBER PKGNAME’ to change the priority of one of the conflicting packages
|
||||
builder for ‘/nix/store/b37x3s7pzxbasfqhaca5dqbf3pjjw0ip-user-environment.drv’ failed with exit code 2
|
||||
error: build of ‘/nix/store/b37x3s7pzxbasfqhaca5dqbf3pjjw0ip-user-environment.drv’ failed
|
||||
```
|
||||
|
||||
The solution is typically to uninstall the package from the
|
||||
environment using `nix-env --uninstall` and reattempt the Home Manager
|
||||
generation switch.
|
||||
|
||||
Why are the session variables not set?
|
||||
--------------------------------------
|
||||
|
||||
Home Manager is only able to set session variables automatically if it
|
||||
manages your Bash or Z shell configuration. If you don't want to let
|
||||
Home Manager manage your shell then you will have to manually source
|
||||
the
|
||||
|
||||
~/.nix-profile/etc/profile.d/hm-session-vars.sh
|
||||
|
||||
file in an appropriate way. In Bash and Z shell this can be done by
|
||||
adding
|
||||
|
||||
```sh
|
||||
. "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh"
|
||||
```
|
||||
|
||||
to your `.profile` and `.zshrc` files, respectively. The
|
||||
`hm-session-vars.sh` file should work in most Bourne-like shells.
|
||||
|
||||
How do set up a configuration for multiple users/machines?
|
||||
----------------------------------------------------------
|
||||
|
||||
A typical way to prepare a repository of configurations for multiple
|
||||
logins and machines is to prepare one "top-level" file for each unique
|
||||
combination.
|
||||
|
||||
For example, if you have two machines, called "kronos" and "rhea" on
|
||||
which you want to configure your user "jane" then you could create the
|
||||
files
|
||||
|
||||
- `kronos-jane.nix`,
|
||||
- `rhea-jane.nix`, and
|
||||
- `common.nix`
|
||||
|
||||
in your repository. On the kronos and rhea machines you can then make
|
||||
`~jane/.config/nixpkgs/home.nix` be a symbolic link to the
|
||||
corresponding file in your configuration repository.
|
||||
|
||||
The `kronos-jane.nix` and `rhea-jane.nix` files follow the format
|
||||
|
||||
```nix
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
imports = [ ./common.nix ];
|
||||
|
||||
# Various options that are specific for this machine/user.
|
||||
}
|
||||
```
|
||||
|
||||
while the `common.nix` file contains configuration shared across the
|
||||
two logins. Of course, instead of just a single `common.nix` file you
|
||||
can have multiple ones, even one per program or service.
|
||||
|
||||
You can get some inspiration from the [Post your home-manager home.nix
|
||||
file!][1] Reddit thread.
|
||||
|
||||
[1]: https://www.reddit.com/r/NixOS/comments/9bb9h9/post_your_homemanager_homenix_file/
|
||||
|
||||
Why do I get an error message about `ca.desrt.dconf`?
|
||||
-----------------------------------------------------
|
||||
|
||||
You are most likely trying to configure the GTK or Gnome Terminal but
|
||||
the DBus session is not aware of the dconf service. The full error you
|
||||
might get is
|
||||
|
||||
error: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name ca.desrt.dconf was not provided by any .service files
|
||||
|
||||
The solution on NixOS is to add
|
||||
|
||||
services.dbus.packages = with pkgs; [ gnome3.dconf ];
|
||||
|
||||
to your system configuration.
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Robert Helgesson
|
||||
Copyright (c) 2017-2019 Robert Helgesson and Home Manager contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
177
README.md
177
README.md
@@ -19,18 +19,25 @@ will write to your dconf store and cannot tell whether a configuration
|
||||
that it is about to be overwrite was from a previous Home Manager
|
||||
generation or from manual configuration.
|
||||
|
||||
Home Manager targets [NixOS][] version 17.03 (the current stable
|
||||
version), it may or may not work on other Linux distributions and
|
||||
NixOS versions.
|
||||
Home Manager targets [NixOS][] unstable and NixOS version 18.09 (the
|
||||
current stable version), it may or may not work on other Linux
|
||||
distributions and NixOS versions.
|
||||
|
||||
Also, the `home-manager` tool does not explicitly support rollbacks at
|
||||
the moment so if your home directory gets messed up you'll have to fix
|
||||
it yourself (you can attempt to run the activation script for the
|
||||
desired generation).
|
||||
it yourself. See the [rollbacks](#rollbacks) section for instructions
|
||||
on how to manually perform a rollback.
|
||||
|
||||
Now when your expectations have been built up and you are eager to try
|
||||
all this out you can go ahead and read the rest of this text.
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
You can chat with us on IRC in the channel [#home-manager][] on
|
||||
[freenode][]. The [channel logs][] are hosted courtesy of
|
||||
[samueldr][].
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
@@ -39,53 +46,95 @@ Currently the easiest way to install Home Manager is as follows:
|
||||
1. Make sure you have a working Nix installation. If you are not
|
||||
using NixOS then you may here have to run
|
||||
|
||||
```
|
||||
```console
|
||||
$ mkdir -m 0755 -p /nix/var/nix/{profiles,gcroots}/per-user/$USER
|
||||
```
|
||||
|
||||
since Home Manager uses these directories to manage your profile
|
||||
generations. On NixOS these should already be available.
|
||||
|
||||
2. Clone the Home Manager repository into the `~/.config/nixpkgs`
|
||||
directory:
|
||||
Also make sure that your user is able to build and install Nix
|
||||
packages. For example, you should be able to successfully run a
|
||||
command like `nix-instantiate '<nixpkgs>' -A hello` without having
|
||||
to switch to the root user. For a multi-user install of Nix this
|
||||
means that your user must be covered by the
|
||||
[`allowed-users`][nixAllowedUsers] Nix option. On NixOS you can
|
||||
control this option using the
|
||||
[`nix.allowedUsers`][nixosAllowedUsers] system option.
|
||||
|
||||
```
|
||||
$ git clone https://github.com/rycee/home-manager ~/.config/nixpkgs/home-manager
|
||||
2. Add the appropriate Home Manager channel. Typically this is
|
||||
|
||||
```console
|
||||
$ nix-channel --add https://github.com/rycee/home-manager/archive/master.tar.gz home-manager
|
||||
$ nix-channel --update
|
||||
```
|
||||
|
||||
3. Add Home Manager to your user's Nixpkgs, for example by adding it
|
||||
to the `packageOverrides` section in your
|
||||
`~/.config/nixpkgs/config.nix` file:
|
||||
if you are following Nixpkgs master or an unstable channel and
|
||||
|
||||
```nix
|
||||
{
|
||||
packageOverrides = pkgs: rec {
|
||||
home-manager = import ./home-manager { inherit pkgs; };
|
||||
};
|
||||
}
|
||||
```console
|
||||
$ nix-channel --add https://github.com/rycee/home-manager/archive/release-18.09.tar.gz home-manager
|
||||
$ nix-channel --update
|
||||
```
|
||||
|
||||
4. Install the `home-manager` package:
|
||||
if you follow a Nixpkgs version 18.09 channel.
|
||||
|
||||
On NixOS you may need to log out and back in for the channel to
|
||||
become available. On non-NixOS you may have to add
|
||||
|
||||
```shell
|
||||
export NIX_PATH=$HOME/.nix-defexpr/channels${NIX_PATH:+:}$NIX_PATH
|
||||
```
|
||||
|
||||
to your shell (see [nix#2033](https://github.com/NixOS/nix/issues/2033)).
|
||||
|
||||
3. Install Home Manager and create the first Home Manager generation:
|
||||
|
||||
```console
|
||||
$ nix-shell '<home-manager>' -A install
|
||||
```
|
||||
|
||||
Once finished, Home Manager should be active and available in your
|
||||
user environment.
|
||||
|
||||
3. If you do not plan on having Home Manager manage your shell
|
||||
configuration then you must source the
|
||||
|
||||
```
|
||||
$ nix-env -f '<nixpkgs>' -iA home-manager
|
||||
installing ‘home-manager’
|
||||
$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh
|
||||
```
|
||||
|
||||
file in your shell configuration. Unfortunately, in this specific
|
||||
case we currently only support POSIX.2-like shells such as
|
||||
[Bash][] or [Z shell][].
|
||||
|
||||
For example, if you use Bash then add
|
||||
|
||||
```bash
|
||||
. "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh"
|
||||
```
|
||||
|
||||
to your `~/.profile` file.
|
||||
|
||||
If instead of using channels you want to run Home Manager from a Git
|
||||
checkout of the repository then you can use the
|
||||
`programs.home-manager.path` option to specify the absolute path to
|
||||
the repository.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The `home-manager` package installs a tool that is conveniently called
|
||||
`home-manager`. This tool can apply configurations to your home
|
||||
Home Manager is typically managed through the `home-manager` tool.
|
||||
This tool can, for example, apply configurations to your home
|
||||
directory, list user packages installed by the tool, and list the
|
||||
configuration generations.
|
||||
|
||||
As an example, let us set up a very simple configuration that installs
|
||||
the htop and fortune packages, installs Emacs with a few extra
|
||||
packages enabled, installs Firefox with Adobe Flash enabled, and
|
||||
enables the user gpg-agent service.
|
||||
As an example, let us expand the initial configuration file from the
|
||||
installation above to install the htop and fortune packages, install
|
||||
Emacs with a few extra packages enabled, install Firefox with the
|
||||
IcedTea plugin enabled, and enable the user gpg-agent service.
|
||||
|
||||
First create a file `~/.config/nixpkgs/home.nix` containing
|
||||
To satisfy the above setup we should elaborate the
|
||||
`~/.config/nixpkgs/home.nix` file as follows:
|
||||
|
||||
```nix
|
||||
{ pkgs, ... }:
|
||||
@@ -106,7 +155,7 @@ First create a file `~/.config/nixpkgs/home.nix` containing
|
||||
|
||||
programs.firefox = {
|
||||
enable = true;
|
||||
enableAdobeFlash = true;
|
||||
enableIcedTea = true;
|
||||
};
|
||||
|
||||
services.gpg-agent = {
|
||||
@@ -114,28 +163,75 @@ First create a file `~/.config/nixpkgs/home.nix` containing
|
||||
defaultCacheTtl = 1800;
|
||||
enableSshSupport = true;
|
||||
};
|
||||
|
||||
programs.home-manager = {
|
||||
enable = true;
|
||||
path = "…";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
To activate this configuration you can then run
|
||||
|
||||
```
|
||||
```console
|
||||
$ home-manager switch
|
||||
```
|
||||
|
||||
or if you are not feeling so lucky,
|
||||
|
||||
```
|
||||
```console
|
||||
$ home-manager build
|
||||
```
|
||||
|
||||
which will create a `result` link to a directory containing an
|
||||
activation script and the generated home directory files.
|
||||
|
||||
Documentation of available configuration options, including
|
||||
descriptions and usage examples, is available in the [Home Manager
|
||||
manual][configuration options] or offline by running
|
||||
|
||||
```console
|
||||
$ man home-configuration.nix
|
||||
```
|
||||
|
||||
Rollbacks
|
||||
---------
|
||||
|
||||
While the `home-manager` tool does not explicitly support rollbacks at
|
||||
the moment it is relatively easy to perform one manually. The steps to
|
||||
do so are
|
||||
|
||||
1. Run `home-manager generations` to determine which generation you
|
||||
wish to rollback to:
|
||||
|
||||
```console
|
||||
$ home-manager generations
|
||||
2018-01-04 11:56 : id 765 -> /nix/store/kahm1rxk77mnvd2l8pfvd4jkkffk5ijk-home-manager-generation
|
||||
2018-01-03 10:29 : id 764 -> /nix/store/2wsmsliqr5yynqkdyjzb1y57pr5q2lsj-home-manager-generation
|
||||
2018-01-01 12:21 : id 763 -> /nix/store/mv960kl9chn2lal5q8lnqdp1ygxngcd1-home-manager-generation
|
||||
2017-12-29 21:03 : id 762 -> /nix/store/6c0k1r03fxckql4vgqcn9ccb616ynb94-home-manager-generation
|
||||
2017-12-25 18:51 : id 761 -> /nix/store/czc5y6vi1rvnkfv83cs3rn84jarcgsgh-home-manager-generation
|
||||
…
|
||||
```
|
||||
|
||||
2. Copy the Nix store path of the generation you chose, e.g.,
|
||||
|
||||
/nix/store/mv960kl9chn2lal5q8lnqdp1ygxngcd1-home-manager-generation
|
||||
|
||||
for generation 763.
|
||||
|
||||
3. Run the `activate` script inside the copied store path:
|
||||
|
||||
```console
|
||||
$ /nix/store/mv960kl9chn2lal5q8lnqdp1ygxngcd1-home-manager-generation/activate
|
||||
Starting home manager activation
|
||||
…
|
||||
```
|
||||
|
||||
Keeping your ~ safe from harm
|
||||
-----------------------------
|
||||
|
||||
To configure programs and services the Home Manager must write various
|
||||
To configure programs and services Home Manager must write various
|
||||
things to your home directory. To prevent overwriting any existing
|
||||
files when switching to a new generation, Home Manager will attempt to
|
||||
detect collisions between existing files and generated files. If any
|
||||
@@ -143,7 +239,7 @@ such collision is detected the activation will terminate before
|
||||
changing anything on your computer.
|
||||
|
||||
For example, suppose you have a wonderful, painstakingly created
|
||||
`~/.gitconfig` and add
|
||||
`~/.config/git/config` and add
|
||||
|
||||
```nix
|
||||
{
|
||||
@@ -162,7 +258,7 @@ For example, suppose you have a wonderful, painstakingly created
|
||||
to your configuration. Attempting to switch to the generation will
|
||||
then result in
|
||||
|
||||
```
|
||||
```console
|
||||
$ home-manager switch
|
||||
…
|
||||
Activating checkLinkTargets
|
||||
@@ -196,7 +292,7 @@ in your system configuration and
|
||||
# …
|
||||
|
||||
xsession.enable = true;
|
||||
xsession.windowManager = "…";
|
||||
xsession.windowManager.command = "…";
|
||||
|
||||
# …
|
||||
}
|
||||
@@ -204,6 +300,15 @@ in your system configuration and
|
||||
|
||||
in your Home Manager configuration.
|
||||
|
||||
[Bash]: https://www.gnu.org/software/bash/
|
||||
[Nix]: https://nixos.org/nix/
|
||||
[NixOS]: https://nixos.org/
|
||||
[Nixpkgs]: https://nixos.org/nixpkgs/
|
||||
[nixAllowedUsers]: https://nixos.org/nix/manual/#conf-allowed-users
|
||||
[nixosAllowedUsers]: https://nixos.org/nixos/manual/options.html#opt-nix.allowedUsers
|
||||
[Z shell]: http://zsh.sourceforge.net/
|
||||
[configuration options]: https://rycee.gitlab.io/home-manager/options.html
|
||||
[#home-manager]: https://webchat.freenode.net/?url=irc%3A%2F%2Firc.freenode.net%2Fhome-manager
|
||||
[freenode]: https://freenode.net/
|
||||
[channel logs]: https://logs.nix.samueldr.com/home-manager/
|
||||
[samueldr]: https://github.com/samueldr/
|
||||
|
||||
16
default.nix
16
default.nix
@@ -1,2 +1,14 @@
|
||||
# Simply defer to the home-manager script derivation.
|
||||
import ./home-manager
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
|
||||
rec {
|
||||
home-manager = import ./home-manager {
|
||||
inherit pkgs;
|
||||
path = toString ./.;
|
||||
};
|
||||
|
||||
install = import ./home-manager/install.nix {
|
||||
inherit home-manager pkgs;
|
||||
};
|
||||
|
||||
nixos = import ./nixos;
|
||||
}
|
||||
|
||||
328
doc/default.nix
Normal file
328
doc/default.nix
Normal file
@@ -0,0 +1,328 @@
|
||||
{ pkgs, options, config, version, revision, extraSources ? [] }:
|
||||
|
||||
with pkgs;
|
||||
|
||||
let
|
||||
lib = pkgs.lib;
|
||||
|
||||
# Remove invisible and internal options.
|
||||
optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options);
|
||||
|
||||
# Replace functions by the string <function>
|
||||
substFunction = x:
|
||||
if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x
|
||||
else if builtins.isList x then map substFunction x
|
||||
else if lib.isFunction x then "<function>"
|
||||
else x;
|
||||
|
||||
# Generate DocBook documentation for a list of packages. This is
|
||||
# what `relatedPackages` option of `mkOption` from
|
||||
# ../../../lib/options.nix influences.
|
||||
#
|
||||
# Each element of `relatedPackages` can be either
|
||||
# - a string: that will be interpreted as an attribute name from `pkgs`,
|
||||
# - a list: that will be interpreted as an attribute path from `pkgs`,
|
||||
# - an attrset: that can specify `name`, `path`, `package`, `comment`
|
||||
# (either of `name`, `path` is required, the rest are optional).
|
||||
genRelatedPackages = packages:
|
||||
let
|
||||
unpack = p: if lib.isString p then { name = p; }
|
||||
else if lib.isList p then { path = p; }
|
||||
else p;
|
||||
describe = args:
|
||||
let
|
||||
name = args.name or (lib.concatStringsSep "." args.path);
|
||||
path = args.path or [ args.name ];
|
||||
package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs);
|
||||
in "<listitem>"
|
||||
+ "<para><literal>pkgs.${name} (${package.meta.name})</literal>"
|
||||
+ lib.optionalString (!package.meta.available) " <emphasis>[UNAVAILABLE]</emphasis>"
|
||||
+ ": ${package.meta.description or "???"}.</para>"
|
||||
+ lib.optionalString (args ? comment) "\n<para>${args.comment}</para>"
|
||||
# Lots of `longDescription's break DocBook, so we just wrap them into <programlisting>
|
||||
+ lib.optionalString (package.meta ? longDescription) "\n<programlisting>${package.meta.longDescription}</programlisting>"
|
||||
+ "</listitem>";
|
||||
in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>";
|
||||
|
||||
optionsListDesc = lib.flip map optionsListVisible (opt: opt // {
|
||||
# Clean up declaration sites to not refer to the NixOS source tree.
|
||||
declarations = map stripAnyPrefixes opt.declarations;
|
||||
}
|
||||
// lib.optionalAttrs (opt ? example) { example = substFunction opt.example; }
|
||||
// lib.optionalAttrs (opt ? default) { default = substFunction opt.default; }
|
||||
// lib.optionalAttrs (opt ? type) { type = substFunction opt.type; }
|
||||
// lib.optionalAttrs (opt ? relatedPackages) { relatedPackages = genRelatedPackages opt.relatedPackages; });
|
||||
|
||||
# We need to strip references to /nix/store/* from options,
|
||||
# including any `extraSources` if some modules came from elsewhere,
|
||||
# or else the build will fail.
|
||||
#
|
||||
# E.g. if some `options` came from modules in ${pkgs.customModules}/nix,
|
||||
# you'd need to include `extraSources = [ pkgs.customModules ]`
|
||||
prefixesToStrip = map (p: "${toString p}/") ([ ./.. ] ++ extraSources);
|
||||
stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip;
|
||||
|
||||
# Custom "less" that pushes up all the things ending in ".enable*"
|
||||
# and ".package*"
|
||||
optionLess = a: b:
|
||||
let
|
||||
ise = lib.hasPrefix "enable";
|
||||
isp = lib.hasPrefix "package";
|
||||
cmp = lib.splitByAndCompare ise lib.compare
|
||||
(lib.splitByAndCompare isp lib.compare lib.compare);
|
||||
in lib.compareLists cmp a.loc b.loc < 0;
|
||||
|
||||
# Customly sort option list for the man page.
|
||||
optionsList = lib.sort optionLess optionsListDesc;
|
||||
|
||||
# Convert the list of options into an XML file.
|
||||
optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList);
|
||||
|
||||
optionsDocBook = runCommand "options-db.xml"
|
||||
{
|
||||
nativeBuildInputs = [ buildPackages.libxslt.bin ];
|
||||
}
|
||||
''
|
||||
optionsXML=${optionsXML}
|
||||
xsltproc \
|
||||
--stringparam program 'home-manager' \
|
||||
--stringparam revision '${revision}' \
|
||||
-o $out ${./options-to-docbook.xsl} $optionsXML
|
||||
'';
|
||||
|
||||
sources = lib.sourceFilesBySuffices ./. [".xml"];
|
||||
|
||||
modulesDoc = builtins.toFile "modules.xml" ''
|
||||
<section xmlns:xi="http://www.w3.org/2001/XInclude" id="modules">
|
||||
${(lib.concatMapStrings (path: ''
|
||||
<xi:include href="${path}" />
|
||||
'') (lib.catAttrs "value" config.meta.doc))}
|
||||
</section>
|
||||
'';
|
||||
|
||||
generatedSources = runCommand "generated-docbook" {} ''
|
||||
mkdir $out
|
||||
ln -s ${modulesDoc} $out/modules.xml
|
||||
ln -s ${optionsDocBook} $out/options-db.xml
|
||||
printf "%s" "${version}" > $out/version
|
||||
'';
|
||||
|
||||
copySources =
|
||||
''
|
||||
cp -prd $sources/* . # */
|
||||
ln -s ${generatedSources} ./generated
|
||||
chmod -R u+w .
|
||||
'';
|
||||
|
||||
toc = builtins.toFile "toc.xml"
|
||||
''
|
||||
<toc role="chunk-toc">
|
||||
<d:tocentry xmlns:d="http://docbook.org/ns/docbook" linkend="book-home-manager-manual"><?dbhtml filename="index.html"?>
|
||||
<d:tocentry linkend="ch-options"><?dbhtml filename="options.html"?></d:tocentry>
|
||||
<d:tocentry linkend="ch-release-notes"><?dbhtml filename="release-notes.html"?></d:tocentry>
|
||||
</d:tocentry>
|
||||
</toc>
|
||||
'';
|
||||
|
||||
manualXsltprocOptions = toString [
|
||||
"--param section.autolabel 1"
|
||||
"--param section.label.includes.component.label 1"
|
||||
"--stringparam html.stylesheet 'style.css overrides.css highlightjs/mono-blue.css'"
|
||||
"--stringparam html.script './highlightjs/highlight.pack.js ./highlightjs/loader.js'"
|
||||
"--param xref.with.number.and.title 1"
|
||||
"--param toc.section.depth 3"
|
||||
"--stringparam admon.style ''"
|
||||
"--stringparam callout.graphics.extension .svg"
|
||||
"--stringparam current.docid manual"
|
||||
"--param chunk.section.depth 0"
|
||||
"--param chunk.first.sections 1"
|
||||
"--param use.id.as.filename 1"
|
||||
"--stringparam generate.toc 'book toc appendix toc'"
|
||||
"--stringparam chunk.toc ${toc}"
|
||||
];
|
||||
|
||||
manual-combined = runCommand "home-manager-manual-combined"
|
||||
{ inherit sources;
|
||||
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
meta.description = "The Home Manager manual as plain docbook XML";
|
||||
}
|
||||
''
|
||||
${copySources}
|
||||
|
||||
xmllint --xinclude --output ./manual-combined.xml ./manual.xml
|
||||
xmllint --xinclude --noxincludenode \
|
||||
--output ./man-pages-combined.xml ./man-pages.xml
|
||||
|
||||
# outputs the context of an xmllint error output
|
||||
# LEN lines around the failing line are printed
|
||||
function context {
|
||||
# length of context
|
||||
local LEN=6
|
||||
# lines to print before error line
|
||||
local BEFORE=4
|
||||
|
||||
# xmllint output lines are:
|
||||
# file.xml:1234: there was an error on line 1234
|
||||
while IFS=':' read -r file line rest; do
|
||||
echo
|
||||
if [[ -n "$rest" ]]; then
|
||||
echo "$file:$line:$rest"
|
||||
local FROM=$(($line>$BEFORE ? $line - $BEFORE : 1))
|
||||
# number lines & filter context
|
||||
nl --body-numbering=a "$file" | sed -n "$FROM,+$LEN p"
|
||||
else
|
||||
if [[ -n "$line" ]]; then
|
||||
echo "$file:$line"
|
||||
else
|
||||
echo "$file"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function lintrng {
|
||||
xmllint --debug --noout --nonet \
|
||||
--relaxng ${docbook5}/xml/rng/docbook/docbook.rng \
|
||||
"$1" \
|
||||
2>&1 | context 1>&2
|
||||
# ^ redirect assumes xmllint doesn’t print to stdout
|
||||
}
|
||||
|
||||
lintrng manual-combined.xml
|
||||
lintrng man-pages-combined.xml
|
||||
|
||||
mkdir $out
|
||||
cp manual-combined.xml $out/
|
||||
cp man-pages-combined.xml $out/
|
||||
'';
|
||||
|
||||
olinkDB = runCommand "manual-olinkdb"
|
||||
{ inherit sources;
|
||||
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
}
|
||||
''
|
||||
xsltproc \
|
||||
${manualXsltprocOptions} \
|
||||
--stringparam collect.xref.targets only \
|
||||
--stringparam targets.filename "$out/manual.db" \
|
||||
--nonet \
|
||||
${docbook5_xsl}/xml/xsl/docbook/xhtml/chunktoc.xsl \
|
||||
${manual-combined}/manual-combined.xml
|
||||
|
||||
cat > "$out/olinkdb.xml" <<EOF
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE targetset SYSTEM
|
||||
"file://${docbook5_xsl}/xml/xsl/docbook/common/targetdatabase.dtd" [
|
||||
<!ENTITY manualtargets SYSTEM "file://$out/manual.db">
|
||||
]>
|
||||
<targetset>
|
||||
<targetsetinfo>
|
||||
Allows for cross-referencing olinks between the manpages
|
||||
and manual.
|
||||
</targetsetinfo>
|
||||
|
||||
<document targetdoc="manual">&manualtargets;</document>
|
||||
</targetset>
|
||||
EOF
|
||||
'';
|
||||
|
||||
in rec {
|
||||
inherit generatedSources;
|
||||
|
||||
# The Home Manager options in JSON format.
|
||||
optionsJSON = runCommand "options-json"
|
||||
{ meta.description = "List of Home Manager options in JSON format";
|
||||
}
|
||||
''
|
||||
# Export list of options in different format.
|
||||
dst=$out/share/doc/home-manager
|
||||
mkdir -p $dst
|
||||
|
||||
cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON
|
||||
(builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList))))
|
||||
} $dst/options.json
|
||||
|
||||
mkdir -p $out/nix-support
|
||||
echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products
|
||||
''; # */
|
||||
|
||||
# Generate the Home Manager manual.
|
||||
manual = runCommand "home-manager-manual"
|
||||
{ inherit sources;
|
||||
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
meta.description = "The Home Manager manual in HTML format";
|
||||
allowedReferences = ["out"];
|
||||
}
|
||||
''
|
||||
# Generate the HTML manual.
|
||||
dst=$out/share/doc/home-manager
|
||||
mkdir -p $dst
|
||||
xsltproc \
|
||||
${manualXsltprocOptions} \
|
||||
--stringparam target.database.document "${olinkDB}/olinkdb.xml" \
|
||||
--nonet --output $dst/ \
|
||||
${docbook5_xsl}/xml/xsl/docbook/xhtml/chunktoc.xsl \
|
||||
${manual-combined}/manual-combined.xml
|
||||
|
||||
mkdir -p $dst/images/callouts
|
||||
cp ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.svg $dst/images/callouts/
|
||||
|
||||
cp ${./style.css} $dst/style.css
|
||||
cp ${./overrides.css} $dst/overrides.css
|
||||
cp -r ${pkgs.documentation-highlighter} $dst/highlightjs
|
||||
|
||||
mkdir -p $out/nix-support
|
||||
echo "nix-build out $out" >> $out/nix-support/hydra-build-products
|
||||
echo "doc manual $dst" >> $out/nix-support/hydra-build-products
|
||||
''; # */
|
||||
|
||||
|
||||
manualEpub = runCommand "home-manager-manual-epub"
|
||||
{ inherit sources;
|
||||
buildInputs = [ libxml2.bin libxslt.bin zip ];
|
||||
}
|
||||
''
|
||||
# Generate the epub manual.
|
||||
dst=$out/share/doc/home-manager
|
||||
|
||||
xsltproc \
|
||||
${manualXsltprocOptions} \
|
||||
--stringparam target.database.document "${olinkDB}/olinkdb.xml" \
|
||||
--nonet --xinclude --output $dst/epub/ \
|
||||
${docbook5_xsl}/xml/xsl/docbook/epub/docbook.xsl \
|
||||
${manual-combined}/manual-combined.xml
|
||||
|
||||
mkdir -p $dst/epub/OEBPS/images/callouts
|
||||
cp -r ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.svg $dst/epub/OEBPS/images/callouts # */
|
||||
echo "application/epub+zip" > mimetype
|
||||
manual="$dst/home-manager-manual.epub"
|
||||
zip -0Xq "$manual" mimetype
|
||||
cd $dst/epub && zip -Xr9D "$manual" *
|
||||
|
||||
rm -rf $dst/epub
|
||||
|
||||
mkdir -p $out/nix-support
|
||||
echo "doc-epub manual $manual" >> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
|
||||
|
||||
# Generate the Home Manager manpages.
|
||||
manpages = runCommand "home-manager-manpages"
|
||||
{ inherit sources;
|
||||
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
|
||||
allowedReferences = ["out"];
|
||||
}
|
||||
''
|
||||
# Generate manpages.
|
||||
mkdir -p $out/share/man
|
||||
xsltproc --nonet \
|
||||
--param man.output.in.separate.dir 1 \
|
||||
--param man.output.base.dir "'$out/share/man/'" \
|
||||
--param man.endnotes.are.numbered 0 \
|
||||
--param man.break.after.slash 1 \
|
||||
--stringparam target.database.document "${olinkDB}/olinkdb.xml" \
|
||||
${docbook5_xsl}/xml/xsl/docbook/manpages/docbook.xsl \
|
||||
${manual-combined}/man-pages-combined.xml
|
||||
'';
|
||||
|
||||
}
|
||||
236
doc/installation.xml
Normal file
236
doc/installation.xml
Normal file
@@ -0,0 +1,236 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="ch-installation">
|
||||
<title>Installing Home Manager</title>
|
||||
<para>
|
||||
Home Manager can be used in three primary ways:
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Using the standalone <command>home-manager</command> tool. For platforms
|
||||
other than NixOS and Darwin, this is the only available choice. It is also
|
||||
recommended for people on NixOS or Darwin that want to manage their home
|
||||
directory independent of the system as a whole. See
|
||||
<xref linkend="sec-install-standalone"/> for instructions on how to
|
||||
perform this installation.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
As a module within a NixOS system configuration. This allows the user
|
||||
profiles to be built together with the system when running
|
||||
<command>nixos-rebuild</command>. See
|
||||
<xref linkend="sec-install-nixos-module"/> for a description of this
|
||||
setup.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
As a module within a
|
||||
<link xlink:href="https://github.com/LnL7/nix-darwin/">nix-darwin</link>
|
||||
system configuration. This allows the user profiles to be built together
|
||||
with the system when running <command>darwin-rebuild</command>. See
|
||||
<xref linkend="sec-install-nix-darwin-module"/> for a description of this
|
||||
setup.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
<section xml:id="sec-install-standalone">
|
||||
<title>Standalone installation</title>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Make sure you have a working Nix installation. If you are not using NixOS
|
||||
then it may be necessary to run
|
||||
</para>
|
||||
<screen>
|
||||
<prompt>$</prompt> <userinput>mkdir -m 0755 -p /nix/var/nix/{profiles,gcroots}/per-user/$USER</userinput>
|
||||
</screen>
|
||||
<para>
|
||||
since Home Manager uses these directories to manage your profile
|
||||
generations. On NixOS these should already be available.
|
||||
</para>
|
||||
<para>
|
||||
Also make sure that your user is able to build and install Nix packages.
|
||||
For example, you should be able to successfully run a command like
|
||||
<literal>nix-instantiate '<nixpkgs>' -A hello</literal> without
|
||||
having to switch to the root user. For a multi-user install of Nix this
|
||||
means that your user must be covered by the
|
||||
<link xlink:href="https://nixos.org/nix/manual/#conf-allowed-users"><literal>allowed-users</literal></link>
|
||||
Nix option. On NixOS you can control this option using the
|
||||
<link xlink:href="https://nixos.org/nixos/manual/options.html#opt-nix.allowedUsers"><literal>nix.allowedUsers</literal></link>
|
||||
system option.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Add the Home Manager channel that you wish to follow. This is done by
|
||||
running
|
||||
</para>
|
||||
<screen>
|
||||
<prompt>$</prompt> <userinput>nix-channel --add https://github.com/rycee/home-manager/archive/master.tar.gz home-manager</userinput>
|
||||
<prompt>$</prompt> <userinput>nix-channel --update</userinput>
|
||||
</screen>
|
||||
<para>
|
||||
if you are following Nixpkgs master or an unstable channel and
|
||||
</para>
|
||||
<screen>
|
||||
<prompt>$</prompt> <userinput>nix-channel --add https://github.com/rycee/home-manager/archive/release-18.09.tar.gz home-manager</userinput>
|
||||
<prompt>$</prompt> <userinput>nix-channel --update</userinput>
|
||||
</screen>
|
||||
<para>
|
||||
if you follow a Nixpkgs version 18.09 channel.
|
||||
</para>
|
||||
<para>
|
||||
On NixOS you may need to log out and back in for the channel to become
|
||||
available. On non-NixOS you may have to add
|
||||
<programlisting language="bash">
|
||||
export NIX_PATH=$HOME/.nix-defexpr/channels${NIX_PATH:+:}$NIX_PATH
|
||||
</programlisting>
|
||||
to your shell (see
|
||||
<link xlink:href="https://github.com/NixOS/nix/issues/2033">nix#2033</link>).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Run the Home Manager installation command and create the first Home
|
||||
Manager generation:
|
||||
</para>
|
||||
<screen>
|
||||
<prompt>$</prompt> <userinput>nix-shell '<home-manager>' -A install</userinput>
|
||||
</screen>
|
||||
<para>
|
||||
Once finished, Home Manager should be active and available in your user
|
||||
environment.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
If you do not plan on having Home Manager manage your shell configuration
|
||||
then you must source the
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh
|
||||
</programlisting>
|
||||
<para>
|
||||
file in your shell configuration. Unfortunately, we currently only support
|
||||
POSIX.2-like shells such as
|
||||
<link xlink:href="https://www.gnu.org/software/bash/">Bash</link> or
|
||||
<link xlink:href="http://zsh.sourceforge.net/">Z shell</link>.
|
||||
</para>
|
||||
<para>
|
||||
For example, if you use Bash then add
|
||||
</para>
|
||||
<programlisting language="bash">
|
||||
. "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh"
|
||||
</programlisting>
|
||||
<para>
|
||||
to your <literal>~/.profile</literal> file.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>
|
||||
If instead of using channels you want to run Home Manager from a Git
|
||||
checkout of the repository then you can use the
|
||||
<literal>programs.home-manager.path</literal> option to specify the absolute
|
||||
path to the repository.
|
||||
</para>
|
||||
</section>
|
||||
<section xml:id="sec-install-nixos-module">
|
||||
<title>NixOS module</title>
|
||||
|
||||
<para>
|
||||
Home Manager provides a NixOS module that allows you to prepare user
|
||||
environments directly from the system configuration file, which often is
|
||||
more convenient than using the <command>home-manager</command> tool. It also
|
||||
opens up additional possibilities, for example, to automatically configure
|
||||
user environments in NixOS declarative containers or on systems deployed
|
||||
through NixOps.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To make the NixOS module available for use you must <option>import</option>
|
||||
it into your system configuration. This is most conveniently done by adding
|
||||
a Home Manager channel, for example
|
||||
</para>
|
||||
|
||||
<screen>
|
||||
<prompt>#</prompt> <userinput>nix-channel --add https://github.com/rycee/home-manager/archive/master.tar.gz home-manager</userinput>
|
||||
<prompt>#</prompt> <userinput>nix-channel --update</userinput>
|
||||
</screen>
|
||||
|
||||
<para>
|
||||
if you are following Nixpkgs master or an unstable channel and
|
||||
</para>
|
||||
|
||||
<screen>
|
||||
<prompt>#</prompt> <userinput>nix-channel --add https://github.com/rycee/home-manager/archive/release-18.09.tar.gz home-manager</userinput>
|
||||
<prompt>#</prompt> <userinput>nix-channel --update</userinput>
|
||||
</screen>
|
||||
|
||||
<para>
|
||||
if you follow a Nixpkgs version 18.09 channel.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
It is then possible to add
|
||||
</para>
|
||||
|
||||
<programlisting language="nix">
|
||||
imports = [ <home-manager/nixos> ];
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
to your system <filename>configuration.nix</filename> file, which will
|
||||
introduce a new NixOS option called <option>home-manager.users</option>
|
||||
whose type is an attribute set that maps user names to Home Manager
|
||||
configurations.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For example, a NixOS configuration may include the lines
|
||||
</para>
|
||||
|
||||
<programlisting language="nix">
|
||||
users.users.eve.isNormalUser = true;
|
||||
home-manager.users.eve = { pkgs, ... }: {
|
||||
home.packages = [ pkgs.atool pkgs.httpie ];
|
||||
programs.bash.enable = true;
|
||||
};
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
and after a <command>nixos-rebuild switch</command> the user eve's
|
||||
environment should include a basic Bash configuration and the packages atool
|
||||
and httpie.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
By default packages will be installed to
|
||||
<filename>$HOME/.nix-profile</filename> but they can be installed to
|
||||
<filename>/etc/profiles</filename> if
|
||||
</para>
|
||||
<programlisting language="nix">
|
||||
home-manager.useUserPackages = true;
|
||||
</programlisting>
|
||||
<para>
|
||||
is added to the system configuration. This is necessary if, for example,
|
||||
you wish to use <command>nixos-rebuild build-vm</command>. This option may
|
||||
become the default value in the future.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
<section xml:id="sec-install-nix-darwin-module">
|
||||
<title>nix-darwin module</title>
|
||||
|
||||
<para>
|
||||
To be done.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
40
doc/man-configuration.xml
Normal file
40
doc/man-configuration.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<refmeta>
|
||||
<refentrytitle><filename>home-configuration.nix</filename></refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
<refmiscinfo class="source">Home Manager</refmiscinfo>
|
||||
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname><filename>home-configuration.nix</filename></refname>
|
||||
<refpurpose>Home Manager configuration specification</refpurpose>
|
||||
</refnamediv>
|
||||
<refsection>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
The file <filename>~/.config/nixpkgs/home.nix</filename> contains the
|
||||
declarative specification of your Home Manager configuration. The command
|
||||
<command>home-manager</command> takes this file and realises the user
|
||||
environment configuration specified therein.
|
||||
</para>
|
||||
</refsection>
|
||||
<refsection>
|
||||
<title>Options</title>
|
||||
<para>
|
||||
You can use the following options in
|
||||
<filename>home-configuration.nix</filename>:
|
||||
</para>
|
||||
<xi:include href="./generated/options-db.xml" xpointer="configuration-variable-list" />
|
||||
</refsection>
|
||||
<refsection>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<citerefentry>
|
||||
<refentrytitle>home-manager</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>
|
||||
</para>
|
||||
</refsection>
|
||||
</refentry>
|
||||
88
doc/man-home-manager.xml
Normal file
88
doc/man-home-manager.xml
Normal file
@@ -0,0 +1,88 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<refmeta>
|
||||
<refentrytitle><command>home-manager</command></refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="source">Home Manager</refmiscinfo>
|
||||
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname><command>home-manager</command></refname>
|
||||
<refpurpose>reconfigure a user environment</refpurpose>
|
||||
</refnamediv>
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>home-manager</command> <group choice="req">
|
||||
<arg choice="plain">
|
||||
<option>help</option>
|
||||
</arg>
|
||||
|
||||
<arg choice="plain">
|
||||
<option>build</option>
|
||||
</arg>
|
||||
|
||||
<arg choice="plain">
|
||||
<option>switch</option>
|
||||
</arg>
|
||||
|
||||
<arg choice="plain">
|
||||
<option>generations</option>
|
||||
</arg>
|
||||
|
||||
<arg choice="plain">
|
||||
<option>remove-generations</option>
|
||||
</arg>
|
||||
|
||||
<arg choice="plain">
|
||||
<option>packages</option>
|
||||
</arg>
|
||||
|
||||
<arg choice="plain">
|
||||
<option>news</option>
|
||||
</arg>
|
||||
</group>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
<refsection>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
This command updates the user environment so that it corresponds to the
|
||||
configuration specified in <filename>~/.config/nixpkgs/home.nix</filename>.
|
||||
</para>
|
||||
</refsection>
|
||||
<refsection>
|
||||
<title>Files</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>
|
||||
<filename>~/.local/share/home-manager/news-read-ids</filename>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Identifiers of news items that have been shown. Can be deleted to reset
|
||||
the read news indicator.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsection>
|
||||
<refsection>
|
||||
<title>Bugs</title>
|
||||
<para>
|
||||
Please report any bugs on the
|
||||
<link
|
||||
xlink:href="https://github.com/rycee/home-manager/issues">project
|
||||
issue tracker</link>.
|
||||
</para>
|
||||
</refsection>
|
||||
<refsection>
|
||||
<title>See also</title>
|
||||
<para>
|
||||
<citerefentry>
|
||||
<refentrytitle>home-configuration.nix</refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
</citerefentry>
|
||||
</para>
|
||||
</refsection>
|
||||
</refentry>
|
||||
12
doc/man-pages.xml
Normal file
12
doc/man-pages.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<reference xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<title>Home Manager Reference Pages</title>
|
||||
<info>
|
||||
<author><personname>Home Manager contributors</personname></author>
|
||||
<copyright><year>2017–2019</year><holder>Home Manager contributors</holder>
|
||||
</copyright>
|
||||
</info>
|
||||
<xi:include href="man-configuration.xml" />
|
||||
<xi:include href="man-home-manager.xml" />
|
||||
</reference>
|
||||
34
doc/manual.xml
Normal file
34
doc/manual.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<book xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="book-home-manager-manual">
|
||||
<info>
|
||||
<title>Home Manager Manual</title>
|
||||
</info>
|
||||
<preface>
|
||||
<title>Preface</title>
|
||||
<para>
|
||||
This manual will eventually describes how to install, use, and extend Home
|
||||
Manager.
|
||||
</para>
|
||||
<para>
|
||||
If you encounter problems or bugs then please report them on the
|
||||
<link xlink:href="https://github.com/rycee/home-manager/issues">Home Manager
|
||||
issue tracker</link>.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
Commands prefixed with <literal>#</literal> have to be run as root, either
|
||||
requiring to login as root user or temporarily switching to it using
|
||||
<literal>sudo</literal> for example.
|
||||
</para>
|
||||
</note>
|
||||
</preface>
|
||||
<xi:include href="installation.xml" />
|
||||
<appendix xml:id="ch-options">
|
||||
<title>Configuration Options</title>
|
||||
<xi:include href="./generated/options-db.xml" xpointer="configuration-variable-list" />
|
||||
</appendix>
|
||||
<xi:include href="./release-notes/release-notes.xml" />
|
||||
</book>
|
||||
239
doc/options-to-docbook.xsl
Normal file
239
doc/options-to-docbook.xsl
Normal file
@@ -0,0 +1,239 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:str="http://exslt.org/strings"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://docbook.org/ns/docbook"
|
||||
extension-element-prefixes="str"
|
||||
>
|
||||
|
||||
<xsl:output method='xml' encoding="UTF-8" />
|
||||
|
||||
<xsl:param name="revision" />
|
||||
<xsl:param name="program" />
|
||||
|
||||
|
||||
<xsl:template match="/expr/list">
|
||||
<appendix>
|
||||
<title>Configuration Options</title>
|
||||
<variablelist xml:id="configuration-variable-list">
|
||||
<xsl:for-each select="attrs">
|
||||
<xsl:variable name="id" select="concat('opt-', str:replace(str:replace(str:replace(str:replace(attr[@name = 'name']/string/@value, '*', '_'), '<', '_'), '>', '_'), '?', '_'))" />
|
||||
<varlistentry>
|
||||
<term xlink:href="#{$id}">
|
||||
<xsl:attribute name="xml:id"><xsl:value-of select="$id"/></xsl:attribute>
|
||||
<option>
|
||||
<xsl:value-of select="attr[@name = 'name']/string/@value" />
|
||||
</option>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
|
||||
<para>
|
||||
<xsl:value-of disable-output-escaping="yes"
|
||||
select="attr[@name = 'description']/string/@value" />
|
||||
</para>
|
||||
|
||||
<xsl:if test="attr[@name = 'type']">
|
||||
<para>
|
||||
<emphasis>Type:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of select="attr[@name = 'type']/string/@value"/>
|
||||
<xsl:if test="attr[@name = 'readOnly']/bool/@value = 'true'">
|
||||
<xsl:text> </xsl:text>
|
||||
<emphasis>(read only)</emphasis>
|
||||
</xsl:if>
|
||||
</para>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="attr[@name = 'default']">
|
||||
<para>
|
||||
<emphasis>Default:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:apply-templates select="attr[@name = 'default']" mode="top" />
|
||||
</para>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="attr[@name = 'example']">
|
||||
<para>
|
||||
<emphasis>Example:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="attr[@name = 'example']/attrs[attr[@name = '_type' and string[@value = 'literalExample']]]">
|
||||
<programlisting><xsl:value-of select="attr[@name = 'example']/attrs/attr[@name = 'text']/string/@value" /></programlisting>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:apply-templates select="attr[@name = 'example']" mode="top" />
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</para>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="attr[@name = 'relatedPackages']">
|
||||
<para>
|
||||
<emphasis>Related packages:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:value-of disable-output-escaping="yes"
|
||||
select="attr[@name = 'relatedPackages']/string/@value" />
|
||||
</para>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="count(attr[@name = 'declarations']/list/*) != 0">
|
||||
<para>
|
||||
<emphasis>Declared by:</emphasis>
|
||||
</para>
|
||||
<xsl:apply-templates select="attr[@name = 'declarations']" />
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="count(attr[@name = 'definitions']/list/*) != 0">
|
||||
<para>
|
||||
<emphasis>Defined by:</emphasis>
|
||||
</para>
|
||||
<xsl:apply-templates select="attr[@name = 'definitions']" />
|
||||
</xsl:if>
|
||||
|
||||
</listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
</xsl:for-each>
|
||||
|
||||
</variablelist>
|
||||
</appendix>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="*" mode="top">
|
||||
<xsl:choose>
|
||||
<xsl:when test="string[contains(@value, '
')]">
|
||||
<programlisting>
|
||||
<xsl:text>''
|
||||
</xsl:text><xsl:value-of select='str:replace(string/@value, "${", "''${")' /><xsl:text>''</xsl:text></programlisting>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<literal><xsl:apply-templates /></literal>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="null">
|
||||
<xsl:text>null</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="string">
|
||||
<xsl:choose>
|
||||
<xsl:when test="(contains(@value, '"') or contains(@value, '\')) and not(contains(@value, '
'))">
|
||||
<xsl:text>''</xsl:text><xsl:value-of select='str:replace(@value, "${", "''${")' /><xsl:text>''</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:text>"</xsl:text><xsl:value-of select="str:replace(str:replace(str:replace(str:replace(@value, '\', '\\'), '"', '\"'), '
', '\n'), '$', '\$')" /><xsl:text>"</xsl:text>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="int">
|
||||
<xsl:value-of select="@value" />
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="bool[@value = 'true']">
|
||||
<xsl:text>true</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="bool[@value = 'false']">
|
||||
<xsl:text>false</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="list">
|
||||
[
|
||||
<xsl:for-each select="*">
|
||||
<xsl:apply-templates select="." />
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:for-each>
|
||||
]
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="attrs[attr[@name = '_type' and string[@value = 'literalExample']]]">
|
||||
<xsl:value-of select="attr[@name = 'text']/string/@value" />
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="attrs">
|
||||
{
|
||||
<xsl:for-each select="attr">
|
||||
<xsl:value-of select="@name" />
|
||||
<xsl:text> = </xsl:text>
|
||||
<xsl:apply-templates select="*" /><xsl:text>; </xsl:text>
|
||||
</xsl:for-each>
|
||||
}
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="derivation">
|
||||
<replaceable>(build of <xsl:value-of select="attr[@name = 'name']/string/@value" />)</replaceable>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="attr[@name = 'declarations' or @name = 'definitions']">
|
||||
<simplelist>
|
||||
<xsl:for-each select="list/string">
|
||||
<member><filename>
|
||||
<!-- Hyperlink the filename either to the NixOS Subversion
|
||||
repository (if it’s a module and we have a revision number),
|
||||
or to the local filesystem. -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="not(starts-with(@value, '/'))">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$program = 'home-manager'">
|
||||
<xsl:attribute name="xlink:href">https://github.com/rycee/home-manager/blob/<xsl:value-of select="$revision"/>/<xsl:value-of select="@value"/>#blob-path</xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="$revision = 'local'">
|
||||
<xsl:attribute name="xlink:href">https://github.com/NixOS/nixpkgs/blob/master/<xsl:value-of select="@value"/></xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:attribute name="xlink:href">https://github.com/NixOS/nixpkgs/blob/<xsl:value-of select="$revision"/>/<xsl:value-of select="@value"/></xsl:attribute>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:when>
|
||||
<xsl:when test="$revision != 'local' and $program = 'nixops' and contains(@value, '/nix/')">
|
||||
<xsl:attribute name="xlink:href">https://github.com/NixOS/nixops/blob/<xsl:value-of select="$revision"/>/nix/<xsl:value-of select="substring-after(@value, '/nix/')"/></xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:attribute name="xlink:href">file://<xsl:value-of select="@value"/></xsl:attribute>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<!-- Print the filename and make it user-friendly by replacing the
|
||||
/nix/store/<hash> prefix by the default location of nixos
|
||||
sources. -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="$program = 'home-manager'">
|
||||
<home-manager/<xsl:value-of select="@value"/>>
|
||||
</xsl:when>
|
||||
<xsl:when test="not(starts-with(@value, '/'))">
|
||||
<nixpkgs/<xsl:value-of select="@value"/>>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains(@value, 'nixops') and contains(@value, '/nix/')">
|
||||
<nixops/<xsl:value-of select="substring-after(@value, '/nix/')"/>>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="@value" />
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</filename></member>
|
||||
</xsl:for-each>
|
||||
</simplelist>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="function">
|
||||
<xsl:text>λ</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
</xsl:stylesheet>
|
||||
9
doc/overrides.css
Normal file
9
doc/overrides.css
Normal file
@@ -0,0 +1,9 @@
|
||||
.docbook .xref img[src^=images\/callouts\/],
|
||||
.screen img,
|
||||
.programlisting img {
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
.calloutlist img {
|
||||
width: 1.5em;
|
||||
}
|
||||
13
doc/release-notes/release-notes.xml
Normal file
13
doc/release-notes/release-notes.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<appendix xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="ch-release-notes">
|
||||
<title>Release Notes</title>
|
||||
<para>
|
||||
This section lists the release notes for stable versions of Home Manager and
|
||||
the current unstable version.
|
||||
</para>
|
||||
<xi:include href="rl-1903.xml" />
|
||||
<xi:include href="rl-1809.xml" />
|
||||
</appendix>
|
||||
11
doc/release-notes/rl-1809.xml
Normal file
11
doc/release-notes/rl-1809.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-release-18.09">
|
||||
<title>Release 18.09</title>
|
||||
|
||||
<para>
|
||||
The 18.09 release branch became the stable branch in September, 2018.
|
||||
</para>
|
||||
</section>
|
||||
67
doc/release-notes/rl-1903.xml
Normal file
67
doc/release-notes/rl-1903.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-release-19.03">
|
||||
<title>Release 19.03 (unstable)</title>
|
||||
|
||||
<para>
|
||||
This is the current unstable branch and the information in this section is
|
||||
therefore not final.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Scheduled released is March, 2019.
|
||||
</para>
|
||||
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-release-19.03-highlights">
|
||||
<title>Highlights</title>
|
||||
|
||||
<para>
|
||||
This release has the following notable changes:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The <option>home.file.<name?>.source</option> now allows source
|
||||
files to be hidden, that is, having a name starting with the
|
||||
<literal>.</literal> character. It also allows the source file name to
|
||||
contain characters not typically allowed for Nix store paths. For example,
|
||||
your configuration can now contain things such as
|
||||
<programlisting>
|
||||
home.file."my file".source = ./. + "/file with spaces!";
|
||||
</programlisting>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="sec-release-19.03-state-version-changes">
|
||||
<title>State Version Changes</title>
|
||||
|
||||
<para>
|
||||
The state version in this release includes the changes below. These changes
|
||||
are only active if the <option>home.stateVersion</option> option is set to
|
||||
"19.03" or later.
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
There is now an option <option>programs.beets.enable</option> that
|
||||
defaults to <literal>false</literal>. Before the module would be active if
|
||||
the <option>programs.beets.settings</option> option was non-empty.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
271
doc/style.css
Normal file
271
doc/style.css
Normal file
@@ -0,0 +1,271 @@
|
||||
/* Copied from http://bakefile.sourceforge.net/, which appears
|
||||
licensed under the GNU GPL. */
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Basic headers and text:
|
||||
***************************************************************************/
|
||||
|
||||
body
|
||||
{
|
||||
font-family: "Nimbus Sans L", sans-serif;
|
||||
background: white;
|
||||
margin: 2em 1em 2em 1em;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4
|
||||
{
|
||||
color: #005aa0;
|
||||
}
|
||||
|
||||
h1 /* title */
|
||||
{
|
||||
font-size: 200%;
|
||||
}
|
||||
|
||||
h2 /* chapters, appendices, subtitle */
|
||||
{
|
||||
font-size: 180%;
|
||||
}
|
||||
|
||||
/* Extra space between chapters, appendices. */
|
||||
div.chapter > div.titlepage h2, div.appendix > div.titlepage h2
|
||||
{
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
div.section > div.titlepage h2 /* sections */
|
||||
{
|
||||
font-size: 150%;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
h3 /* subsections */
|
||||
{
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
div.simplesect h2
|
||||
{
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
div.appendix h3
|
||||
{
|
||||
font-size: 150%;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
div.refnamediv h2, div.refsynopsisdiv h2, div.refsection h2 /* refentry parts */
|
||||
{
|
||||
margin-top: 1.4em;
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
div.refsection h3
|
||||
{
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Examples:
|
||||
***************************************************************************/
|
||||
|
||||
div.example
|
||||
{
|
||||
border: 1px solid #b0b0b0;
|
||||
padding: 6px 6px;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
background: #f4f4f8;
|
||||
border-radius: 0.4em;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
div.example p.title
|
||||
{
|
||||
margin-top: 0em;
|
||||
}
|
||||
|
||||
div.example pre
|
||||
{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Screen dumps:
|
||||
***************************************************************************/
|
||||
|
||||
pre.screen, pre.programlisting
|
||||
{
|
||||
border: 1px solid #b0b0b0;
|
||||
padding: 3px 3px;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
|
||||
background: #f4f4f8;
|
||||
font-family: monospace;
|
||||
border-radius: 0.4em;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
div.example pre.programlisting
|
||||
{
|
||||
border: 0px;
|
||||
padding: 0 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Notes, warnings etc:
|
||||
***************************************************************************/
|
||||
|
||||
.note, .warning
|
||||
{
|
||||
border: 1px solid #b0b0b0;
|
||||
padding: 3px 3px;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
margin-bottom: 1em;
|
||||
padding: 0.3em 0.3em 0.3em 0.3em;
|
||||
background: #fffff5;
|
||||
border-radius: 0.4em;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
div.note, div.warning
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.note h3, div.warning h3
|
||||
{
|
||||
color: red;
|
||||
font-size: 100%;
|
||||
padding-right: 0.5em;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.note p, div.warning p
|
||||
{
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
div.note h3 + p, div.warning h3 + p
|
||||
{
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.note h3
|
||||
{
|
||||
color: blue;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
div.navfooter *
|
||||
{
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Links colors and highlighting:
|
||||
***************************************************************************/
|
||||
|
||||
a { text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
a:link { color: #0048b3; }
|
||||
a:visited { color: #002a6a; }
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Table of contents:
|
||||
***************************************************************************/
|
||||
|
||||
div.toc
|
||||
{
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.toc dl
|
||||
{
|
||||
margin-top: 0em;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Special elements:
|
||||
***************************************************************************/
|
||||
|
||||
tt, code
|
||||
{
|
||||
color: #400000;
|
||||
}
|
||||
|
||||
.term
|
||||
{
|
||||
font-weight: bold;
|
||||
|
||||
}
|
||||
|
||||
div.variablelist dd p, div.glosslist dd p
|
||||
{
|
||||
margin-top: 0em;
|
||||
}
|
||||
|
||||
div.variablelist dd, div.glosslist dd
|
||||
{
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
div.glosslist dt
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.varname
|
||||
{
|
||||
color: #400000;
|
||||
}
|
||||
|
||||
span.command strong
|
||||
{
|
||||
font-weight: normal;
|
||||
color: #400000;
|
||||
}
|
||||
|
||||
div.calloutlist table
|
||||
{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
border-collapse: collapse;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
table.simplelist
|
||||
{
|
||||
text-align: left;
|
||||
color: #005aa0;
|
||||
border: 0;
|
||||
padding: 5px;
|
||||
background: #fffff5;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
box-shadow: none;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
div.navheader table, div.navfooter table {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
div.affiliation
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
@@ -1,41 +1,37 @@
|
||||
{ pkgs, modulesPath ? "$HOME/.config/nixpkgs/home-manager/modules" }:
|
||||
{ pkgs
|
||||
|
||||
# Extra path to Home Manager. If set then this path will be tried
|
||||
# before `$HOME/.config/nixpkgs/home-manager` and
|
||||
# `$HOME/.nixpkgs/home-manager`.
|
||||
, path ? null
|
||||
}:
|
||||
|
||||
let
|
||||
|
||||
homeManagerExpr = pkgs.writeText "home-manager.nix" ''
|
||||
{ pkgs ? import <nixpkgs> {}, confPath }:
|
||||
|
||||
let
|
||||
env = import <home-manager> {
|
||||
configuration = import confPath;
|
||||
pkgs = pkgs;
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit (env) activation-script;
|
||||
}
|
||||
'';
|
||||
pathStr = if path == null then "" else path;
|
||||
|
||||
in
|
||||
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "home-manager";
|
||||
|
||||
phases = [ "installPhase" ];
|
||||
|
||||
installPhase = ''
|
||||
install -v -D -m755 ${./home-manager} $out/bin/home-manager
|
||||
pkgs.runCommand
|
||||
"home-manager"
|
||||
{
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
meta = with pkgs.stdenv.lib; {
|
||||
description = "A user environment configurator";
|
||||
maintainers = [ maintainers.rycee ];
|
||||
platforms = platforms.unix;
|
||||
license = licenses.mit;
|
||||
};
|
||||
}
|
||||
''
|
||||
install -v -D -m755 ${./home-manager} $out/bin/home-manager
|
||||
|
||||
substituteInPlace $out/bin/home-manager \
|
||||
--subst-var-by bash "${pkgs.bash}" \
|
||||
--subst-var-by coreutils "${pkgs.coreutils}" \
|
||||
--subst-var-by MODULES_PATH '${modulesPath}' \
|
||||
--subst-var-by HOME_MANAGER_EXPR_PATH "${homeManagerExpr}"
|
||||
'';
|
||||
|
||||
meta = with pkgs.stdenv.lib; {
|
||||
description = "A user environment configurator";
|
||||
maintainers = [ maintainers.rycee ];
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
}
|
||||
--subst-var-by findutils "${pkgs.findutils}" \
|
||||
--subst-var-by gnused "${pkgs.gnused}" \
|
||||
--subst-var-by less "${pkgs.less}" \
|
||||
--subst-var-by HOME_MANAGER_PATH '${pathStr}'
|
||||
''
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
#!@bash@/bin/bash
|
||||
|
||||
# This code explicitly requires GNU Core Utilities and we therefore
|
||||
# need to ensure they are prioritized over any other similarly named
|
||||
# tools on the system.
|
||||
PATH=@coreutils@/bin:$PATH
|
||||
# Prepare to use tools from Nixpkgs.
|
||||
PATH=@coreutils@/bin:@findutils@/bin:@gnused@/bin:@less@/bin${PATH:+:}$PATH
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
function errorEcho() {
|
||||
# shellcheck disable=2048,2086
|
||||
echo $* >&2
|
||||
}
|
||||
|
||||
function setWorkDir() {
|
||||
if [[ ! -v WORK_DIR ]]; then
|
||||
WORK_DIR="$(mktemp --tmpdir -d home-manager-build.XXXXXXXXXX)"
|
||||
# shellcheck disable=2064
|
||||
trap "rm -r '$WORK_DIR'" EXIT
|
||||
fi
|
||||
}
|
||||
|
||||
# Attempts to set the HOME_MANAGER_CONFIG global variable.
|
||||
#
|
||||
# If no configuration file can be found then this function will print
|
||||
@@ -14,7 +25,7 @@ set -euo pipefail
|
||||
function setConfigFile() {
|
||||
if [[ -v HOME_MANAGER_CONFIG ]] ; then
|
||||
if [[ ! -e "$HOME_MANAGER_CONFIG" ]] ; then
|
||||
echo "No configure file found at $HOME_MANAGER_CONFIG"
|
||||
errorEcho "No configuration file found at $HOME_MANAGER_CONFIG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -22,55 +33,38 @@ function setConfigFile() {
|
||||
return
|
||||
fi
|
||||
|
||||
local defaultConfFile="${XDG_CONFIG_HOME:-$HOME/.config}/nixpkgs/home.nix"
|
||||
local confFile
|
||||
for confFile in "$HOME/.config/nixpkgs/home.nix" \
|
||||
for confFile in "$defaultConfFile" \
|
||||
"$HOME/.nixpkgs/home.nix" ; do
|
||||
if [[ -e "$confFile" ]] ; then
|
||||
HOME_MANAGER_CONFIG="$confFile"
|
||||
HOME_MANAGER_CONFIG="$(realpath "$confFile")"
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
echo "No configuration file found. " \
|
||||
"Please create one at ~/.config/nixpkgs/home.nix"
|
||||
errorEcho "No configuration file found." \
|
||||
"Please create one at $defaultConfFile"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function setHomeManagerModulesPath() {
|
||||
local modulesPath
|
||||
for modulesPath in "@MODULES_PATH@" \
|
||||
"$HOME/.nixpkgs/home-manager/modules" ; do
|
||||
if [[ -e "$modulesPath" ]] ; then
|
||||
export NIX_PATH="$NIX_PATH${NIX_PATH:+:}home-manager=$modulesPath"
|
||||
function setHomeManagerNixPath() {
|
||||
local path
|
||||
for path in "@HOME_MANAGER_PATH@" \
|
||||
"${XDG_CONFIG_HOME:-$HOME/.config}/nixpkgs/home-manager" \
|
||||
"$HOME/.nixpkgs/home-manager" ; do
|
||||
if [[ -e "$path" || "$path" =~ ^https?:// ]] ; then
|
||||
export NIX_PATH="home-manager=$path${NIX_PATH:+:}$NIX_PATH"
|
||||
return
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function doBuild() {
|
||||
if [[ -z "$1" ]]; then
|
||||
echo "Need to provide generation output path."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -e "$1" ]]; then
|
||||
echo "The output path $1 already exists."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function doBuildAttr() {
|
||||
setConfigFile
|
||||
setHomeManagerModulesPath
|
||||
setHomeManagerNixPath
|
||||
|
||||
output="$(realpath "$1")"
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export NIX_PATH="$NIX_PATH${NIX_PATH:+:}home-manager=@MODULES_PATH@"
|
||||
|
||||
local extraArgs
|
||||
extraArgs=""
|
||||
local extraArgs="$*"
|
||||
|
||||
for p in "${EXTRA_NIX_PATH[@]}"; do
|
||||
extraArgs="$extraArgs -I $p"
|
||||
@@ -80,38 +74,276 @@ function doBuild() {
|
||||
extraArgs="$extraArgs --show-trace"
|
||||
fi
|
||||
|
||||
nix-build $extraArgs \
|
||||
"@HOME_MANAGER_EXPR_PATH@" \
|
||||
--argstr confPath "$HOME_MANAGER_CONFIG" \
|
||||
-A activation-script \
|
||||
-o "$output"
|
||||
# shellcheck disable=2086
|
||||
if [[ -v USE_NIX2_COMMAND ]]; then
|
||||
nix build \
|
||||
-f "<home-manager/home-manager/home-manager.nix>" \
|
||||
$extraArgs \
|
||||
--argstr confPath "$HOME_MANAGER_CONFIG" \
|
||||
--argstr confAttr "$HOME_MANAGER_CONFIG_ATTRIBUTE"
|
||||
else
|
||||
nix-build \
|
||||
"<home-manager/home-manager/home-manager.nix>" \
|
||||
$extraArgs \
|
||||
--argstr confPath "$HOME_MANAGER_CONFIG" \
|
||||
--argstr confAttr "$HOME_MANAGER_CONFIG_ATTRIBUTE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Presents news to the user. Takes as argument the path to a "news
|
||||
# info" file as generated by `buildNews`.
|
||||
function presentNews() {
|
||||
local infoFile="$1"
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$infoFile"
|
||||
|
||||
# shellcheck disable=2154
|
||||
if [[ $newsNumUnread -eq 0 ]]; then
|
||||
return
|
||||
elif [[ "$newsDisplay" == "silent" ]]; then
|
||||
return
|
||||
elif [[ "$newsDisplay" == "notify" ]]; then
|
||||
local msg
|
||||
if [[ $newsNumUnread -eq 1 ]]; then
|
||||
msg="There is an unread and relevant news item.\n"
|
||||
msg+="Read it by running the command '$(basename "$0") news'."
|
||||
else
|
||||
msg="There are $newsNumUnread unread and relevant news items.\n"
|
||||
msg+="Read them by running the command '$(basename "$0") news'."
|
||||
fi
|
||||
|
||||
# Not actually an error but here stdout is reserved for
|
||||
# nix-build output.
|
||||
errorEcho
|
||||
errorEcho -e "$msg"
|
||||
errorEcho
|
||||
|
||||
if [[ -v DISPLAY ]] && type -P notify-send > /dev/null; then
|
||||
notify-send "Home Manager" "$msg"
|
||||
fi
|
||||
elif [[ "$newsDisplay" == "show" ]]; then
|
||||
doShowNews --unread
|
||||
else
|
||||
errorEcho "Unknown 'news.display' setting '$newsDisplay'."
|
||||
fi
|
||||
}
|
||||
|
||||
function doEdit() {
|
||||
if [[ ! -v EDITOR || -z $EDITOR ]]; then
|
||||
errorEcho "Please set the \$EDITOR environment variable"
|
||||
return 1
|
||||
fi
|
||||
|
||||
setConfigFile
|
||||
|
||||
exec "$EDITOR" "$HOME_MANAGER_CONFIG"
|
||||
}
|
||||
|
||||
function doBuild() {
|
||||
if [[ ! -w . ]]; then
|
||||
errorEcho "Cannot run build in read-only directory";
|
||||
return 1
|
||||
fi
|
||||
|
||||
setWorkDir
|
||||
|
||||
local newsInfo
|
||||
newsInfo=$(buildNews)
|
||||
|
||||
local exitCode
|
||||
|
||||
if [[ -v USE_NIX2_COMMAND ]]; then
|
||||
doBuildAttr activationPackage \
|
||||
&& exitCode=0 || exitCode=1
|
||||
else
|
||||
doBuildAttr --attr activationPackage \
|
||||
&& exitCode=0 || exitCode=1
|
||||
fi
|
||||
|
||||
presentNews "$newsInfo"
|
||||
|
||||
return $exitCode
|
||||
}
|
||||
|
||||
function doSwitch() {
|
||||
local wrkdir
|
||||
wrkdir="$(mktemp -d)"
|
||||
setWorkDir
|
||||
|
||||
if doBuild "$wrkdir/generation" ; then
|
||||
"$wrkdir/generation/activate"
|
||||
local newsInfo
|
||||
newsInfo=$(buildNews)
|
||||
|
||||
local generation
|
||||
local exitCode=0
|
||||
|
||||
# Build the generation and run the activate script. Note, we
|
||||
# specify an output link so that it is treated as a GC root. This
|
||||
# prevents an unfortunately timed GC from removing the generation
|
||||
# before activation completes.
|
||||
generation="$WORK_DIR/generation"
|
||||
|
||||
if [[ -v USE_NIX2_COMMAND ]]; then
|
||||
doBuildAttr \
|
||||
--out-link "$generation" \
|
||||
activationPackage \
|
||||
&& "$generation/activate" || exitCode=1
|
||||
else
|
||||
doBuildAttr \
|
||||
--out-link "$generation" \
|
||||
--attr activationPackage \
|
||||
&& "$generation/activate" || exitCode=1
|
||||
fi
|
||||
|
||||
rm -r "$wrkdir"
|
||||
presentNews "$newsInfo"
|
||||
|
||||
return $exitCode
|
||||
}
|
||||
|
||||
function doListGens() {
|
||||
# Whether to colorize the generations output.
|
||||
local color="never"
|
||||
if [[ -t 1 ]]; then
|
||||
color="always"
|
||||
fi
|
||||
|
||||
pushd "/nix/var/nix/profiles/per-user/$USER" > /dev/null
|
||||
ls --color=yes -gG --sort time home-manager-*-link \
|
||||
| cut -d' ' -f 4-
|
||||
# shellcheck disable=2012
|
||||
ls --color=$color -gG --time-style=long-iso --sort time home-manager-*-link \
|
||||
| cut -d' ' -f 4- \
|
||||
| sed -E 's/home-manager-([[:digit:]]*)-link/: id \1/'
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
# Removes linked generations. Takes as arguments identifiers of
|
||||
# generations to remove.
|
||||
function doRmGenerations() {
|
||||
if [[ -v VERBOSE ]]; then
|
||||
export VERBOSE_ARG="--verbose"
|
||||
else
|
||||
export VERBOSE_ARG=""
|
||||
fi
|
||||
|
||||
if [[ -v DRY_RUN ]] ; then
|
||||
export DRY_RUN_CMD=echo
|
||||
else
|
||||
export DRY_RUN_CMD=""
|
||||
fi
|
||||
|
||||
pushd "/nix/var/nix/profiles/per-user/$USER" > /dev/null
|
||||
|
||||
for generationId in "$@"; do
|
||||
local linkName="home-manager-$generationId-link"
|
||||
|
||||
if [[ ! -e $linkName ]]; then
|
||||
errorEcho "No generation with ID $generationId"
|
||||
elif [[ $linkName == $(readlink home-manager) ]]; then
|
||||
errorEcho "Cannot remove the current generation $generationId"
|
||||
else
|
||||
echo Removing generation $generationId
|
||||
$DRY_RUN_CMD rm $VERBOSE_ARG $linkName
|
||||
fi
|
||||
done
|
||||
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
function doExpireGenerations() {
|
||||
local profileDir="/nix/var/nix/profiles/per-user/$USER"
|
||||
|
||||
local generations
|
||||
generations="$( \
|
||||
find "$profileDir" -name 'home-manager-*-link' -not -newermt "$1" \
|
||||
| sed 's/^.*-\([0-9]*\)-link$/\1/' \
|
||||
)"
|
||||
|
||||
if [[ -n $generations ]]; then
|
||||
# shellcheck disable=2086
|
||||
doRmGenerations $generations
|
||||
elif [[ -v VERBOSE ]]; then
|
||||
echo "No generations to expire"
|
||||
fi
|
||||
}
|
||||
|
||||
function doListPackages() {
|
||||
local outPath
|
||||
outPath="$(nix-env -q --out-path | grep -o '/.*home-manager-path$')"
|
||||
if [[ -n "$outPath" ]] ; then
|
||||
nix-store -q --references "$outPath" | sed 's/[^-]*-//'
|
||||
else
|
||||
echo "No home-manager packages seem to be installed."
|
||||
errorEcho "No home-manager packages seem to be installed."
|
||||
fi
|
||||
}
|
||||
|
||||
function newsReadIdsFile() {
|
||||
local dataDir="${XDG_DATA_HOME:-$HOME/.local/share}/home-manager"
|
||||
local path="$dataDir/news-read-ids"
|
||||
|
||||
# If the path doesn't exist then we should create it, otherwise
|
||||
# Nix will error out when we attempt to use builtins.readFile.
|
||||
if [[ ! -f "$path" ]]; then
|
||||
mkdir -p "$dataDir"
|
||||
touch "$path"
|
||||
fi
|
||||
|
||||
echo "$path"
|
||||
}
|
||||
|
||||
# Builds news meta information to be sourced into this script.
|
||||
#
|
||||
# Note, we suppress build output to remove unnecessary verbosity. We
|
||||
# put the output in the work directory to avoid the risk of an
|
||||
# unfortunately timed GC removing it.
|
||||
function buildNews() {
|
||||
local output
|
||||
output="$WORK_DIR/news-info.sh"
|
||||
|
||||
if [[ -v USE_NIX2_COMMAND ]]; then
|
||||
doBuildAttr \
|
||||
--out-link "$output" \
|
||||
--quiet \
|
||||
--arg check false \
|
||||
--argstr newsReadIdsFile "$(newsReadIdsFile)" \
|
||||
newsInfo
|
||||
else
|
||||
doBuildAttr \
|
||||
--out-link "$output" \
|
||||
--no-build-output \
|
||||
--quiet \
|
||||
--arg check false \
|
||||
--argstr newsReadIdsFile "$(newsReadIdsFile)" \
|
||||
--attr newsInfo \
|
||||
> /dev/null
|
||||
fi
|
||||
|
||||
echo "$output"
|
||||
}
|
||||
|
||||
function doShowNews() {
|
||||
setWorkDir
|
||||
|
||||
local infoFile
|
||||
infoFile=$(buildNews) || return 1
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$infoFile"
|
||||
|
||||
# shellcheck disable=2154
|
||||
case $1 in
|
||||
--all)
|
||||
${PAGER:-less} "$newsFileAll"
|
||||
;;
|
||||
--unread)
|
||||
${PAGER:-less} "$newsFileUnread"
|
||||
;;
|
||||
*)
|
||||
errorEcho "Unknown argument $1"
|
||||
return 1
|
||||
esac
|
||||
|
||||
# shellcheck disable=2154
|
||||
if [[ -s "$newsUnreadIdsFile" ]]; then
|
||||
local newsReadIdsFile
|
||||
newsReadIdsFile="$(newsReadIdsFile)"
|
||||
cat "$newsUnreadIdsFile" >> "$newsReadIdsFile"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -122,29 +354,65 @@ function doHelp() {
|
||||
echo
|
||||
echo " -f FILE The home configuration file."
|
||||
echo " Default is '~/.config/nixpkgs/home.nix'."
|
||||
echo " -A ATTRIBUTE Optional attribute that selects a configuration"
|
||||
echo " expression in the configuration file."
|
||||
echo " -I PATH Add a path to the Nix expression search path."
|
||||
echo " -v Verbose output"
|
||||
echo " -n Do a dry run, only prints what actions would be taken"
|
||||
echo " -h Print this help"
|
||||
echo
|
||||
echo "Commands"
|
||||
echo
|
||||
echo " help Print this help"
|
||||
echo
|
||||
echo " edit Open the home configuration in \$EDITOR"
|
||||
echo
|
||||
echo " build Build configuration into result directory"
|
||||
echo
|
||||
echo " switch Build and activate configuration"
|
||||
echo
|
||||
echo " generations List all home environment generations"
|
||||
echo
|
||||
echo " remove-generations ID..."
|
||||
echo " Remove indicated generations. Use 'generations' command to"
|
||||
echo " find suitable generation numbers."
|
||||
echo
|
||||
echo " expire-generations TIMESTAMP"
|
||||
echo " Remove generations older than TIMESTAMP where TIMESTAMP is"
|
||||
echo " interpreted as in the -d argument of the date tool. For"
|
||||
echo " example \"-30 days\" or \"2018-01-01\"."
|
||||
echo
|
||||
echo " packages List all packages installed in home-manager-path"
|
||||
echo
|
||||
echo " news Show news entries in a pager"
|
||||
}
|
||||
|
||||
EXTRA_NIX_PATH=()
|
||||
HOME_MANAGER_CONFIG_ATTRIBUTE=""
|
||||
|
||||
while getopts f:I:vnh opt; do
|
||||
# As a special case, if the user has given --help anywhere on the
|
||||
# command line then print help and exit.
|
||||
for arg in "$@"; do
|
||||
if [[ $arg == "--help" ]]; then
|
||||
doHelp
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
|
||||
while getopts 2f:I:A:vnh opt; do
|
||||
case $opt in
|
||||
2)
|
||||
USE_NIX2_COMMAND=1
|
||||
;;
|
||||
f)
|
||||
HOME_MANAGER_CONFIG="$OPTARG"
|
||||
;;
|
||||
I)
|
||||
EXTRA_NIX_PATH+=("$OPTARG")
|
||||
;;
|
||||
A)
|
||||
HOME_MANAGER_CONFIG_ATTRIBUTE="$OPTARG"
|
||||
;;
|
||||
v)
|
||||
export VERBOSE=1
|
||||
;;
|
||||
@@ -156,7 +424,7 @@ while getopts f:I:vnh opt; do
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option -$OPTARG" >&2
|
||||
errorEcho "Unknown option -$OPTARG"
|
||||
doHelp >&2
|
||||
exit 1
|
||||
;;
|
||||
@@ -166,11 +434,20 @@ done
|
||||
# Get rid of the options.
|
||||
shift "$((OPTIND-1))"
|
||||
|
||||
cmd="$*"
|
||||
if [[ $# -eq 0 ]]; then
|
||||
doHelp >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cmd="$1"
|
||||
shift 1
|
||||
|
||||
case "$cmd" in
|
||||
edit)
|
||||
doEdit
|
||||
;;
|
||||
build)
|
||||
doBuild "result"
|
||||
doBuild
|
||||
;;
|
||||
switch)
|
||||
doSwitch
|
||||
@@ -178,14 +455,23 @@ case "$cmd" in
|
||||
generations)
|
||||
doListGens
|
||||
;;
|
||||
remove-generations)
|
||||
doRmGenerations "$@"
|
||||
;;
|
||||
expire-generations)
|
||||
doExpireGenerations "$@"
|
||||
;;
|
||||
packages)
|
||||
doListPackages
|
||||
;;
|
||||
news)
|
||||
doShowNews --all
|
||||
;;
|
||||
help|--help)
|
||||
doHelp
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command: $cmd"
|
||||
errorEcho "Unknown command: $cmd"
|
||||
doHelp >&2
|
||||
exit 1
|
||||
;;
|
||||
|
||||
88
home-manager/home-manager.nix
Normal file
88
home-manager/home-manager.nix
Normal file
@@ -0,0 +1,88 @@
|
||||
{ pkgs ? import <nixpkgs> {}
|
||||
, confPath
|
||||
, confAttr
|
||||
, check ? true
|
||||
, newsReadIdsFile ? null
|
||||
}:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
env = import ../modules {
|
||||
configuration =
|
||||
if confAttr == ""
|
||||
then confPath
|
||||
else (import confPath).${confAttr};
|
||||
pkgs = pkgs;
|
||||
check = check;
|
||||
};
|
||||
|
||||
newsReadIds =
|
||||
if newsReadIdsFile == null
|
||||
then {}
|
||||
else
|
||||
let
|
||||
ids = splitString "\n" (fileContents newsReadIdsFile);
|
||||
in
|
||||
builtins.listToAttrs (map (id: { name = id; value = null; }) ids);
|
||||
|
||||
newsIsRead = entry: builtins.hasAttr entry.id newsReadIds;
|
||||
|
||||
newsFiltered =
|
||||
let
|
||||
pred = entry: entry.condition && ! newsIsRead entry;
|
||||
in
|
||||
filter pred env.newsEntries;
|
||||
|
||||
newsNumUnread = length newsFiltered;
|
||||
|
||||
newsFileUnread = pkgs.writeText "news-unread.txt" (
|
||||
concatMapStringsSep "\n\n" (entry:
|
||||
let
|
||||
time = replaceStrings ["T"] [" "] (removeSuffix "+00:00" entry.time);
|
||||
in
|
||||
''
|
||||
* ${time}
|
||||
|
||||
${replaceStrings ["\n"] ["\n "] entry.message}
|
||||
''
|
||||
) newsFiltered
|
||||
);
|
||||
|
||||
newsFileAll = pkgs.writeText "news-all.txt" (
|
||||
concatMapStringsSep "\n\n" (entry:
|
||||
let
|
||||
flag = if newsIsRead entry then "read" else "unread";
|
||||
time = replaceStrings ["T"] [" "] (removeSuffix "+00:00" entry.time);
|
||||
in
|
||||
''
|
||||
* ${time} [${flag}]
|
||||
|
||||
${replaceStrings ["\n"] ["\n "] entry.message}
|
||||
''
|
||||
) env.newsEntries
|
||||
);
|
||||
|
||||
# File where each line corresponds to an unread news entry
|
||||
# identifier. If non-empty then the file ends in "\n".
|
||||
newsUnreadIdsFile = pkgs.writeText "news-unread-ids" (
|
||||
let
|
||||
text = concatMapStringsSep "\n" (entry: entry.id) newsFiltered;
|
||||
in
|
||||
text + optionalString (text != "") "\n"
|
||||
);
|
||||
|
||||
newsInfo = pkgs.writeText "news-info.sh" ''
|
||||
local newsNumUnread=${toString newsNumUnread}
|
||||
local newsDisplay="${env.newsDisplay}"
|
||||
local newsFileAll="${newsFileAll}"
|
||||
local newsFileUnread="${newsFileUnread}"
|
||||
local newsUnreadIdsFile="${newsUnreadIdsFile}"
|
||||
'';
|
||||
|
||||
in
|
||||
{
|
||||
inherit (env) activationPackage;
|
||||
inherit newsInfo;
|
||||
}
|
||||
56
home-manager/install.nix
Normal file
56
home-manager/install.nix
Normal file
@@ -0,0 +1,56 @@
|
||||
{ home-manager, pkgs }:
|
||||
|
||||
pkgs.runCommand
|
||||
"home-manager-install"
|
||||
{
|
||||
propagatedBuildInputs = [ home-manager ];
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
shellHook = ''
|
||||
confFile="''${XDG_CONFIG_HOME:-$HOME/.config}/nixpkgs/home.nix"
|
||||
|
||||
if [[ ! -e $confFile ]]; then
|
||||
echo
|
||||
echo "Creating initial Home Manager configuration..."
|
||||
|
||||
mkdir -p "$(dirname "$confFile")"
|
||||
cat > $confFile <<EOF
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
# Let Home Manager install and manage itself.
|
||||
programs.home-manager.enable = true;
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Creating initial Home Manager generation..."
|
||||
echo
|
||||
|
||||
if home-manager switch; then
|
||||
cat <<EOF
|
||||
|
||||
All done! The home-manager tool should now be installed and you
|
||||
can edit
|
||||
|
||||
$confFile
|
||||
|
||||
to configure Home Manager. Run 'man home-configuration.nix' to
|
||||
see all available options.
|
||||
EOF
|
||||
exit 0
|
||||
else
|
||||
cat <<EOF
|
||||
|
||||
Uh oh, the installation failed! Please create an issue at
|
||||
|
||||
https://github.com/rycee/home-manager/issues
|
||||
|
||||
if the error seems to be the fault of Home Manager.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
}
|
||||
""
|
||||
414
modules/accounts/email.nix
Normal file
414
modules/accounts/email.nix
Normal file
@@ -0,0 +1,414 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.accounts.email;
|
||||
|
||||
gpgModule = types.submodule {
|
||||
options = {
|
||||
key = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
The key to use as listed in <command>gpg --list-keys</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
signByDefault = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Sign messages by default.";
|
||||
};
|
||||
|
||||
encryptByDefault = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Encrypt outgoing messages by default.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
signatureModule = types.submodule {
|
||||
options = {
|
||||
text = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = ''
|
||||
--
|
||||
Luke Skywalker
|
||||
May the force be with you.
|
||||
'';
|
||||
description = ''
|
||||
Signature content.
|
||||
'';
|
||||
};
|
||||
|
||||
showSignature = mkOption {
|
||||
type = types.enum [ "append" "attach" "none" ];
|
||||
default = "none";
|
||||
description = "Method to communicate the signature.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
tlsModule = types.submodule {
|
||||
options = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable TLS/SSL.
|
||||
'';
|
||||
};
|
||||
|
||||
useStartTls = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to use STARTTLS.
|
||||
'';
|
||||
};
|
||||
|
||||
certificatesFile = mkOption {
|
||||
type = types.path;
|
||||
default = config.accounts.email.certificatesFile;
|
||||
defaultText = "config.accounts.email.certificatesFile";
|
||||
description = ''
|
||||
Path to file containing certificate authorities that should
|
||||
be used to validate the connection authenticity. If
|
||||
<literal>null</literal> then the system default is used.
|
||||
Note, if set then the system default may still be accepted.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
imapModule = types.submodule {
|
||||
options = {
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
example = "imap.example.org";
|
||||
description = ''
|
||||
Hostname of IMAP server.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.nullOr types.ints.positive;
|
||||
default = null;
|
||||
example = 993;
|
||||
description = ''
|
||||
The port on which the IMAP server listens. If
|
||||
<literal>null</literal> then the default port is used.
|
||||
'';
|
||||
};
|
||||
|
||||
tls = mkOption {
|
||||
type = tlsModule;
|
||||
default = {};
|
||||
description = ''
|
||||
Configuration for secure connections.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
smtpModule = types.submodule {
|
||||
options = {
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
example = "smtp.example.org";
|
||||
description = ''
|
||||
Hostname of SMTP server.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.nullOr types.ints.positive;
|
||||
default = null;
|
||||
example = 465;
|
||||
description = ''
|
||||
The port on which the SMTP server listens. If
|
||||
<literal>null</literal> then the default port is used.
|
||||
'';
|
||||
};
|
||||
|
||||
tls = mkOption {
|
||||
type = tlsModule;
|
||||
default = {};
|
||||
description = ''
|
||||
Configuration for secure connections.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
maildirModule = types.submodule ({ config, ... }: {
|
||||
options = {
|
||||
path = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Path to maildir directory where mail for this account is
|
||||
stored. This is relative to the base maildir path.
|
||||
'';
|
||||
};
|
||||
|
||||
absPath = mkOption {
|
||||
type = types.path;
|
||||
readOnly = true;
|
||||
internal = true;
|
||||
default = "${cfg.maildirBasePath}/${config.path}";
|
||||
description = ''
|
||||
A convenience option whose value is the absolute path of
|
||||
this maildir.
|
||||
'';
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
mailAccountOpts = { name, config, ... }: {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
Unique identifier of the account. This is set to the
|
||||
attribute name of the account configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
primary = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether this is the primary account. Only one account may be
|
||||
set as primary.
|
||||
'';
|
||||
};
|
||||
|
||||
flavor = mkOption {
|
||||
type = types.enum [ "plain" "gmail.com" "runbox.com" ];
|
||||
default = "plain";
|
||||
description = ''
|
||||
Some email providers have peculiar behavior that require
|
||||
special treatment. This option is therefore intended to
|
||||
indicate the nature of the provider.
|
||||
</para><para>
|
||||
When this indicates a specific provider then, for example,
|
||||
the IMAP and SMTP server configuration may be set
|
||||
automatically.
|
||||
'';
|
||||
};
|
||||
|
||||
address = mkOption {
|
||||
type = types.strMatching ".*@.*";
|
||||
example = "jane.doe@example.org";
|
||||
description = "The email address of this account.";
|
||||
};
|
||||
|
||||
realName = mkOption {
|
||||
type = types.str;
|
||||
example = "Jane Doe";
|
||||
description = "Name displayed when sending mails.";
|
||||
};
|
||||
|
||||
userName = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
The server username of this account. This will be used as
|
||||
the SMTP and IMAP user name.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordCommand = mkOption {
|
||||
type = types.nullOr (types.either types.str (types.listOf types.str));
|
||||
default = null;
|
||||
apply = p: if isString p then splitString " " p else p;
|
||||
example = "secret-tool lookup email me@example.org";
|
||||
description = ''
|
||||
A command, which when run writes the account password on
|
||||
standard output.
|
||||
'';
|
||||
};
|
||||
|
||||
folders = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
inbox = mkOption {
|
||||
type = types.str;
|
||||
default = "Inbox";
|
||||
description = ''
|
||||
Relative path of the inbox mail.
|
||||
'';
|
||||
};
|
||||
|
||||
sent = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = "Sent";
|
||||
description = ''
|
||||
Relative path of the sent mail folder.
|
||||
'';
|
||||
};
|
||||
|
||||
drafts = mkOption {
|
||||
type = types.str;
|
||||
default = "Drafts";
|
||||
description = ''
|
||||
Relative path of the drafts mail folder.
|
||||
'';
|
||||
};
|
||||
|
||||
trash = mkOption {
|
||||
type = types.str;
|
||||
default = "Trash";
|
||||
description = ''
|
||||
Relative path of the deleted mail folder.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = ''
|
||||
Standard email folders.
|
||||
'';
|
||||
};
|
||||
|
||||
imap = mkOption {
|
||||
type = types.nullOr imapModule;
|
||||
default = null;
|
||||
description = ''
|
||||
The IMAP configuration to use for this account.
|
||||
'';
|
||||
};
|
||||
|
||||
signature = mkOption {
|
||||
type = signatureModule;
|
||||
default = {};
|
||||
description = ''
|
||||
Signature configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
gpg = mkOption {
|
||||
type = types.nullOr gpgModule;
|
||||
default = null;
|
||||
description = ''
|
||||
GPG configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
smtp = mkOption {
|
||||
type = types.nullOr smtpModule;
|
||||
default = null;
|
||||
description = ''
|
||||
The SMTP configuration to use for this account.
|
||||
'';
|
||||
};
|
||||
|
||||
maildir = mkOption {
|
||||
type = types.nullOr maildirModule;
|
||||
defaultText = { path = "\${name}"; };
|
||||
description = ''
|
||||
Maildir configuration for this account.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
{
|
||||
name = name;
|
||||
maildir = mkOptionDefault { path = "${name}"; };
|
||||
}
|
||||
|
||||
(mkIf (config.flavor == "gmail.com") {
|
||||
userName = mkDefault config.address;
|
||||
|
||||
imap = {
|
||||
host = "imap.gmail.com";
|
||||
};
|
||||
|
||||
smtp = {
|
||||
host = "smtp.gmail.com";
|
||||
port = if config.smtp.tls.useStartTls then 587 else 465;
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf (config.flavor == "runbox.com") {
|
||||
imap = {
|
||||
host = "mail.runbox.com";
|
||||
};
|
||||
|
||||
smtp = {
|
||||
host = "mail.runbox.com";
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.accounts.email = {
|
||||
certificatesFile = mkOption {
|
||||
type = types.path;
|
||||
default = "/etc/ssl/certs/ca-certificates.crt";
|
||||
description = ''
|
||||
Path to default file containing certificate authorities that
|
||||
should be used to validate the connection authenticity. This
|
||||
path may be overridden on a per-account basis.
|
||||
'';
|
||||
};
|
||||
|
||||
maildirBasePath = mkOption {
|
||||
type = types.str;
|
||||
default = "${config.home.homeDirectory}/Maildir";
|
||||
defaultText = "$HOME/Maildir";
|
||||
apply = p:
|
||||
if hasPrefix "/" p
|
||||
then p
|
||||
else "${config.home.homeDirectory}/${p}";
|
||||
description = ''
|
||||
The base directory for account maildir directories. May be a
|
||||
relative path, in which case it is relative the home
|
||||
directory.
|
||||
'';
|
||||
};
|
||||
|
||||
accounts = mkOption {
|
||||
type = types.attrsOf (types.submodule [
|
||||
mailAccountOpts
|
||||
(import ../programs/alot-accounts.nix)
|
||||
(import ../programs/astroid-accounts.nix)
|
||||
(import ../programs/mbsync-accounts.nix)
|
||||
(import ../programs/msmtp-accounts.nix)
|
||||
(import ../programs/notmuch-accounts.nix)
|
||||
(import ../programs/offlineimap-accounts.nix)
|
||||
]);
|
||||
default = {};
|
||||
description = "List of email accounts.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.accounts != {}) {
|
||||
assertions = [
|
||||
(
|
||||
let
|
||||
primaries =
|
||||
catAttrs "name"
|
||||
(filter (a: a.primary)
|
||||
(attrValues cfg.accounts));
|
||||
in
|
||||
{
|
||||
assertion = length primaries == 1;
|
||||
message =
|
||||
"Must have exactly one primary mail account but found "
|
||||
+ toString (length primaries)
|
||||
+ optionalString (length primaries > 1)
|
||||
(", namely " + concatStringsSep ", " primaries);
|
||||
}
|
||||
)
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,46 +1,15 @@
|
||||
{ configuration
|
||||
, pkgs
|
||||
, lib ? pkgs.stdenv.lib
|
||||
|
||||
# Whether to check that each option has a matching declaration.
|
||||
, check ? true
|
||||
}:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
modules = [
|
||||
./home-environment.nix
|
||||
./manual.nix
|
||||
./misc/gtk.nix
|
||||
./misc/pam.nix
|
||||
./programs/bash.nix
|
||||
./programs/beets.nix
|
||||
./programs/eclipse.nix
|
||||
./programs/emacs.nix
|
||||
./programs/firefox.nix
|
||||
./programs/git.nix
|
||||
./programs/gnome-terminal.nix
|
||||
./programs/info.nix
|
||||
./programs/lesspipe.nix
|
||||
./programs/ssh.nix
|
||||
./programs/texlive.nix
|
||||
./services/dunst.nix
|
||||
./services/gnome-keyring.nix
|
||||
./services/gpg-agent.nix
|
||||
./services/keepassx.nix
|
||||
./services/network-manager-applet.nix
|
||||
./services/random-background.nix
|
||||
./services/redshift.nix
|
||||
./services/taffybar.nix
|
||||
./services/tahoe-lafs.nix
|
||||
./services/udiskie.nix
|
||||
./services/xscreensaver.nix
|
||||
./systemd.nix
|
||||
./xresources.nix
|
||||
./xsession.nix
|
||||
<nixpkgs/nixos/modules/misc/assertions.nix>
|
||||
<nixpkgs/nixos/modules/misc/meta.nix>
|
||||
];
|
||||
|
||||
collectFailed = cfg:
|
||||
map (x: x.message) (filter (x: !x.assertion) cfg.assertions);
|
||||
|
||||
@@ -50,23 +19,22 @@ let
|
||||
in
|
||||
fold f res res.config.warnings;
|
||||
|
||||
pkgsModule = {
|
||||
config._module.args.pkgs = lib.mkForce pkgs;
|
||||
config._module.args.baseModules = modules;
|
||||
rawModule = lib.evalModules {
|
||||
modules =
|
||||
[ configuration ]
|
||||
++ (import ./modules.nix { inherit check lib pkgs; });
|
||||
specialArgs = {
|
||||
modulesPath = builtins.toString ./.;
|
||||
};
|
||||
};
|
||||
|
||||
module = showWarnings (
|
||||
let
|
||||
mod = lib.evalModules {
|
||||
modules = [ configuration ] ++ modules ++ [ pkgsModule ];
|
||||
};
|
||||
|
||||
failed = collectFailed mod.config;
|
||||
|
||||
failed = collectFailed rawModule.config;
|
||||
failedStr = concatStringsSep "\n" (map (x: "- ${x}") failed);
|
||||
in
|
||||
if failed == []
|
||||
then mod
|
||||
then rawModule
|
||||
else throw "\nFailed assertions:\n${failedStr}"
|
||||
);
|
||||
|
||||
@@ -75,6 +43,14 @@ in
|
||||
{
|
||||
inherit (module) options config;
|
||||
|
||||
activationPackage = module.config.home.activationPackage;
|
||||
|
||||
# For backwards compatibility. Please use activationPackage instead.
|
||||
activation-script = module.config.home.activationPackage;
|
||||
home-path = module.config.home.path;
|
||||
|
||||
newsDisplay = rawModule.config.news.display;
|
||||
newsEntries =
|
||||
sort (a: b: a.time > b.time) (
|
||||
filter (a: a.condition) rawModule.config.news.entries
|
||||
);
|
||||
}
|
||||
|
||||
283
modules/files.nix
Normal file
283
modules/files.nix
Normal file
@@ -0,0 +1,283 @@
|
||||
{ pkgs, config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.home.file;
|
||||
|
||||
dag = config.lib.dag;
|
||||
|
||||
homeDirectory = config.home.homeDirectory;
|
||||
|
||||
fileType = (import lib/file-type.nix {
|
||||
inherit homeDirectory lib pkgs;
|
||||
}).fileType;
|
||||
|
||||
sourceStorePath = file:
|
||||
let
|
||||
sourcePath = toString file.source;
|
||||
sourceName = config.lib.strings.storeFileName (baseNameOf sourcePath);
|
||||
in
|
||||
if builtins.hasContext sourcePath
|
||||
then file.source
|
||||
else builtins.path { path = file.source; name = sourceName; };
|
||||
|
||||
# A symbolic link whose target path matches this pattern will be
|
||||
# considered part of a Home Manager generation.
|
||||
homeFilePattern = "${builtins.storeDir}/*-home-manager-files/*";
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
home.file = mkOption {
|
||||
description = "Attribute set of files to link into the user home.";
|
||||
default = {};
|
||||
type = fileType "<envar>HOME</envar>" homeDirectory;
|
||||
};
|
||||
|
||||
home-files = mkOption {
|
||||
type = types.package;
|
||||
internal = true;
|
||||
description = "Package to contain all home files";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
# This verifies that the links we are about to create will not
|
||||
# overwrite an existing file.
|
||||
home.activation.checkLinkTargets = dag.entryBefore ["writeBoundary"] (
|
||||
let
|
||||
check = pkgs.writeText "check" ''
|
||||
. ${./lib-bash/color-echo.sh}
|
||||
|
||||
newGenFiles="$1"
|
||||
shift
|
||||
for sourcePath in "$@" ; do
|
||||
relativePath="''${sourcePath#$newGenFiles/}"
|
||||
targetPath="$HOME/$relativePath"
|
||||
if [[ -e "$targetPath" \
|
||||
&& ! "$(readlink "$targetPath")" == ${homeFilePattern} ]] ; then
|
||||
errorEcho "Existing file '$targetPath' is in the way"
|
||||
collision=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -v collision ]] ; then
|
||||
errorEcho "Please move the above files and try again"
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
in
|
||||
''
|
||||
function checkNewGenCollision() {
|
||||
local newGenFiles
|
||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||
find "$newGenFiles" -type f -print0 -or -type l -print0 \
|
||||
| xargs -0 bash ${check} "$newGenFiles"
|
||||
}
|
||||
|
||||
checkNewGenCollision || exit 1
|
||||
''
|
||||
);
|
||||
|
||||
# This activation script will
|
||||
#
|
||||
# 1. Remove files from the old generation that are not in the new
|
||||
# generation.
|
||||
#
|
||||
# 2. Switch over the Home Manager gcroot and current profile
|
||||
# links.
|
||||
#
|
||||
# 3. Symlink files from the new generation into $HOME.
|
||||
#
|
||||
# This order is needed to ensure that we always know which links
|
||||
# belong to which generation. Specifically, if we're moving from
|
||||
# generation A to generation B having sets of home file links FA
|
||||
# and FB, respectively then cleaning before linking produces state
|
||||
# transitions similar to
|
||||
#
|
||||
# FA → FA ∩ FB → (FA ∩ FB) ∪ FB = FB
|
||||
#
|
||||
# and a failure during the intermediate state FA ∩ FB will not
|
||||
# result in lost links because this set of links are in both the
|
||||
# source and target generation.
|
||||
home.activation.linkGeneration = dag.entryAfter ["writeBoundary"] (
|
||||
let
|
||||
link = pkgs.writeText "link" ''
|
||||
newGenFiles="$1"
|
||||
shift
|
||||
for sourcePath in "$@" ; do
|
||||
relativePath="''${sourcePath#$newGenFiles/}"
|
||||
targetPath="$HOME/$relativePath"
|
||||
$DRY_RUN_CMD mkdir -p $VERBOSE_ARG "$(dirname "$targetPath")"
|
||||
$DRY_RUN_CMD ln -nsf $VERBOSE_ARG "$sourcePath" "$targetPath"
|
||||
done
|
||||
'';
|
||||
|
||||
cleanup = pkgs.writeText "cleanup" ''
|
||||
. ${./lib-bash/color-echo.sh}
|
||||
|
||||
newGenFiles="$1"
|
||||
shift 1
|
||||
for relativePath in "$@" ; do
|
||||
targetPath="$HOME/$relativePath"
|
||||
if [[ -e "$newGenFiles/$relativePath" ]] ; then
|
||||
$VERBOSE_ECHO "Checking $targetPath: exists"
|
||||
elif [[ ! "$(readlink "$targetPath")" == ${homeFilePattern} ]] ; then
|
||||
warnEcho "Path '$targetPath' not link into Home Manager generation. Skipping delete."
|
||||
else
|
||||
$VERBOSE_ECHO "Checking $targetPath: gone (deleting)"
|
||||
$DRY_RUN_CMD rm $VERBOSE_ARG "$targetPath"
|
||||
|
||||
# Recursively delete empty parent directories.
|
||||
targetDir="$(dirname "$relativePath")"
|
||||
if [[ "$targetDir" != "." ]] ; then
|
||||
pushd "$HOME" > /dev/null
|
||||
|
||||
# Call rmdir with a relative path excluding $HOME.
|
||||
# Otherwise, it might try to delete $HOME and exit
|
||||
# with a permission error.
|
||||
$DRY_RUN_CMD rmdir $VERBOSE_ARG \
|
||||
-p --ignore-fail-on-non-empty \
|
||||
"$targetDir"
|
||||
|
||||
popd > /dev/null
|
||||
fi
|
||||
fi
|
||||
done
|
||||
'';
|
||||
in
|
||||
''
|
||||
function linkNewGen() {
|
||||
echo "Creating home file links in $HOME"
|
||||
|
||||
local newGenFiles
|
||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||
find "$newGenFiles" -type f -print0 -or -type l -print0 \
|
||||
| xargs -0 bash ${link} "$newGenFiles"
|
||||
}
|
||||
|
||||
function cleanOldGen() {
|
||||
if [[ ! -v oldGenPath ]] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Cleaning up orphan links from $HOME"
|
||||
|
||||
local newGenFiles oldGenFiles
|
||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||
oldGenFiles="$(readlink -e "$oldGenPath/home-files")"
|
||||
|
||||
# Apply the cleanup script on each leaf in the old
|
||||
# generation. The find command below will print the
|
||||
# relative path of the entry.
|
||||
find "$oldGenFiles" '(' -type f -or -type l ')' -printf '%P\0' \
|
||||
| xargs -0 bash ${cleanup} "$newGenFiles"
|
||||
}
|
||||
|
||||
cleanOldGen
|
||||
|
||||
if [[ ! -v oldGenPath || "$oldGenPath" != "$newGenPath" ]] ; then
|
||||
echo "Creating profile generation $newGenNum"
|
||||
$DRY_RUN_CMD ln -Tsf $VERBOSE_ARG "$newGenPath" "$newGenProfilePath"
|
||||
$DRY_RUN_CMD ln -Tsf $VERBOSE_ARG $(basename "$newGenProfilePath") "$genProfilePath"
|
||||
$DRY_RUN_CMD ln -Tsf $VERBOSE_ARG "$newGenPath" "$newGenGcPath"
|
||||
else
|
||||
echo "No change so reusing latest profile generation $oldGenNum"
|
||||
fi
|
||||
|
||||
linkNewGen
|
||||
''
|
||||
);
|
||||
|
||||
home.activation.checkFilesChanged = dag.entryBefore ["linkGeneration"] (
|
||||
''
|
||||
declare -A changedFiles
|
||||
'' + concatMapStrings (v: ''
|
||||
cmp --quiet "${sourceStorePath v}" "${homeDirectory}/${v.target}" \
|
||||
&& changedFiles["${v.target}"]=0 \
|
||||
|| changedFiles["${v.target}"]=1
|
||||
'') (filter (v: v.onChange != "") (attrValues cfg))
|
||||
);
|
||||
|
||||
home.activation.onFilesChange = dag.entryAfter ["linkGeneration"] (
|
||||
concatMapStrings (v: ''
|
||||
if [[ ${"$\{changedFiles"}["${v.target}"]} -eq 1 ]]; then
|
||||
${v.onChange}
|
||||
fi
|
||||
'') (filter (v: v.onChange != "") (attrValues cfg))
|
||||
);
|
||||
|
||||
# Symlink directories and files that have the right execute bit.
|
||||
# Copy files that need their execute bit changed.
|
||||
home-files = pkgs.runCommand
|
||||
"home-manager-files"
|
||||
{
|
||||
nativeBuildInputs = [ pkgs.xlibs.lndir ];
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
}
|
||||
(''
|
||||
mkdir -p $out
|
||||
|
||||
function insertFile() {
|
||||
local source="$1"
|
||||
local relTarget="$2"
|
||||
local executable="$3"
|
||||
local recursive="$4"
|
||||
|
||||
# Figure out the real absolute path to the target.
|
||||
local target
|
||||
target="$(realpath -m "$out/$relTarget")"
|
||||
|
||||
# Target path must be within $HOME.
|
||||
if [[ ! $target == $out* ]] ; then
|
||||
echo "Error installing file '$relTarget' outside \$HOME" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "$target")"
|
||||
if [[ -d $source ]]; then
|
||||
if [[ $recursive ]]; then
|
||||
mkdir -p "$target"
|
||||
lndir -silent "$source" "$target"
|
||||
else
|
||||
ln -s "$source" "$target"
|
||||
fi
|
||||
else
|
||||
[[ -x $source ]] && isExecutable=1 || isExecutable=""
|
||||
|
||||
# Link the file into the home file directory if possible,
|
||||
# i.e., if the executable bit of the source is the same we
|
||||
# expect for the target. Otherwise, we copy the file and
|
||||
# set the executable bit to the expected value.
|
||||
if [[ $executable == inherit || $isExecutable == $executable ]]; then
|
||||
ln -s "$source" "$target"
|
||||
else
|
||||
cp "$source" "$target"
|
||||
|
||||
if [[ $executable == inherit ]]; then
|
||||
# Don't change file mode if it should match the source.
|
||||
:
|
||||
elif [[ $executable ]]; then
|
||||
chmod +x "$target"
|
||||
else
|
||||
chmod -x "$target"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
'' + concatStrings (
|
||||
mapAttrsToList (n: v: ''
|
||||
insertFile "${sourceStorePath v}" \
|
||||
"${v.target}" \
|
||||
"${if v.executable == null
|
||||
then "inherit"
|
||||
else builtins.toString v.executable}" \
|
||||
"${builtins.toString v.recursive}"
|
||||
'') cfg
|
||||
));
|
||||
};
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
with import ./lib/dag.nix;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.home;
|
||||
|
||||
dag = config.lib.dag;
|
||||
|
||||
languageSubModule = types.submodule {
|
||||
options = {
|
||||
base = mkOption {
|
||||
@@ -93,53 +94,42 @@ let
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
imports = [
|
||||
(mkRemovedOptionModule [ "home" "sessionVariableSetter" ] ''
|
||||
Session variables are now always set through the shell. This is
|
||||
done automatically if the shell configuration is managed by Home
|
||||
Manager. If not, then you must source the
|
||||
|
||||
~/.nix-profile/etc/profile.d/hm-session-vars.sh
|
||||
|
||||
file yourself.
|
||||
'')
|
||||
];
|
||||
|
||||
options = {
|
||||
home.file = mkOption {
|
||||
description = "Attribute set of files to link into the user home.";
|
||||
default = {};
|
||||
type = types.loaOf (types.submodule (
|
||||
{ name, config, ... }: {
|
||||
options = {
|
||||
target = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Path to target file relative to <envar>HOME</envar>.
|
||||
'';
|
||||
};
|
||||
home.username = mkOption {
|
||||
type = types.str;
|
||||
defaultText = "$USER";
|
||||
description = "The user's username.";
|
||||
};
|
||||
|
||||
text = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.lines;
|
||||
description = "Text of the file.";
|
||||
};
|
||||
home.homeDirectory = mkOption {
|
||||
type = types.path;
|
||||
defaultText = "$HOME";
|
||||
description = "The user's home directory.";
|
||||
};
|
||||
|
||||
source = mkOption {
|
||||
type = types.path;
|
||||
description = ''
|
||||
Path of the source file. The file name must not start
|
||||
with a period since Nix will not allow such names in
|
||||
the Nix store.
|
||||
</para><para>
|
||||
This may refer to a directory.
|
||||
'';
|
||||
};
|
||||
|
||||
mode = mkOption {
|
||||
type = types.str;
|
||||
default = "444";
|
||||
description = "The permissions to apply to the file.";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
target = mkDefault name;
|
||||
source = mkIf (config.text != null) (
|
||||
let name' = "user-etc-" + baseNameOf name;
|
||||
in mkDefault (pkgs.writeText name' config.text)
|
||||
);
|
||||
};
|
||||
})
|
||||
);
|
||||
home.profileDirectory = mkOption {
|
||||
type = types.path;
|
||||
defaultText = "~/.nix-profile";
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
The profile directory where Home Manager generations are
|
||||
installed.
|
||||
'';
|
||||
};
|
||||
|
||||
home.language = mkOption {
|
||||
@@ -149,9 +139,12 @@ in
|
||||
};
|
||||
|
||||
home.keyboard = mkOption {
|
||||
type = keyboardSubModule;
|
||||
type = types.nullOr keyboardSubModule;
|
||||
default = {};
|
||||
description = "Keyboard configuration.";
|
||||
description = ''
|
||||
Keyboard configuration. Set to <literal>null</literal> to
|
||||
disable Home Manager keyboard management.
|
||||
'';
|
||||
};
|
||||
|
||||
home.sessionVariables = mkOption {
|
||||
@@ -160,22 +153,34 @@ in
|
||||
example = { EDITOR = "emacs"; GS_OPTIONS = "-sPAPERSIZE=a4"; };
|
||||
description = ''
|
||||
Environment variables to always set at login.
|
||||
'';
|
||||
};
|
||||
|
||||
home.sessionVariableSetter = mkOption {
|
||||
default = "bash";
|
||||
type = types.enum [ "pam" "bash" ];
|
||||
example = "pam";
|
||||
description = ''
|
||||
Identifies the module that should set the session variables.
|
||||
</para><para>
|
||||
If "bash" is set then <varname>config.bash.enable</varname>
|
||||
must also be enabled.
|
||||
The values may refer to other environment variables using
|
||||
POSIX.2 style variable references. For example, a variable
|
||||
<varname>parameter</varname> may be referenced as
|
||||
<code>$parameter</code> or <code>''${parameter}</code>. A
|
||||
default value <literal>foo</literal> may be given as per
|
||||
<code>''${parameter:-foo}</code> and, similarly, an alternate
|
||||
value <literal>bar</literal> can be given as per
|
||||
<code>''${parameter:+bar}</code>.
|
||||
</para><para>
|
||||
If "pam" is set then PAM must be used to set the system
|
||||
environment. Also mind that typical environment variables
|
||||
might not be set by the time PAM starts up.
|
||||
Note, these variables may be set in any order so no session
|
||||
variable may have a runtime dependency on another session
|
||||
variable. In particular code like
|
||||
<programlisting language="nix">
|
||||
home.sessionVariables = {
|
||||
FOO = "Hello";
|
||||
BAR = "$FOO World!";
|
||||
};
|
||||
</programlisting>
|
||||
may not work as expected. If you need to reference another
|
||||
session variable, then do so inside Nix instead. The above
|
||||
example then becomes
|
||||
<programlisting language="nix">
|
||||
home.sessionVariables = {
|
||||
FOO = "Hello";
|
||||
BAR = "''${config.home.sessionVariables.FOO} World!";
|
||||
};
|
||||
</programlisting>
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -185,11 +190,33 @@ in
|
||||
description = "The set of packages to appear in the user environment.";
|
||||
};
|
||||
|
||||
home.extraOutputsToInstall = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "doc" "info" "devdoc" ];
|
||||
description = ''
|
||||
List of additional package outputs of the packages
|
||||
<varname>home.packages</varname> that should be installed into
|
||||
the user environment.
|
||||
'';
|
||||
};
|
||||
|
||||
home.path = mkOption {
|
||||
internal = true;
|
||||
description = "The derivation installing the user packages.";
|
||||
};
|
||||
|
||||
home.emptyActivationPath = mkOption {
|
||||
internal = true;
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether the activation script should start with an empty
|
||||
<envvar>PATH</envvar> variable. When <literal>false</literal>
|
||||
then the user's <envvar>PATH</envvar> will be used.
|
||||
'';
|
||||
};
|
||||
|
||||
home.activation = mkOption {
|
||||
internal = true;
|
||||
default = {};
|
||||
@@ -210,27 +237,50 @@ in
|
||||
type = types.package;
|
||||
description = "The package containing the complete activation script.";
|
||||
};
|
||||
|
||||
home.extraBuilderCommands = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
internal = true;
|
||||
description = ''
|
||||
Extra commands to run in the Home Manager generation builder.
|
||||
'';
|
||||
};
|
||||
|
||||
home.extraProfileCommands = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
internal = true;
|
||||
description = ''
|
||||
Extra commands to run in the Home Manager profile builder.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
assertions = [
|
||||
(let
|
||||
badFiles =
|
||||
filter (f: hasPrefix "." (baseNameOf f))
|
||||
(map (v: toString v.source)
|
||||
(attrValues cfg.file));
|
||||
badFilesStr = toString badFiles;
|
||||
in
|
||||
{
|
||||
assertion = badFiles == [];
|
||||
message = "Source file names must not start with '.': ${badFilesStr}";
|
||||
})
|
||||
{
|
||||
assertion = config.home.username != "";
|
||||
message = "Username could not be determined";
|
||||
}
|
||||
{
|
||||
assertion = config.home.homeDirectory != "";
|
||||
message = "Home directory could not be determined";
|
||||
}
|
||||
];
|
||||
|
||||
home.username = mkDefault (builtins.getEnv "USER");
|
||||
home.homeDirectory = mkDefault (builtins.getEnv "HOME");
|
||||
|
||||
home.profileDirectory =
|
||||
if config.submoduleSupport.enable
|
||||
&& config.submoduleSupport.externalPackageInstall
|
||||
then config.home.path
|
||||
else cfg.homeDirectory + "/.nix-profile";
|
||||
|
||||
home.sessionVariables =
|
||||
let
|
||||
maybeSet = name: value:
|
||||
listToAttrs (optional (value != null) { inherit name value; });
|
||||
maybeSet = n: v: optionalAttrs (v != null) { ${n} = v; };
|
||||
in
|
||||
(maybeSet "LANG" cfg.language.base)
|
||||
//
|
||||
@@ -242,132 +292,63 @@ in
|
||||
//
|
||||
(maybeSet "LC_TIME" cfg.language.time);
|
||||
|
||||
home.packages = [
|
||||
# Provide a file holding all session variables.
|
||||
(
|
||||
pkgs.writeTextFile {
|
||||
name = "hm-session-vars.sh";
|
||||
destination = "/etc/profile.d/hm-session-vars.sh";
|
||||
text = ''
|
||||
# Only source this once.
|
||||
if [ -n "$__HM_SESS_VARS_SOURCED" ]; then return; fi
|
||||
export __HM_SESS_VARS_SOURCED=1
|
||||
|
||||
${config.lib.shell.exportAll cfg.sessionVariables}
|
||||
'';
|
||||
}
|
||||
)
|
||||
];
|
||||
|
||||
# A dummy entry acting as a boundary between the activation
|
||||
# script's "check" and the "write" phases.
|
||||
home.activation.writeBoundary = dagEntryAnywhere "";
|
||||
home.activation.writeBoundary = dag.entryAnywhere "";
|
||||
|
||||
# This verifies that the links we are about to create will not
|
||||
# overwrite an existing file.
|
||||
home.activation.checkLinkTargets = dagEntryBefore ["writeBoundary"] (
|
||||
let
|
||||
pattern = "-home-manager-files/";
|
||||
check = pkgs.writeText "check" ''
|
||||
. ${./lib-bash/color-echo.sh}
|
||||
|
||||
newGenFiles="$1"
|
||||
shift
|
||||
for sourcePath in "$@" ; do
|
||||
relativePath="''${sourcePath#$newGenFiles/}"
|
||||
targetPath="$HOME/$relativePath"
|
||||
if [[ -e "$targetPath" \
|
||||
&& ! "$(readlink -e "$targetPath")" =~ "${pattern}" ]] ; then
|
||||
errorEcho "Existing file '$targetPath' is in the way"
|
||||
collision=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -v collision ]] ; then
|
||||
errorEcho "Please move the above files and try again"
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
in
|
||||
''
|
||||
function checkNewGenCollision() {
|
||||
local newGenFiles
|
||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||
find "$newGenFiles" -type f -print0 -or -type l -print0 \
|
||||
| xargs -0 bash ${check} "$newGenFiles"
|
||||
}
|
||||
|
||||
checkNewGenCollision || exit 1
|
||||
''
|
||||
);
|
||||
|
||||
home.activation.linkGeneration = dagEntryAfter ["writeBoundary"] (
|
||||
let
|
||||
pattern = "-home-manager-files/";
|
||||
|
||||
link = pkgs.writeText "link" ''
|
||||
newGenFiles="$1"
|
||||
shift
|
||||
for sourcePath in "$@" ; do
|
||||
relativePath="''${sourcePath#$newGenFiles/}"
|
||||
targetPath="$HOME/$relativePath"
|
||||
$DRY_RUN_CMD mkdir -p $VERBOSE_ARG "$(dirname "$targetPath")"
|
||||
$DRY_RUN_CMD ln -nsf $VERBOSE_ARG "$sourcePath" "$targetPath"
|
||||
done
|
||||
'';
|
||||
|
||||
cleanup = pkgs.writeText "cleanup" ''
|
||||
. ${./lib-bash/color-echo.sh}
|
||||
|
||||
newGenFiles="$1"
|
||||
oldGenFiles="$2"
|
||||
shift 2
|
||||
for sourcePath in "$@" ; do
|
||||
relativePath="''${sourcePath#$oldGenFiles/}"
|
||||
targetPath="$HOME/$relativePath"
|
||||
if [[ -e "$newGenFiles/$relativePath" ]] ; then
|
||||
$VERBOSE_ECHO "Checking $targetPath exists"
|
||||
elif [[ ! "$(readlink -e "$targetPath")" =~ "${pattern}" ]] ; then
|
||||
warnEcho "Path '$targetPath' not link into Home Manager generation. Skipping delete."
|
||||
else
|
||||
echo "Checking $targetPath gone (deleting)"
|
||||
$DRY_RUN_CMD rm $VERBOSE_ARG "$targetPath"
|
||||
$DRY_RUN_CMD rmdir --ignore-fail-on-non-empty \
|
||||
$VERBOSE_ARG -p "$(dirname "$targetPath")"
|
||||
fi
|
||||
done
|
||||
'';
|
||||
in
|
||||
# Install packages to the user environment.
|
||||
#
|
||||
# Note, sometimes our target may not allow modification of the Nix
|
||||
# store and then we cannot rely on `nix-env -i`. This is the case,
|
||||
# for example, if we are running as a NixOS module and building a
|
||||
# virtual machine. Then we must instead rely on an external
|
||||
# mechanism for installing packages, which in NixOS is provided by
|
||||
# the `users.users.<name?>.packages` option. The activation
|
||||
# command is still needed since some modules need to run their
|
||||
# activation commands after the packages are guaranteed to be
|
||||
# installed.
|
||||
#
|
||||
# In case the user has moved from a user-install of Home Manager
|
||||
# to a submodule managed one we attempt to uninstall the
|
||||
# `home-manager-path` package if it is installed.
|
||||
home.activation.installPackages = dag.entryAfter ["writeBoundary"] (
|
||||
if config.submoduleSupport.externalPackageInstall
|
||||
then
|
||||
''
|
||||
function linkNewGen() {
|
||||
local newGenFiles
|
||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||
find "$newGenFiles" -type f -print0 -or -type l -print0 \
|
||||
| xargs -0 bash ${link} "$newGenFiles"
|
||||
}
|
||||
|
||||
function cleanOldGen() {
|
||||
if [[ ! -v oldGenPath ]] ; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Cleaning up orphan links from $HOME"
|
||||
|
||||
local newGenFiles oldGenFiles
|
||||
newGenFiles="$(readlink -e "$newGenPath/home-files")"
|
||||
oldGenFiles="$(readlink -e "$oldGenPath/home-files")"
|
||||
find "$oldGenFiles" -type f -print0 -or -type l -print0 \
|
||||
| xargs -0 bash ${cleanup} "$newGenFiles" "$oldGenFiles"
|
||||
}
|
||||
|
||||
if [[ ! -v oldGenPath || "$oldGenPath" != "$newGenPath" ]] ; then
|
||||
echo "Creating profile generation $newGenNum"
|
||||
$DRY_RUN_CMD ln -Tsf $VERBOSE_ARG "$newGenPath" "$newGenProfilePath"
|
||||
$DRY_RUN_CMD ln -Tsf $VERBOSE_ARG "$newGenProfilePath" "$genProfilePath"
|
||||
$DRY_RUN_CMD ln -Tsf $VERBOSE_ARG "$newGenPath" "$newGenGcPath"
|
||||
else
|
||||
echo "No change so reusing latest profile generation $oldGenNum"
|
||||
if nix-env -q | grep '^home-manager-path$'; then
|
||||
$DRY_RUN_CMD nix-env -e home-manager-path
|
||||
fi
|
||||
|
||||
linkNewGen
|
||||
cleanOldGen
|
||||
''
|
||||
else
|
||||
''
|
||||
$DRY_RUN_CMD nix-env -i ${cfg.path}
|
||||
''
|
||||
);
|
||||
|
||||
home.activation.installPackages = dagEntryAfter ["writeBoundary"] ''
|
||||
$DRY_RUN_CMD nix-env -i ${cfg.path}
|
||||
'';
|
||||
|
||||
home.activationPackage =
|
||||
let
|
||||
mkCmd = res: ''
|
||||
noteEcho Activating ${res.name}
|
||||
${res.data}
|
||||
'';
|
||||
sortedCommands = dagTopoSort cfg.activation;
|
||||
sortedCommands = dag.topoSort cfg.activation;
|
||||
activationCmds =
|
||||
if sortedCommands ? result then
|
||||
concatStringsSep "\n" (map mkCmd sortedCommands.result)
|
||||
@@ -375,16 +356,28 @@ in
|
||||
abort ("Dependency cycle in activation script: "
|
||||
+ builtins.toJSON sortedCommands);
|
||||
|
||||
sf = pkgs.writeText "activation-script" ''
|
||||
# Programs that always should be available on the activation
|
||||
# script's PATH.
|
||||
activationBinPaths = lib.makeBinPath [
|
||||
pkgs.bash
|
||||
pkgs.coreutils
|
||||
pkgs.diffutils # For `cmp` and `diff`.
|
||||
pkgs.findutils
|
||||
pkgs.gnugrep
|
||||
pkgs.gnused
|
||||
pkgs.ncurses # For `tput`.
|
||||
]
|
||||
+ optionalString (!cfg.emptyActivationPath) "\${PATH:+:}$PATH";
|
||||
|
||||
activationScript = pkgs.writeScript "activation-script" ''
|
||||
#!${pkgs.stdenv.shell}
|
||||
|
||||
set -eu
|
||||
set -o pipefail
|
||||
|
||||
# This code explicitly requires GNU Core Utilities and Bash.
|
||||
# We therefore need to ensure they are prioritized over any
|
||||
# other similarly named tools on the system.
|
||||
export PATH="${pkgs.coreutils}/bin:${pkgs.bash}/bin:$PATH"
|
||||
cd $HOME
|
||||
|
||||
export PATH="${activationBinPaths}"
|
||||
|
||||
. ${./lib-bash/color-echo.sh}
|
||||
|
||||
@@ -392,47 +385,34 @@ in
|
||||
|
||||
${activationCmds}
|
||||
'';
|
||||
|
||||
home-files = pkgs.stdenv.mkDerivation {
|
||||
name = "home-manager-files";
|
||||
|
||||
phases = [ "installPhase" ];
|
||||
|
||||
installPhase =
|
||||
"mkdir -p $out\n" +
|
||||
concatStringsSep "\n" (
|
||||
mapAttrsToList (n: v:
|
||||
''
|
||||
if [ -d "${v.source}" ]; then
|
||||
mkdir -pv "$(dirname "$out/${v.target}")"
|
||||
ln -sv "${v.source}" "$out/${v.target}"
|
||||
else
|
||||
install -D -m${v.mode} "${v.source}" "$out/${v.target}"
|
||||
fi
|
||||
''
|
||||
) cfg.file
|
||||
);
|
||||
};
|
||||
in
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "home-manager-generation";
|
||||
pkgs.runCommand
|
||||
"home-manager-generation"
|
||||
{
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
}
|
||||
''
|
||||
mkdir -p $out
|
||||
|
||||
phases = [ "installPhase" ];
|
||||
|
||||
installPhase = ''
|
||||
install -D -m755 ${sf} $out/activate
|
||||
cp ${activationScript} $out/activate
|
||||
|
||||
substituteInPlace $out/activate \
|
||||
--subst-var-by GENERATION_DIR $out
|
||||
|
||||
ln -s ${home-files} $out/home-files
|
||||
ln -s ${config.home-files} $out/home-files
|
||||
ln -s ${cfg.path} $out/home-path
|
||||
|
||||
${cfg.extraBuilderCommands}
|
||||
'';
|
||||
};
|
||||
|
||||
home.path = pkgs.buildEnv {
|
||||
name = "home-manager-path";
|
||||
|
||||
paths = cfg.packages;
|
||||
inherit (cfg) extraOutputsToInstall;
|
||||
|
||||
postBuild = cfg.extraProfileCommands;
|
||||
|
||||
meta = {
|
||||
description = "Environment of packages installed through home-manager";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
function setupVars() {
|
||||
local profilesPath="/nix/var/nix/profiles/per-user/$USER"
|
||||
local gcPath="/nix/var/nix/gcroots/per-user/$USER"
|
||||
@@ -9,27 +11,38 @@ function setupVars() {
|
||||
| sort -rn \
|
||||
| head -1)
|
||||
|
||||
if [[ -n "$greatestGenNum" ]] ; then
|
||||
if [[ -n $greatestGenNum ]] ; then
|
||||
oldGenNum=$greatestGenNum
|
||||
newGenNum=$((oldGenNum + 1))
|
||||
else
|
||||
newGenNum=1
|
||||
fi
|
||||
|
||||
if [[ -e "$gcPath/current-home" ]] ; then
|
||||
if [[ -e $gcPath/current-home ]] ; then
|
||||
oldGenPath="$(readlink -e "$gcPath/current-home")"
|
||||
fi
|
||||
|
||||
$VERBOSE_ECHO "Sanity checking oldGenNum and oldGenPath"
|
||||
if [[ -v oldGenNum && ! -v oldGenPath
|
||||
|| ! -v oldGenNum && -v oldGenPath ]]; then
|
||||
errorEcho "Invalid profile number and GC root values! These must be"
|
||||
errorEcho "either both empty or both set but are now set to"
|
||||
errorEcho " '${oldGenNum:-}' and '${oldGenPath:-}'"
|
||||
errorEcho "If you don't mind losing previous profile generations then"
|
||||
errorEcho "the easiest solution is probably to run"
|
||||
errorEcho " rm $profilesPath/home-manager*"
|
||||
errorEcho " rm $gcPath/current-home"
|
||||
errorEcho "and trying home-manager switch again. Good luck!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
genProfilePath="$profilesPath/home-manager"
|
||||
newGenPath="@GENERATION_DIR@";
|
||||
newGenProfilePath="$profilesPath/home-manager-$newGenNum-link"
|
||||
newGenGcPath="$gcPath/current-home"
|
||||
}
|
||||
|
||||
setupVars
|
||||
|
||||
echo "Starting home manager activation"
|
||||
|
||||
if [[ -v VERBOSE ]]; then
|
||||
export VERBOSE_ECHO=echo
|
||||
export VERBOSE_ARG="--verbose"
|
||||
@@ -38,14 +51,23 @@ else
|
||||
export VERBOSE_ARG=""
|
||||
fi
|
||||
|
||||
echo "Starting home manager activation"
|
||||
|
||||
setupVars
|
||||
|
||||
if [[ -v DRY_RUN ]] ; then
|
||||
$VERBOSE_ECHO "This is a dry run"
|
||||
echo "This is a dry run"
|
||||
export DRY_RUN_CMD=echo
|
||||
else
|
||||
$VERBOSE_ECHO "This is a live run"
|
||||
export DRY_RUN_CMD=""
|
||||
fi
|
||||
|
||||
if [[ -v VERBOSE ]]; then
|
||||
echo -n "Using Nix version: "
|
||||
nix-env --version
|
||||
fi
|
||||
|
||||
$VERBOSE_ECHO "Activation variables:"
|
||||
if [[ -v oldGenNum ]] ; then
|
||||
$VERBOSE_ECHO " oldGenNum=$oldGenNum"
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
# - the addition of the function `dagEntryBefore` indicating a
|
||||
# "wanted by" relationship.
|
||||
|
||||
with import <nixpkgs/lib/strings.nix>;
|
||||
with import <nixpkgs/lib/attrsets.nix>;
|
||||
with import <nixpkgs/lib/lists.nix>;
|
||||
{ lib }:
|
||||
|
||||
with lib;
|
||||
|
||||
rec {
|
||||
|
||||
|
||||
23
modules/lib/default.nix
Normal file
23
modules/lib/default.nix
Normal file
@@ -0,0 +1,23 @@
|
||||
{ lib }:
|
||||
|
||||
{
|
||||
dag =
|
||||
let
|
||||
d = import ./dag.nix { inherit lib; };
|
||||
in
|
||||
{
|
||||
empty = d.emptyDag;
|
||||
isDag = d.isDag;
|
||||
topoSort = d.dagTopoSort;
|
||||
map = d.dagMap;
|
||||
entryAnywhere = d.dagEntryAnywhere;
|
||||
entryBetween = d.dagEntryBetween;
|
||||
entryAfter = d.dagEntryAfter;
|
||||
entryBefore = d.dagEntryBefore;
|
||||
};
|
||||
|
||||
strings = import ./strings.nix { inherit lib; };
|
||||
|
||||
shell = import ./shell.nix { inherit lib; };
|
||||
zsh = import ./zsh.nix { inherit lib; };
|
||||
}
|
||||
102
modules/lib/file-type.nix
Normal file
102
modules/lib/file-type.nix
Normal file
@@ -0,0 +1,102 @@
|
||||
{ homeDirectory, lib, pkgs }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
stringsExtra = import ./strings.nix { inherit lib; };
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
# Constructs a type suitable for a `home.file` like option. The
|
||||
# target path may be either absolute or relative, in which case it
|
||||
# is relative the `basePath` argument (which itself must be an
|
||||
# absolute path).
|
||||
#
|
||||
# Arguments:
|
||||
# - basePathDesc docbook compatible description of the base path
|
||||
# - basePath the file base path
|
||||
fileType = basePathDesc: basePath: types.loaOf (types.submodule (
|
||||
{ name, config, ... }: {
|
||||
options = {
|
||||
target = mkOption {
|
||||
type = types.str;
|
||||
apply = p:
|
||||
let
|
||||
absPath = if hasPrefix "/" p then p else "${basePath}/${p}";
|
||||
in
|
||||
removePrefix (homeDirectory + "/") absPath;
|
||||
description = ''
|
||||
Path to target file relative to ${basePathDesc}.
|
||||
'';
|
||||
};
|
||||
|
||||
text = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.lines;
|
||||
description = "Text of the file.";
|
||||
};
|
||||
|
||||
source = mkOption {
|
||||
type = types.path;
|
||||
description = ''
|
||||
Path of the source file. The file name must not start
|
||||
with a period since Nix will not allow such names in
|
||||
the Nix store.
|
||||
</para><para>
|
||||
This may refer to a directory.
|
||||
'';
|
||||
};
|
||||
|
||||
executable = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
Set the execute bit. If <literal>null</literal>, defaults to the mode
|
||||
of the <varname>source</varname> file or to <literal>false</literal>
|
||||
for files created through the <varname>text</varname> option.
|
||||
'';
|
||||
};
|
||||
|
||||
recursive = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
If the file source is a directory, then this option
|
||||
determines whether the directory should be recursively
|
||||
linked to the target location. This option has no effect
|
||||
if the source is a file.
|
||||
</para><para>
|
||||
If <literal>false</literal> (the default) then the target
|
||||
will be a symbolic link to the source directory. If
|
||||
<literal>true</literal> then the target will be a
|
||||
directory structure matching the source's but whose leafs
|
||||
are symbolic links to the files of the source directory.
|
||||
'';
|
||||
};
|
||||
|
||||
onChange = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Shell commands to run when file has changed between
|
||||
generations. The script will be run
|
||||
<emphasis>after</emphasis> the new files have been linked
|
||||
into place.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
target = mkDefault name;
|
||||
source = mkIf (config.text != null) (
|
||||
mkDefault (pkgs.writeTextFile {
|
||||
inherit (config) executable text;
|
||||
name = stringsExtra.storeFileName name;
|
||||
})
|
||||
);
|
||||
};
|
||||
}
|
||||
));
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/* Functions that generate widespread file
|
||||
* formats from nix data structures.
|
||||
*
|
||||
* They all follow a similar interface:
|
||||
* generator { config-attrs } data
|
||||
*
|
||||
* Tests can be found in ./tests.nix
|
||||
* Documentation in the manual, #sec-generators
|
||||
*/
|
||||
with import <nixpkgs/lib/trivial.nix>;
|
||||
let
|
||||
libStr = import <nixpkgs/lib/strings.nix>;
|
||||
libAttr = import <nixpkgs/lib/attrsets.nix>;
|
||||
|
||||
flipMapAttrs = flip libAttr.mapAttrs;
|
||||
in
|
||||
|
||||
rec {
|
||||
|
||||
/* Generate a line of key k and value v, separated by
|
||||
* character sep. If sep appears in k, it is escaped.
|
||||
* Helper for synaxes with different separators.
|
||||
*
|
||||
* mkKeyValueDefault ":" "f:oo" "bar"
|
||||
* > "f\:oo:bar"
|
||||
*/
|
||||
mkKeyValueDefault = sep: k: v:
|
||||
"${libStr.escape [sep] k}${sep}${toString v}";
|
||||
|
||||
|
||||
/* Generate a key-value-style config file from an attrset.
|
||||
*
|
||||
* mkKeyValue is the same as in toINI.
|
||||
*/
|
||||
toKeyValue = {
|
||||
mkKeyValue ? mkKeyValueDefault "="
|
||||
}: attrs:
|
||||
let mkLine = k: v: mkKeyValue k v + "\n";
|
||||
in libStr.concatStrings (libAttr.mapAttrsToList mkLine attrs);
|
||||
|
||||
|
||||
/* Generate an INI-style config file from an
|
||||
* attrset of sections to an attrset of key-value pairs.
|
||||
*
|
||||
* generators.toINI {} {
|
||||
* foo = { hi = "${pkgs.hello}"; ciao = "bar"; };
|
||||
* baz = { "also, integers" = 42; };
|
||||
* }
|
||||
*
|
||||
*> [baz]
|
||||
*> also, integers=42
|
||||
*>
|
||||
*> [foo]
|
||||
*> ciao=bar
|
||||
*> hi=/nix/store/y93qql1p5ggfnaqjjqhxcw0vqw95rlz0-hello-2.10
|
||||
*
|
||||
* The mk* configuration attributes can generically change
|
||||
* the way sections and key-value strings are generated.
|
||||
*
|
||||
* For more examples see the test cases in ./tests.nix.
|
||||
*/
|
||||
toINI = {
|
||||
# apply transformations (e.g. escapes) to section names
|
||||
mkSectionName ? (name: libStr.escape [ "[" "]" ] name),
|
||||
# format a setting line from key and value
|
||||
mkKeyValue ? mkKeyValueDefault "="
|
||||
}: attrsOfAttrs:
|
||||
let
|
||||
# map function to string for each key val
|
||||
mapAttrsToStringsSep = sep: mapFn: attrs:
|
||||
libStr.concatStringsSep sep
|
||||
(libAttr.mapAttrsToList mapFn attrs);
|
||||
mkSection = sectName: sectValues: ''
|
||||
[${mkSectionName sectName}]
|
||||
'' + toKeyValue { inherit mkKeyValue; } sectValues;
|
||||
in
|
||||
# map input to ini sections
|
||||
mapAttrsToStringsSep "\n" mkSection attrsOfAttrs;
|
||||
|
||||
|
||||
/* Generates JSON from an arbitrary (non-function) value.
|
||||
* For more information see the documentation of the builtin.
|
||||
*/
|
||||
toJSON = {}: builtins.toJSON;
|
||||
|
||||
|
||||
/* YAML has been a strict superset of JSON since 1.2, so we
|
||||
* use toJSON. Before it only had a few differences referring
|
||||
* to implicit typing rules, so it should work with older
|
||||
* parsers as well.
|
||||
*/
|
||||
toYAML = {}@args: toJSON args;
|
||||
}
|
||||
11
modules/lib/shell.nix
Normal file
11
modules/lib/shell.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{ lib }:
|
||||
|
||||
rec {
|
||||
# Produces a Bourne shell like variable export statement.
|
||||
export = n: v: "export ${n}=\"${toString v}\"";
|
||||
|
||||
# Given an attribute set containing shell variable names and their
|
||||
# assignment, this function produces a string containing an export
|
||||
# statement for each set entry.
|
||||
exportAll = vars: lib.concatStringsSep "\n" (lib.mapAttrsToList export vars);
|
||||
}
|
||||
27
modules/lib/strings.nix
Normal file
27
modules/lib/strings.nix
Normal file
@@ -0,0 +1,27 @@
|
||||
{ lib }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
# Figures out a valid Nix store name for the given path.
|
||||
storeFileName = path:
|
||||
let
|
||||
# All characters that are considered safe. Note "-" is not
|
||||
# included to avoid "-" followed by digit being interpreted as a
|
||||
# version.
|
||||
safeChars =
|
||||
[ "+" "." "_" "?" "=" ]
|
||||
++ lowerChars
|
||||
++ upperChars
|
||||
++ stringToCharacters "0123456789";
|
||||
|
||||
empties = l: genList (x: "") (length l);
|
||||
|
||||
unsafeInName = stringToCharacters (
|
||||
replaceStrings safeChars (empties safeChars) path
|
||||
);
|
||||
|
||||
safeName = replaceStrings unsafeInName (empties unsafeInName) path;
|
||||
in
|
||||
"hm_" + safeName;
|
||||
}
|
||||
28
modules/lib/zsh.nix
Normal file
28
modules/lib/zsh.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{ lib }:
|
||||
|
||||
rec {
|
||||
# Produces a Zsh shell like value
|
||||
toZshValue = v: if builtins.isBool v then
|
||||
if v then "true" else "false"
|
||||
else if builtins.isString v then
|
||||
"\"${v}\""
|
||||
else if builtins.isList v then
|
||||
"(${lib.concatStringsSep " " (map toZshValue v)})"
|
||||
else "\"${toString v}\"";
|
||||
|
||||
# Produces a Zsh shell like definition statement
|
||||
define = n: v: "${n}=${toZshValue v}";
|
||||
|
||||
# Given an attribute set containing shell variable names and their
|
||||
# assignments, this function produces a string containing a definition
|
||||
# statement for each set entry.
|
||||
defineAll = vars: lib.concatStringsSep "\n" (lib.mapAttrsToList define vars);
|
||||
|
||||
# Produces a Zsh shell like export statement
|
||||
export = n: v: "export ${define n v}";
|
||||
|
||||
# Given an attribute set containing shell variable names and their
|
||||
# assignments, this function produces a string containing an export
|
||||
# statement for each set entry.
|
||||
exportAll = vars: lib.concatStringsSep "\n" (lib.mapAttrsToList export vars);
|
||||
}
|
||||
@@ -4,19 +4,21 @@ with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.manual;
|
||||
|
||||
/* For the purpose of generating docs, evaluate options with each derivation
|
||||
in `pkgs` (recursively) replaced by a fake with path "\${pkgs.attribute.path}".
|
||||
It isn't perfect, but it seems to cover a vast majority of use cases.
|
||||
Caveat: even if the package is reached by a different means,
|
||||
the path above will be shown and not e.g. `${config.services.foo.package}`. */
|
||||
nixosManual = import <nixpkgs/nixos/doc/manual> {
|
||||
homeManagerManual = import ../doc {
|
||||
inherit pkgs config;
|
||||
version = "0.1";
|
||||
revision = "release-0.1";
|
||||
revision = "master";
|
||||
options =
|
||||
let
|
||||
scrubbedEval = evalModules {
|
||||
modules = [ { nixpkgs.system = pkgs.stdenv.system; } ] ++ baseModules;
|
||||
modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ baseModules;
|
||||
args = (config._module.args) // { modules = [ ]; };
|
||||
specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; };
|
||||
};
|
||||
@@ -32,18 +34,42 @@ let
|
||||
in scrubbedEval.options;
|
||||
};
|
||||
|
||||
homeEnvironmentManPages = pkgs.runCommand "home-environment-manpages" {
|
||||
allowedReferences = [ "out" ];
|
||||
} ''
|
||||
install -v -D -m444 \
|
||||
${nixosManual.manpages}/share/man/man5/configuration.nix.5 \
|
||||
$out/share/man/man5/home-configuration.nix.5
|
||||
'';
|
||||
manualHtmlRoot = "${homeManagerManual.manual}/share/doc/home-manager/index.html";
|
||||
|
||||
helpScript = pkgs.writeShellScriptBin "home-manager-help" ''
|
||||
#!${pkgs.bash}/bin/bash -e
|
||||
|
||||
if [ -z "$BROWSER" ]; then
|
||||
for candidate in xdg-open open w3m; do
|
||||
BROWSER="$(type -P $candidate || true)"
|
||||
if [ -x "$BROWSER" ]; then
|
||||
break;
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$BROWSER" ]; then
|
||||
echo "$0: unable to start a web browser; please set \$BROWSER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$BROWSER" ${manualHtmlRoot}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
manual.html.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to install the HTML manual. This also installs the
|
||||
<command>home-manager-help</command> tool, which opens a local
|
||||
copy of the Home Manager manual in the system web browser.
|
||||
'';
|
||||
};
|
||||
|
||||
manual.manpages.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@@ -59,10 +85,17 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf config.manual.manpages.enable {
|
||||
# To fix error during manpage build.
|
||||
meta.doc = builtins.toFile "nothingness" "<para></para>";
|
||||
config = {
|
||||
home.packages = mkMerge [
|
||||
(mkIf cfg.html.enable [ helpScript homeManagerManual.manual ])
|
||||
|
||||
home.packages = [ homeEnvironmentManPages ];
|
||||
(mkIf cfg.manpages.enable [ homeManagerManual.manpages ])
|
||||
];
|
||||
};
|
||||
|
||||
# To fix error during manpage build.
|
||||
meta = {
|
||||
maintainers = [ maintainers.rycee ];
|
||||
doc = builtins.toFile "nothingness" "";
|
||||
};
|
||||
}
|
||||
|
||||
83
modules/misc/dconf.nix
Normal file
83
modules/misc/dconf.nix
Normal file
@@ -0,0 +1,83 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.dconf;
|
||||
dag = config.lib.dag;
|
||||
|
||||
toDconfIni = generators.toINI { mkKeyValue = mkIniKeyValue; };
|
||||
|
||||
mkIniKeyValue = key: value:
|
||||
let
|
||||
tweakVal = v:
|
||||
if isString v then "'${v}'"
|
||||
else if isList v then "[" + concatMapStringsSep "," tweakVal v + "]"
|
||||
else if isBool v then (if v then "true" else "false")
|
||||
else toString v;
|
||||
in
|
||||
"${key}=${tweakVal value}";
|
||||
|
||||
primitive = with types; either bool (either int str);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.gnidorah maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
dconf = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
visible = false;
|
||||
description = ''
|
||||
Whether to enable dconf settings.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = with types;
|
||||
attrsOf (attrsOf (either primitive (listOf primitive)));
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
"org/gnome/calculator" = {
|
||||
button-mode = "programming";
|
||||
show-thousands = true;
|
||||
base = 10;
|
||||
word-size = 64;
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Settings to write to the dconf configuration system.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.enable && cfg.settings != {}) {
|
||||
home.activation.dconfSettings = dag.entryAfter ["installPackages"] (
|
||||
let
|
||||
iniFile = pkgs.writeText "hm-dconf.ini" (toDconfIni cfg.settings);
|
||||
in
|
||||
''
|
||||
if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then
|
||||
DCONF_DBUS_RUN_SESSION=""
|
||||
else
|
||||
DCONF_DBUS_RUN_SESSION="${pkgs.dbus}/bin/dbus-run-session"
|
||||
fi
|
||||
|
||||
if [[ -v DRY_RUN ]]; then
|
||||
echo $DCONF_DBUS_RUN_SESSION ${pkgs.gnome3.dconf}/bin/dconf load / "<" ${iniFile}
|
||||
else
|
||||
$DCONF_DBUS_RUN_SESSION ${pkgs.gnome3.dconf}/bin/dconf load / < ${iniFile}
|
||||
fi
|
||||
|
||||
unset DCONF_DBUS_RUN_SESSION
|
||||
''
|
||||
);
|
||||
};
|
||||
}
|
||||
41
modules/misc/fontconfig.nix
Normal file
41
modules/misc/fontconfig.nix
Normal file
@@ -0,0 +1,41 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.fonts.fontconfig;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
fonts.fontconfig = {
|
||||
enableProfileFonts = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Configure fontconfig to discover fonts installed through
|
||||
<varname>home.packages</varname> and
|
||||
<command>nix-env</command>.
|
||||
</para><para>
|
||||
Note, this is only necessary on non-NixOS systems.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enableProfileFonts {
|
||||
xdg.configFile."fontconfig/conf.d/10-nix-profile-fonts.conf".text = ''
|
||||
<?xml version='1.0'?>
|
||||
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
|
||||
<fontconfig>
|
||||
<dir>${config.home.profileDirectory}/lib/X11/fonts</dir>
|
||||
<dir>${config.home.profileDirectory}/share/fonts</dir>
|
||||
</fontconfig>
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -8,7 +8,7 @@ let
|
||||
cfg2 = config.gtk.gtk2;
|
||||
cfg3 = config.gtk.gtk3;
|
||||
|
||||
toGtk3Ini = (import ../lib/generators.nix).toINI {
|
||||
toGtk3Ini = generators.toINI {
|
||||
mkKeyValue = key: value:
|
||||
let
|
||||
value' =
|
||||
@@ -27,78 +27,115 @@ let
|
||||
in
|
||||
"${n} = ${v'}";
|
||||
|
||||
fontType = types.submodule {
|
||||
options = {
|
||||
package = mkOption {
|
||||
type = types.nullOr types.package;
|
||||
default = null;
|
||||
example = literalExample "pkgs.dejavu_fonts";
|
||||
description = ''
|
||||
Package providing the font. This package will be installed
|
||||
to your profile. If <literal>null</literal> then the font
|
||||
is assumed to already be available in your profile.
|
||||
'';
|
||||
};
|
||||
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
example = "DejaVu Sans 8";
|
||||
description = ''
|
||||
The family name and size of the font within the package.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
themeType = types.submodule {
|
||||
options = {
|
||||
package = mkOption {
|
||||
type = types.nullOr types.package;
|
||||
default = null;
|
||||
example = literalExample "pkgs.gnome3.gnome_themes_standard";
|
||||
description = ''
|
||||
Package providing the theme. This package will be installed
|
||||
to your profile. If <literal>null</literal> then the theme
|
||||
is assumed to already be available in your profile.
|
||||
'';
|
||||
};
|
||||
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
example = "Adwaita";
|
||||
description = "The name of the theme within the package.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
imports = [
|
||||
(mkRemovedOptionModule ["gtk" "gtk3" "waylandSupport"] ''
|
||||
This options is not longer needed and can be removed.
|
||||
'')
|
||||
];
|
||||
|
||||
options = {
|
||||
gtk = {
|
||||
enable = mkEnableOption "GTK 2/3 configuration";
|
||||
|
||||
fontName = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
font = mkOption {
|
||||
type = types.nullOr fontType;
|
||||
default = null;
|
||||
example = "DejaVu Sans 8";
|
||||
description = ''
|
||||
The font to use in GTK+ 2/3 applications.
|
||||
'';
|
||||
};
|
||||
|
||||
themeName = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
iconTheme = mkOption {
|
||||
type = types.nullOr themeType;
|
||||
default = null;
|
||||
example = "Vertex-Dark";
|
||||
description = "The name of the GTK+2/3 theme to use.";
|
||||
description = "The icon theme to use.";
|
||||
};
|
||||
|
||||
iconThemeName = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
theme = mkOption {
|
||||
type = types.nullOr themeType;
|
||||
default = null;
|
||||
example = "Tango";
|
||||
description = "The name of the icon theme to use.";
|
||||
description = "The GTK+2/3 theme to use.";
|
||||
};
|
||||
|
||||
gtk2 = mkOption {
|
||||
description = "Options specific to GTK+ 2";
|
||||
default = {};
|
||||
type = types.submodule {
|
||||
options = {
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = "gtk-can-change-accels = 1";
|
||||
description = ''
|
||||
Extra configuration lines to add verbatim to
|
||||
<filename>~/.gtkrc-2.0</filename>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
gtk2 = {
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = "gtk-can-change-accels = 1";
|
||||
description = ''
|
||||
Extra configuration lines to add verbatim to
|
||||
<filename>~/.gtkrc-2.0</filename>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
gtk3 = mkOption {
|
||||
description = "Options specific to GTK+ 3";
|
||||
default = {};
|
||||
type = types.submodule {
|
||||
options = {
|
||||
extraConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = { gtk-cursor-blink = false; gtk-recent-files-limit = 20; };
|
||||
description = ''
|
||||
Extra configuration options to add to
|
||||
<filename>~/.config/gtk-3.0/settings.ini</filename>.
|
||||
'';
|
||||
};
|
||||
gtk3 = {
|
||||
extraConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = { gtk-cursor-blink = false; gtk-recent-files-limit = 20; };
|
||||
description = ''
|
||||
Extra configuration options to add to
|
||||
<filename>~/.config/gtk-3.0/settings.ini</filename>.
|
||||
'';
|
||||
};
|
||||
|
||||
extraCss = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra configuration lines to add verbatim to
|
||||
<filename>~/.config/gtk-3.0/gtk.css</filename>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
extraCss = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra configuration lines to add verbatim to
|
||||
<filename>~/.config/gtk-3.0/gtk.css</filename>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -107,25 +144,45 @@ in
|
||||
config = mkIf cfg.enable (
|
||||
let
|
||||
ini =
|
||||
optionalAttrs (cfg.fontName != null)
|
||||
{ gtk-font-name = cfg.fontName; }
|
||||
optionalAttrs (cfg.font != null)
|
||||
{ gtk-font-name = cfg.font.name; }
|
||||
//
|
||||
optionalAttrs (cfg.themeName != null)
|
||||
{ gtk-theme-name = cfg.themeName; }
|
||||
optionalAttrs (cfg.theme != null)
|
||||
{ gtk-theme-name = cfg.theme.name; }
|
||||
//
|
||||
optionalAttrs (cfg.iconThemeName != null)
|
||||
{ gtk-icon-theme-name = cfg.iconThemeName; };
|
||||
optionalAttrs (cfg.iconTheme != null)
|
||||
{ gtk-icon-theme-name = cfg.iconTheme.name; };
|
||||
|
||||
dconfIni =
|
||||
optionalAttrs (cfg.font != null)
|
||||
{ font-name = cfg.font.name; }
|
||||
//
|
||||
optionalAttrs (cfg.theme != null)
|
||||
{ gtk-theme = cfg.theme.name; }
|
||||
//
|
||||
optionalAttrs (cfg.iconTheme != null)
|
||||
{ icon-theme = cfg.iconTheme.name; };
|
||||
|
||||
optionalPackage = opt:
|
||||
optional (opt != null && opt.package != null) opt.package;
|
||||
in
|
||||
{
|
||||
home.packages =
|
||||
optionalPackage cfg.font
|
||||
++ optionalPackage cfg.theme
|
||||
++ optionalPackage cfg.iconTheme;
|
||||
|
||||
home.file.".gtkrc-2.0".text =
|
||||
concatStringsSep "\n" (
|
||||
mapAttrsToList formatGtk2Option ini
|
||||
) + "\n" + cfg2.extraConfig;
|
||||
|
||||
home.file.".config/gtk-3.0/settings.ini".text =
|
||||
xdg.configFile."gtk-3.0/settings.ini".text =
|
||||
toGtk3Ini { Settings = ini // cfg3.extraConfig; };
|
||||
|
||||
home.file.".config/gtk-3.0/gtk.css".text = cfg3.extraCss;
|
||||
xdg.configFile."gtk-3.0/gtk.css".text = cfg3.extraCss;
|
||||
|
||||
dconf.settings."org/gnome/desktop/interface" = dconfIni;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
14
modules/misc/lib.nix
Normal file
14
modules/misc/lib.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
options = {
|
||||
lib = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.attrs;
|
||||
default = {};
|
||||
description = ''
|
||||
This option allows modules to define helper functions,
|
||||
constants, etc.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
1002
modules/misc/news.nix
Normal file
1002
modules/misc/news.nix
Normal file
File diff suppressed because it is too large
Load Diff
153
modules/misc/nixpkgs.nix
Normal file
153
modules/misc/nixpkgs.nix
Normal file
@@ -0,0 +1,153 @@
|
||||
# Adapted from Nixpkgs.
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
isConfig = x:
|
||||
builtins.isAttrs x || builtins.isFunction x;
|
||||
|
||||
optCall = f: x:
|
||||
if builtins.isFunction f
|
||||
then f x
|
||||
else f;
|
||||
|
||||
mergeConfig = lhs_: rhs_:
|
||||
let
|
||||
lhs = optCall lhs_ { inherit pkgs; };
|
||||
rhs = optCall rhs_ { inherit pkgs; };
|
||||
in
|
||||
lhs // rhs //
|
||||
optionalAttrs (lhs ? packageOverrides) {
|
||||
packageOverrides = pkgs:
|
||||
optCall lhs.packageOverrides pkgs //
|
||||
optCall (attrByPath ["packageOverrides"] ({}) rhs) pkgs;
|
||||
} //
|
||||
optionalAttrs (lhs ? perlPackageOverrides) {
|
||||
perlPackageOverrides = pkgs:
|
||||
optCall lhs.perlPackageOverrides pkgs //
|
||||
optCall (attrByPath ["perlPackageOverrides"] ({}) rhs) pkgs;
|
||||
};
|
||||
|
||||
configType = mkOptionType {
|
||||
name = "nixpkgs-config";
|
||||
description = "nixpkgs config";
|
||||
check = x:
|
||||
let traceXIfNot = c:
|
||||
if c x then true
|
||||
else lib.traceSeqN 1 x false;
|
||||
in traceXIfNot isConfig;
|
||||
merge = args: fold (def: mergeConfig def.value) {};
|
||||
};
|
||||
|
||||
overlayType = mkOptionType {
|
||||
name = "nixpkgs-overlay";
|
||||
description = "nixpkgs overlay";
|
||||
check = builtins.isFunction;
|
||||
merge = lib.mergeOneOption;
|
||||
};
|
||||
|
||||
_pkgs = import <nixpkgs> (
|
||||
filterAttrs (n: v: v != null) config.nixpkgs
|
||||
);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.nixpkgs = {
|
||||
config = mkOption {
|
||||
default = null;
|
||||
example = { allowBroken = true; };
|
||||
type = types.nullOr configType;
|
||||
description = ''
|
||||
The configuration of the Nix Packages collection. (For
|
||||
details, see the Nixpkgs documentation.) It allows you to set
|
||||
package configuration options.
|
||||
|
||||
</para><para>
|
||||
|
||||
If <literal>null</literal>, then configuration is taken from
|
||||
the fallback location, for example,
|
||||
<filename>~/.config/nixpkgs/config.nix</filename>.
|
||||
|
||||
</para><para>
|
||||
|
||||
Note, this option will not apply outside your Home Manager
|
||||
configuration like when installing manually through
|
||||
<command>nix-env</command>. If you want to apply it both
|
||||
inside and outside Home Manager you can put it in a separate
|
||||
file and include something like
|
||||
|
||||
<programlisting language="nix">
|
||||
nixpkgs.config = import ./nixpkgs-config.nix;
|
||||
xdg.configFile."nixpkgs/config.nix".source =
|
||||
./nixpkgs-config.nix;
|
||||
</programlisting>
|
||||
|
||||
in your Home Manager configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
overlays = mkOption {
|
||||
default = null;
|
||||
example = literalExample
|
||||
''
|
||||
[ (self: super: {
|
||||
openssh = super.openssh.override {
|
||||
hpnSupport = true;
|
||||
withKerberos = true;
|
||||
kerberos = self.libkrb5;
|
||||
};
|
||||
};
|
||||
) ]
|
||||
'';
|
||||
type = types.nullOr (types.listOf overlayType);
|
||||
description = ''
|
||||
List of overlays to use with the Nix Packages collection. (For
|
||||
details, see the Nixpkgs documentation.) It allows you to
|
||||
override packages globally. This is a function that takes as
|
||||
an argument the <emphasis>original</emphasis> Nixpkgs. The
|
||||
first argument should be used for finding dependencies, and
|
||||
the second should be used for overriding recipes.
|
||||
|
||||
</para><para>
|
||||
|
||||
If <literal>null</literal>, then the overlays are taken from
|
||||
the fallback location, for example,
|
||||
<filename>~/.config/nixpkgs/overlays</filename>.
|
||||
|
||||
</para><para>
|
||||
|
||||
Like <varname>nixpkgs.config</varname> this option only
|
||||
applies within the Home Manager configuration. See
|
||||
<varname>nixpkgs.config</varname> for a suggested setup that
|
||||
works both internally and externally.
|
||||
'';
|
||||
};
|
||||
|
||||
system = mkOption {
|
||||
type = types.str;
|
||||
example = "i686-linux";
|
||||
internal = true;
|
||||
description = ''
|
||||
Specifies the Nix platform type for which the user environment
|
||||
should be built. If unset, it defaults to the platform type of
|
||||
your host system. Specifying this option is useful when doing
|
||||
distributed multi-platform deployment, or when building
|
||||
virtual machines.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
_module.args = {
|
||||
pkgs = _pkgs;
|
||||
pkgs_i686 =
|
||||
if _pkgs.stdenv.isLinux && _pkgs.stdenv.hostPlatform.isx86
|
||||
then _pkgs.pkgsi686Linux
|
||||
else { };
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -4,17 +4,33 @@ with lib;
|
||||
|
||||
let
|
||||
|
||||
homeCfg = config.home;
|
||||
vars = config.pam.sessionVariables;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {};
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
config = mkIf (homeCfg.sessionVariableSetter == "pam") {
|
||||
options = {
|
||||
pam.sessionVariables = mkOption {
|
||||
default = {};
|
||||
type = types.attrs;
|
||||
example = { EDITOR = "vim"; };
|
||||
description = ''
|
||||
Environment variables that will be set for the PAM session.
|
||||
The variable values must be as described in
|
||||
<citerefentry>
|
||||
<refentrytitle>pam_env.conf</refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
</citerefentry>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (vars != {}) {
|
||||
home.file.".pam_environment".text =
|
||||
concatStringsSep "\n" (
|
||||
mapAttrsToList (n: v: "${n} OVERRIDE=${v}") homeCfg.sessionVariables
|
||||
mapAttrsToList (n: v: "${n} OVERRIDE=\"${toString v}\"") vars
|
||||
) + "\n";
|
||||
};
|
||||
}
|
||||
|
||||
41
modules/misc/qt.nix
Normal file
41
modules/misc/qt.nix
Normal file
@@ -0,0 +1,41 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.qt;
|
||||
dag = config.lib.dag;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
qt = {
|
||||
enable = mkEnableOption "Qt 4 and 5 configuration";
|
||||
|
||||
useGtkTheme = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether Qt 4 and 5 should be set up to use the GTK theme
|
||||
settings.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.enable && cfg.useGtkTheme) {
|
||||
home.sessionVariables.QT_QPA_PLATFORMTHEME = "gtk2";
|
||||
home.packages = [ pkgs.libsForQt5.qtstyleplugins ];
|
||||
xsession.profileExtra =
|
||||
"systemctl --user import-environment QT_QPA_PLATFORMTHEME";
|
||||
|
||||
home.activation.useGtkThemeInQt4 = dag.entryAfter ["writeBoundary"] ''
|
||||
$DRY_RUN_CMD ${pkgs.crudini}/bin/crudini $VERBOSE_ARG \
|
||||
--set "${config.xdg.configHome}/Trolltech.conf" Qt style GTK+
|
||||
'';
|
||||
};
|
||||
}
|
||||
32
modules/misc/submodule-support.nix
Normal file
32
modules/misc/submodule-support.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{ lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options.submoduleSupport = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
internal = true;
|
||||
description = ''
|
||||
Whether the Home Manager module system is used as a submodule
|
||||
in, for example, NixOS or nix-darwin.
|
||||
'';
|
||||
};
|
||||
|
||||
externalPackageInstall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
internal = true;
|
||||
description = ''
|
||||
Whether the packages of <option>home.packages</option> are
|
||||
installed separately from the Home Manager activation script.
|
||||
In NixOS, for example, this may be accomplished by installing
|
||||
the packages through
|
||||
<option>users.users.<name?>.packages</option>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
24
modules/misc/version.nix
Normal file
24
modules/misc/version.nix
Normal file
@@ -0,0 +1,24 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
options = {
|
||||
home.stateVersion = mkOption {
|
||||
type = types.enum [ "18.09" "19.03" ];
|
||||
default = "18.09";
|
||||
description = ''
|
||||
It is occasionally necessary for Home Manager to change
|
||||
configuration defaults in a way that is incompatible with
|
||||
stateful data. This could, for example, include switching the
|
||||
default data format or location of a file.
|
||||
</para><para>
|
||||
The <emphasis>state version</emphasis> indicates which default
|
||||
settings are in effect and will therefore help avoid breaking
|
||||
program configurations. Switching to a higher state version
|
||||
typically requires performing some manual steps, such as data
|
||||
conversion or moving files.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
101
modules/misc/xdg.nix
Normal file
101
modules/misc/xdg.nix
Normal file
@@ -0,0 +1,101 @@
|
||||
{ options, config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.xdg;
|
||||
|
||||
dag = config.lib.dag;
|
||||
|
||||
fileType = (import ../lib/file-type.nix {
|
||||
inherit (config.home) homeDirectory;
|
||||
inherit lib pkgs;
|
||||
}).fileType;
|
||||
|
||||
defaultCacheHome = "${config.home.homeDirectory}/.cache";
|
||||
defaultConfigHome = "${config.home.homeDirectory}/.config";
|
||||
defaultDataHome = "${config.home.homeDirectory}/.local/share";
|
||||
|
||||
getXdgDir = name: fallback:
|
||||
let
|
||||
value = builtins.getEnv name;
|
||||
in
|
||||
if value != "" then value else fallback;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.xdg = {
|
||||
enable = mkEnableOption "management of XDG base directories";
|
||||
|
||||
cacheHome = mkOption {
|
||||
type = types.path;
|
||||
defaultText = "~/.cache";
|
||||
description = ''
|
||||
Absolute path to directory holding application caches.
|
||||
'';
|
||||
};
|
||||
|
||||
configFile = mkOption {
|
||||
type = fileType "<varname>xdg.configHome</varname>" cfg.configHome;
|
||||
default = {};
|
||||
description = ''
|
||||
Attribute set of files to link into the user's XDG
|
||||
configuration home.
|
||||
'';
|
||||
};
|
||||
|
||||
configHome = mkOption {
|
||||
type = types.path;
|
||||
defaultText = "~/.config";
|
||||
description = ''
|
||||
Absolute path to directory holding application configurations.
|
||||
'';
|
||||
};
|
||||
|
||||
dataFile = mkOption {
|
||||
type = fileType "<varname>xdg.dataHome</varname>" cfg.dataHome;
|
||||
default = {};
|
||||
description = ''
|
||||
Attribute set of files to link into the user's XDG
|
||||
data home.
|
||||
'';
|
||||
};
|
||||
|
||||
dataHome = mkOption {
|
||||
type = types.path;
|
||||
defaultText = "~/.local/share";
|
||||
description = ''
|
||||
Absolute path to directory holding application data.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
(mkIf cfg.enable {
|
||||
xdg.cacheHome = mkDefault defaultCacheHome;
|
||||
xdg.configHome = mkDefault defaultConfigHome;
|
||||
xdg.dataHome = mkDefault defaultDataHome;
|
||||
|
||||
home.sessionVariables = {
|
||||
XDG_CACHE_HOME = cfg.cacheHome;
|
||||
XDG_CONFIG_HOME = cfg.configHome;
|
||||
XDG_DATA_HOME = cfg.dataHome;
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf (!cfg.enable) {
|
||||
xdg.cacheHome = getXdgDir "XDG_CACHE_HOME" defaultCacheHome;
|
||||
xdg.configHome = getXdgDir "XDG_CONFIG_HOME" defaultConfigHome;
|
||||
xdg.dataHome = getXdgDir "XDG_DATA_HOME" defaultDataHome;
|
||||
})
|
||||
|
||||
{
|
||||
home.file = mkMerge [ cfg.configFile cfg.dataFile ];
|
||||
home.activation.xdgCreateCache = dag.entryAfter [ "writeBoundary" ] ''
|
||||
$DRY_RUN_CMD mkdir $VERBOSE_ARG -m0700 -p "${config.xdg.cacheHome}"
|
||||
'';
|
||||
}
|
||||
];
|
||||
}
|
||||
139
modules/modules.nix
Normal file
139
modules/modules.nix
Normal file
@@ -0,0 +1,139 @@
|
||||
{ pkgs
|
||||
, lib
|
||||
|
||||
# Whether to enable module type checking.
|
||||
, check ? true
|
||||
}:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
hostPlatform = pkgs.stdenv.hostPlatform;
|
||||
|
||||
checkPlatform = any (meta.platformMatch pkgs.stdenv.hostPlatform);
|
||||
|
||||
loadModule = file: { condition ? true }: {
|
||||
inherit file condition;
|
||||
};
|
||||
|
||||
allModules = [
|
||||
(loadModule ./accounts/email.nix { })
|
||||
(loadModule ./files.nix { })
|
||||
(loadModule ./home-environment.nix { })
|
||||
(loadModule ./manual.nix { })
|
||||
(loadModule ./misc/dconf.nix { })
|
||||
(loadModule ./misc/fontconfig.nix { })
|
||||
(loadModule ./misc/gtk.nix { })
|
||||
(loadModule ./misc/lib.nix { })
|
||||
(loadModule ./misc/news.nix { })
|
||||
(loadModule ./misc/nixpkgs.nix { })
|
||||
(loadModule ./misc/pam.nix { })
|
||||
(loadModule ./misc/qt.nix { })
|
||||
(loadModule ./misc/submodule-support.nix { })
|
||||
(loadModule ./misc/version.nix { })
|
||||
(loadModule ./misc/xdg.nix { })
|
||||
(loadModule ./programs/afew.nix { })
|
||||
(loadModule ./programs/alot.nix { })
|
||||
(loadModule ./programs/astroid.nix { })
|
||||
(loadModule ./programs/autorandr.nix { })
|
||||
(loadModule ./programs/bash.nix { })
|
||||
(loadModule ./programs/beets.nix { })
|
||||
(loadModule ./programs/browserpass.nix { })
|
||||
(loadModule ./programs/chromium.nix { condition = hostPlatform.isLinux; })
|
||||
(loadModule ./programs/command-not-found/command-not-found.nix { })
|
||||
(loadModule ./programs/direnv.nix { })
|
||||
(loadModule ./programs/eclipse.nix { })
|
||||
(loadModule ./programs/emacs.nix { })
|
||||
(loadModule ./programs/feh.nix { })
|
||||
(loadModule ./programs/firefox.nix { })
|
||||
(loadModule ./programs/fish.nix { })
|
||||
(loadModule ./programs/fzf.nix { })
|
||||
(loadModule ./programs/git.nix { })
|
||||
(loadModule ./programs/gnome-terminal.nix { })
|
||||
(loadModule ./programs/go.nix { })
|
||||
(loadModule ./programs/home-manager.nix { })
|
||||
(loadModule ./programs/htop.nix { })
|
||||
(loadModule ./programs/info.nix { })
|
||||
(loadModule ./programs/irssi.nix { })
|
||||
(loadModule ./programs/jq.nix { })
|
||||
(loadModule ./programs/lesspipe.nix { })
|
||||
(loadModule ./programs/man.nix { })
|
||||
(loadModule ./programs/matplotlib.nix { })
|
||||
(loadModule ./programs/mbsync.nix { })
|
||||
(loadModule ./programs/mercurial.nix { })
|
||||
(loadModule ./programs/msmtp.nix { })
|
||||
(loadModule ./programs/neovim.nix { })
|
||||
(loadModule ./programs/newsboat.nix { })
|
||||
(loadModule ./programs/noti.nix { })
|
||||
(loadModule ./programs/notmuch.nix { })
|
||||
(loadModule ./programs/obs-studio.nix { })
|
||||
(loadModule ./programs/offlineimap.nix { })
|
||||
(loadModule ./programs/opam.nix { })
|
||||
(loadModule ./programs/pidgin.nix { })
|
||||
(loadModule ./programs/rofi.nix { })
|
||||
(loadModule ./programs/ssh.nix { })
|
||||
(loadModule ./programs/taskwarrior.nix { })
|
||||
(loadModule ./programs/termite.nix { })
|
||||
(loadModule ./programs/texlive.nix { })
|
||||
(loadModule ./programs/tmux.nix { })
|
||||
(loadModule ./programs/urxvt.nix { })
|
||||
(loadModule ./programs/vim.nix { })
|
||||
(loadModule ./programs/vscode.nix { })
|
||||
(loadModule ./programs/zathura.nix { })
|
||||
(loadModule ./programs/zsh.nix { })
|
||||
(loadModule ./services/blueman-applet.nix { })
|
||||
(loadModule ./services/compton.nix { })
|
||||
(loadModule ./services/dunst.nix { })
|
||||
(loadModule ./services/emacs.nix { condition = hostPlatform.isLinux; })
|
||||
(loadModule ./services/flameshot.nix { })
|
||||
(loadModule ./services/gnome-keyring.nix { })
|
||||
(loadModule ./services/gpg-agent.nix { })
|
||||
(loadModule ./services/kbfs.nix { })
|
||||
(loadModule ./services/kdeconnect.nix { })
|
||||
(loadModule ./services/keepassx.nix { })
|
||||
(loadModule ./services/keybase.nix { })
|
||||
(loadModule ./services/mbsync.nix { })
|
||||
(loadModule ./services/mpd.nix { })
|
||||
(loadModule ./services/network-manager-applet.nix { })
|
||||
(loadModule ./services/nextcloud-client.nix { })
|
||||
(loadModule ./services/owncloud-client.nix { })
|
||||
(loadModule ./services/parcellite.nix { })
|
||||
(loadModule ./services/pasystray.nix { })
|
||||
(loadModule ./services/polybar.nix { })
|
||||
(loadModule ./services/random-background.nix { })
|
||||
(loadModule ./services/redshift.nix { })
|
||||
(loadModule ./services/screen-locker.nix { })
|
||||
(loadModule ./services/stalonetray.nix { })
|
||||
(loadModule ./services/status-notifier-watcher.nix { })
|
||||
(loadModule ./services/syncthing.nix { })
|
||||
(loadModule ./services/taffybar.nix { })
|
||||
(loadModule ./services/tahoe-lafs.nix { })
|
||||
(loadModule ./services/udiskie.nix { })
|
||||
(loadModule ./services/unclutter.nix { })
|
||||
(loadModule ./services/window-managers/awesome.nix { })
|
||||
(loadModule ./services/window-managers/i3.nix { })
|
||||
(loadModule ./services/window-managers/xmonad.nix { })
|
||||
(loadModule ./services/xembed-sni-proxy.nix { condition = hostPlatform.isLinux; })
|
||||
(loadModule ./services/xscreensaver.nix { })
|
||||
(loadModule ./systemd.nix { })
|
||||
(loadModule ./xcursor.nix { })
|
||||
(loadModule ./xresources.nix { })
|
||||
(loadModule ./xsession.nix { })
|
||||
(loadModule <nixpkgs/nixos/modules/misc/assertions.nix> { })
|
||||
(loadModule <nixpkgs/nixos/modules/misc/meta.nix> { })
|
||||
];
|
||||
|
||||
modules = map (getAttr "file") (filter (getAttr "condition") allModules);
|
||||
|
||||
pkgsModule = {
|
||||
config._module.args.baseModules = modules;
|
||||
config._module.args.pkgs = lib.mkDefault pkgs;
|
||||
config._module.check = check;
|
||||
config.lib = import ./lib { inherit lib; };
|
||||
config.nixpkgs.system = mkDefault pkgs.system;
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
modules ++ [ pkgsModule ]
|
||||
52
modules/programs/afew.nix
Normal file
52
modules/programs/afew.nix
Normal file
@@ -0,0 +1,52 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.afew;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.programs.afew = {
|
||||
enable = mkEnableOption "the afew initial tagging script for Notmuch";
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = ''
|
||||
[SpamFilter]
|
||||
[KillThreadsFilter]
|
||||
[ListMailsFilter]
|
||||
[ArchiveSentMailsFilter]
|
||||
[InboxFilter]
|
||||
'';
|
||||
example = ''
|
||||
[SpamFilter]
|
||||
|
||||
[Filter.0]
|
||||
query = from:pointyheaded@boss.com
|
||||
tags = -new;+boss
|
||||
message = Message from above
|
||||
|
||||
[InboxFilter]
|
||||
'';
|
||||
description = ''
|
||||
Extra lines added to afew configuration file. Available
|
||||
configuration options are described in the afew manual:
|
||||
<link xlink:href="https://afew.readthedocs.io/en/latest/configuration.html" />.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.afew ];
|
||||
|
||||
xdg.configFile."afew/config".text = ''
|
||||
# Generated by Home Manager.
|
||||
# See https://afew.readthedocs.io/
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
};
|
||||
}
|
||||
32
modules/programs/alot-accounts.nix
Normal file
32
modules/programs/alot-accounts.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
options.alot = {
|
||||
sendMailCommand = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
description = ''
|
||||
Command to send a mail. If msmtp is enabled for the account,
|
||||
then this is set to
|
||||
<command>msmtpq --read-envelope-from --read-recipients</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra settings to add to this Alot account configuration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf config.notmuch.enable {
|
||||
alot.sendMailCommand = mkOptionDefault (
|
||||
if config.msmtp.enable
|
||||
then "msmtpq --read-envelope-from --read-recipients"
|
||||
else null
|
||||
);
|
||||
};
|
||||
}
|
||||
167
modules/programs/alot.nix
Normal file
167
modules/programs/alot.nix
Normal file
@@ -0,0 +1,167 @@
|
||||
# alot config loader is sensitive to leading space !
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.alot;
|
||||
|
||||
alotAccounts = filter (a: a.notmuch.enable)
|
||||
(attrValues config.accounts.email.accounts);
|
||||
|
||||
boolStr = v: if v then "True" else "False";
|
||||
|
||||
accountStr = account: with account;
|
||||
concatStringsSep "\n" (
|
||||
[ "[[${name}]]" ]
|
||||
++ mapAttrsToList (n: v: n + "=" + v) (
|
||||
{
|
||||
address = address;
|
||||
realname = realName;
|
||||
sendmail_command =
|
||||
optionalString (alot.sendMailCommand != null) alot.sendMailCommand;
|
||||
}
|
||||
// optionalAttrs (gpg != null) {
|
||||
gpg_key = gpg.key;
|
||||
encrypt_by_default = if gpg.encryptByDefault then "all" else "none";
|
||||
sign_by_default = boolStr gpg.signByDefault;
|
||||
}
|
||||
// optionalAttrs (signature.showSignature != "none") {
|
||||
signature = pkgs.writeText "signature.txt" signature.text;
|
||||
signature_as_attachment =
|
||||
boolStr (signature.showSignature == "attach");
|
||||
}
|
||||
)
|
||||
)
|
||||
+ "\n"
|
||||
+ alot.extraConfig;
|
||||
|
||||
configFile =
|
||||
let
|
||||
bindingsToStr = attrSet:
|
||||
concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${v}") attrSet);
|
||||
in
|
||||
''
|
||||
# Generated by Home Manager.
|
||||
# See http://alot.readthedocs.io/en/latest/configuration/config_options.html
|
||||
|
||||
${cfg.extraConfig}
|
||||
|
||||
[bindings]
|
||||
${bindingsToStr cfg.bindings.global}
|
||||
|
||||
[[bufferlist]]
|
||||
${bindingsToStr cfg.bindings.bufferlist}
|
||||
[[search]]
|
||||
${bindingsToStr cfg.bindings.search}
|
||||
[[envelope]]
|
||||
${bindingsToStr cfg.bindings.envelope}
|
||||
[[taglist]]
|
||||
${bindingsToStr cfg.bindings.taglist}
|
||||
[[thread]]
|
||||
${bindingsToStr cfg.bindings.thread}
|
||||
|
||||
[accounts]
|
||||
|
||||
${concatStringsSep "\n\n" (map accountStr alotAccounts)}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.programs.alot = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether to enable the Alot mail user agent. Alot uses the
|
||||
Notmuch email system and will therefore be automatically
|
||||
enabled for each email account that is managed by Notmuch.
|
||||
'';
|
||||
};
|
||||
|
||||
hooks = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Content of the hooks file.
|
||||
'';
|
||||
};
|
||||
|
||||
bindings = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
global = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Global keybindings.";
|
||||
};
|
||||
|
||||
bufferlist = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Bufferlist mode keybindings.";
|
||||
};
|
||||
|
||||
search = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Search mode keybindings.";
|
||||
};
|
||||
|
||||
envelope = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Envelope mode keybindings.";
|
||||
};
|
||||
|
||||
taglist = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Taglist mode keybindings.";
|
||||
};
|
||||
|
||||
thread = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Thread mode keybindings.";
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = ''
|
||||
Keybindings.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = ''
|
||||
auto_remove_unread = True
|
||||
ask_subject = False
|
||||
handle_mouse = True
|
||||
initial_command = "search tag:inbox AND NOT tag:killed"
|
||||
input_timeout = 0.3
|
||||
prefer_plaintext = True
|
||||
thread_indent_replies = 4
|
||||
'';
|
||||
description = ''
|
||||
Extra lines added to alot configuration file.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.alot ];
|
||||
|
||||
xdg.configFile."alot/config".text = configFile;
|
||||
|
||||
xdg.configFile."alot/hooks.py".text =
|
||||
''
|
||||
# Generated by Home Manager.
|
||||
''
|
||||
+ cfg.hooks;
|
||||
};
|
||||
}
|
||||
33
modules/programs/astroid-accounts.nix
Normal file
33
modules/programs/astroid-accounts.nix
Normal file
@@ -0,0 +1,33 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
options.astroid = {
|
||||
enable = mkEnableOption "Astroid";
|
||||
|
||||
sendMailCommand = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Command to send a mail. If msmtp is enabled for the account,
|
||||
then this is set to
|
||||
<command>msmtpq --read-envelope-from --read-recipients</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = { select_query = ""; };
|
||||
description = ''
|
||||
Extra settings to add to this astroid account configuration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf config.notmuch.enable {
|
||||
astroid.sendMailCommand = mkIf config.msmtp.enable (
|
||||
mkOptionDefault "msmtpq --read-envelope-from --read-recipients"
|
||||
);
|
||||
};
|
||||
}
|
||||
113
modules/programs/astroid-config-template.json
Normal file
113
modules/programs/astroid-config-template.json
Normal file
@@ -0,0 +1,113 @@
|
||||
{
|
||||
"astroid": {
|
||||
"config": {
|
||||
"version": "11"
|
||||
},
|
||||
"debug": {
|
||||
"dryrun_sending": "false"
|
||||
},
|
||||
"hints": {
|
||||
"level": "0"
|
||||
},
|
||||
"log": {
|
||||
"syslog": "false",
|
||||
"stdout": "true",
|
||||
"level": "info"
|
||||
}
|
||||
},
|
||||
"startup": {
|
||||
"queries": {
|
||||
"inbox": "tag:inbox"
|
||||
}
|
||||
},
|
||||
"terminal": {
|
||||
"height": "10",
|
||||
"font_description": "default"
|
||||
},
|
||||
"thread_index": {
|
||||
"page_jump_rows": "6",
|
||||
"sort_order": "newest",
|
||||
"cell": {
|
||||
"font_description": "default",
|
||||
"line_spacing": "2",
|
||||
"date_length": "10",
|
||||
"message_count_length": "4",
|
||||
"authors_length": "20",
|
||||
"subject_color": "#807d74",
|
||||
"subject_color_selected": "#000000",
|
||||
"background_color_selected": "",
|
||||
"background_color_marked": "#fff584",
|
||||
"background_color_marked_selected": "#bcb559",
|
||||
"tags_length": "80",
|
||||
"tags_upper_color": "#e5e5e5",
|
||||
"tags_lower_color": "#333333",
|
||||
"tags_alpha": "0.5",
|
||||
"hidden_tags": "attachment,flagged,unread"
|
||||
}
|
||||
},
|
||||
"general": {
|
||||
"time": {
|
||||
"clock_format": "local",
|
||||
"same_year": "%b %-e",
|
||||
"diff_year": "%x"
|
||||
}
|
||||
},
|
||||
"editor": {
|
||||
"charset": "utf-8",
|
||||
"save_draft_on_force_quit": "true",
|
||||
"attachment_words": "attach",
|
||||
"attachment_directory": "~",
|
||||
"markdown_processor": "marked"
|
||||
},
|
||||
"mail": {
|
||||
"reply": {
|
||||
"quote_line": "Excerpts from %1's message of %2:",
|
||||
"mailinglist_reply_to_sender": "true"
|
||||
},
|
||||
"forward": {
|
||||
"quote_line": "Forwarding %1's message of %2:",
|
||||
"disposition": "inline"
|
||||
},
|
||||
"sent_tags": "sent",
|
||||
"message_id_fqdn": "",
|
||||
"message_id_user": "",
|
||||
"user_agent": "default",
|
||||
"send_delay": "2",
|
||||
"close_on_success": "false",
|
||||
"format_flowed": "false"
|
||||
},
|
||||
"poll": {
|
||||
"interval": "60",
|
||||
"always_full_refresh": "false"
|
||||
},
|
||||
"attachment": {
|
||||
"external_open_cmd": "xdg-open"
|
||||
},
|
||||
"thread_view": {
|
||||
"open_html_part_external": "false",
|
||||
"preferred_type": "plain",
|
||||
"preferred_html_only": "false",
|
||||
"allow_remote_when_encrypted": "false",
|
||||
"open_external_link": "xdg-open",
|
||||
"default_save_directory": "~",
|
||||
"indent_messages": "false",
|
||||
"gravatar": {
|
||||
"enable": "true"
|
||||
},
|
||||
"mark_unread_delay": "0.5",
|
||||
"expand_flagged": "true"
|
||||
},
|
||||
"crypto": {
|
||||
"gpg": {
|
||||
"path": "gpg2",
|
||||
"always_trust": "true",
|
||||
"enabled": "true"
|
||||
}
|
||||
},
|
||||
"saved_searches": {
|
||||
"show_on_startup": "false",
|
||||
"save_history": "true",
|
||||
"history_lines_to_show": "15",
|
||||
"history_lines": "1000"
|
||||
}
|
||||
}
|
||||
139
modules/programs/astroid.nix
Normal file
139
modules/programs/astroid.nix
Normal file
@@ -0,0 +1,139 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
with builtins;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.astroid;
|
||||
|
||||
astroidAccounts =
|
||||
filterAttrs
|
||||
(n: v: v.astroid.enable)
|
||||
config.accounts.email.accounts;
|
||||
|
||||
boolOpt = b: if b then "true" else "false";
|
||||
|
||||
accountAttr = account: with account; {
|
||||
email = address;
|
||||
name = realName;
|
||||
sendmail = astroid.sendMailCommand;
|
||||
additional_sent_tags = "";
|
||||
default = boolOpt primary;
|
||||
save_drafts_to = folders.drafts;
|
||||
save_sent = "true";
|
||||
save_sent_to = folders.sent;
|
||||
select_query = "";
|
||||
}
|
||||
// optionalAttrs (signature.showSignature != "none") {
|
||||
signature_attach = boolOpt (signature.showSignature == "attach");
|
||||
signature_default_on = boolOpt (signature.showSignature != "none");
|
||||
signature_file = pkgs.writeText "signature.txt" signature.text;
|
||||
signature_file_markdown = "false";
|
||||
signature_separate = "true"; # prepends '--\n' to the signature
|
||||
}
|
||||
// optionalAttrs (gpg != null) {
|
||||
always_gpg_sign = boolOpt gpg.signByDefault;
|
||||
gpgkey = gpg.key;
|
||||
}
|
||||
// astroid.extraConfig;
|
||||
|
||||
# See https://github.com/astroidmail/astroid/wiki/Configuration-Reference
|
||||
configFile = mailAccounts:
|
||||
let
|
||||
template = fromJSON (readFile ./astroid-config-template.json);
|
||||
astroidConfig = foldl' recursiveUpdate template [
|
||||
{
|
||||
astroid.notmuch_config = "${config.xdg.configHome}/notmuch/notmuchrc";
|
||||
accounts = mapAttrs (n: accountAttr) astroidAccounts;
|
||||
crypto.gpg.path = "${pkgs.gnupg}/bin/gpg";
|
||||
}
|
||||
cfg.extraConfig
|
||||
cfg.externalEditor
|
||||
];
|
||||
in
|
||||
builtins.toJSON astroidConfig;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.astroid = {
|
||||
enable = mkEnableOption "Astroid";
|
||||
|
||||
pollScript = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "mbsync gmail";
|
||||
description = ''
|
||||
Script to run to fetch/update mails.
|
||||
'';
|
||||
};
|
||||
|
||||
externalEditor = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
# Converts it into JSON that can be merged into the configuration.
|
||||
apply = cmd:
|
||||
optionalAttrs (cmd != null) {
|
||||
editor = {
|
||||
"external_editor" = "true";
|
||||
"cmd" = cmd;
|
||||
};
|
||||
};
|
||||
example = "nvim-qt -- -c 'set ft=mail' '+set fileencoding=utf-8' '+set ff=unix' '+set enc=utf-8' '+set fo+=w' %1";
|
||||
description = ''
|
||||
You can use <code>%1</code>, <code>%2</code>, and
|
||||
<code>%3</code> to refer respectively to:
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem><para>file name</para></listitem>
|
||||
<listitem><para>server name</para></listitem>
|
||||
<listitem><para>socket ID</para></listitem>
|
||||
</orderedlist>
|
||||
See <link xlink:href='https://github.com/astroidmail/astroid/wiki/Customizing-editor' />.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = { poll.interval = 0; };
|
||||
description = ''
|
||||
JSON config that will override the default Astroid configuration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = config.programs.notmuch.maildir.synchronizeFlags;
|
||||
message = "The astroid module requires"
|
||||
+ " 'programs.notmuch.maildir.synchronizeFlags = true'.";
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = [ pkgs.astroid ];
|
||||
|
||||
xdg.configFile."astroid/config".source =
|
||||
pkgs.runCommand "out.json"
|
||||
{
|
||||
json = configFile astroidAccounts;
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
}
|
||||
''
|
||||
echo -n "$json" | ${pkgs.jq}/bin/jq . > $out
|
||||
'';
|
||||
|
||||
xdg.configFile."astroid/poll.sh" = {
|
||||
executable = true;
|
||||
text = ''
|
||||
# Generated by Home Manager
|
||||
|
||||
${cfg.pollScript}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
277
modules/programs/autorandr.nix
Normal file
277
modules/programs/autorandr.nix
Normal file
@@ -0,0 +1,277 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.autorandr;
|
||||
|
||||
matrixOf = n: m: elemType: mkOptionType rec {
|
||||
name = "matrixOf";
|
||||
description = "${toString n}×${toString m} matrix of ${elemType.description}s";
|
||||
check = xss:
|
||||
let
|
||||
listOfSize = l: xs: isList xs && length xs == l;
|
||||
in
|
||||
listOfSize n xss && all (xs: listOfSize m xs && all elemType.check xs) xss;
|
||||
merge = mergeOneOption;
|
||||
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*" "*"]);
|
||||
getSubModules = elemType.getSubModules;
|
||||
substSubModules = mod: matrixOf n m (elemType.substSubModules mod);
|
||||
functor = (defaultFunctor name) // { wrapped = elemType; };
|
||||
};
|
||||
|
||||
profileModule = types.submodule {
|
||||
options = {
|
||||
fingerprint = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
description = ''
|
||||
Output name to EDID mapping.
|
||||
Use <code>autorandr --fingerprint</code> to get current setup values.
|
||||
'';
|
||||
default = {};
|
||||
};
|
||||
|
||||
config = mkOption {
|
||||
type = types.attrsOf configModule;
|
||||
description = "Per output profile configuration.";
|
||||
default = {};
|
||||
};
|
||||
|
||||
hooks = mkOption {
|
||||
type = profileHooksModule;
|
||||
description = "Profile hook scripts.";
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configModule = types.submodule {
|
||||
options = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
description = "Whether to enable the output.";
|
||||
default = true;
|
||||
};
|
||||
|
||||
primary = mkOption {
|
||||
type = types.bool;
|
||||
description = "Whether output should be marked as primary";
|
||||
default = false;
|
||||
};
|
||||
|
||||
position = mkOption {
|
||||
type = types.str;
|
||||
description = "Output position";
|
||||
default = "";
|
||||
example = "5760x0";
|
||||
};
|
||||
|
||||
mode = mkOption {
|
||||
type = types.str;
|
||||
description = "Output resolution.";
|
||||
default = "";
|
||||
example = "3840x2160";
|
||||
};
|
||||
|
||||
rate = mkOption {
|
||||
type = types.str;
|
||||
description = "Output framerate.";
|
||||
default = "";
|
||||
example = "60.00";
|
||||
};
|
||||
|
||||
gamma = mkOption {
|
||||
type = types.str;
|
||||
description = "Output gamma configuration.";
|
||||
default = "";
|
||||
example = "1.0:0.909:0.833";
|
||||
};
|
||||
|
||||
rotate = mkOption {
|
||||
type = types.nullOr (types.enum ["normal" "left" "right" "inverted"]);
|
||||
description = "Output rotate configuration.";
|
||||
default = null;
|
||||
example = "left";
|
||||
};
|
||||
|
||||
transform = mkOption {
|
||||
type = types.nullOr (matrixOf 3 3 types.float);
|
||||
default = null;
|
||||
example = literalExample ''
|
||||
[
|
||||
[ 0.6 0.0 0.0 ]
|
||||
[ 0.0 0.6 0.0 ]
|
||||
[ 0.0 0.0 1.0 ]
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
Refer to
|
||||
<citerefentry>
|
||||
<refentrytitle>xrandr</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>
|
||||
for the documentation of the transform matrix.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hookType = types.lines;
|
||||
|
||||
globalHooksModule = types.submodule {
|
||||
options = {
|
||||
postswitch = mkOption {
|
||||
type = types.attrsOf hookType;
|
||||
description = "Postswitch hook executed after mode switch.";
|
||||
default = {};
|
||||
};
|
||||
|
||||
preswitch = mkOption {
|
||||
type = types.attrsOf hookType;
|
||||
description = "Preswitch hook executed before mode switch.";
|
||||
default = {};
|
||||
};
|
||||
|
||||
predetect = mkOption {
|
||||
type = types.attrsOf hookType;
|
||||
description = "Predetect hook executed before autorandr attempts to run xrandr.";
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
profileHooksModule = types.submodule {
|
||||
options = {
|
||||
postswitch = mkOption {
|
||||
type = hookType;
|
||||
description = "Postswitch hook executed after mode switch.";
|
||||
default = "";
|
||||
};
|
||||
|
||||
preswitch = mkOption {
|
||||
type = hookType;
|
||||
description = "Preswitch hook executed before mode switch.";
|
||||
default = "";
|
||||
};
|
||||
|
||||
predetect = mkOption {
|
||||
type = hookType;
|
||||
description = "Predetect hook executed before autorandr attempts to run xrandr.";
|
||||
default = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hookToFile = folder: name: hook:
|
||||
nameValuePair
|
||||
"autorandr/${folder}/${name}"
|
||||
{ source = "${pkgs.writeShellScriptBin "hook" hook}/bin/hook"; };
|
||||
profileToFiles = name: profile: with profile; mkMerge ([
|
||||
{
|
||||
"autorandr/${name}/setup".text = concatStringsSep "\n" (mapAttrsToList fingerprintToString fingerprint);
|
||||
"autorandr/${name}/config".text = concatStringsSep "\n" (mapAttrsToList configToString profile.config);
|
||||
}
|
||||
(mkIf (hooks.postswitch != "") (listToAttrs [ (hookToFile name "postswitch" hooks.postswitch) ]))
|
||||
(mkIf (hooks.preswitch != "") (listToAttrs [ (hookToFile name "preswitch" hooks.preswitch) ]))
|
||||
(mkIf (hooks.predetect != "") (listToAttrs [ (hookToFile name "predetect" hooks.predetect) ]))
|
||||
]);
|
||||
fingerprintToString = name: edid: "${name} ${edid}";
|
||||
configToString = name: config: if config.enable then ''
|
||||
output ${name}
|
||||
${optionalString (config.position != "") "pos ${config.position}"}
|
||||
${optionalString config.primary "primary"}
|
||||
${optionalString (config.gamma != "") "gamma ${config.gamma}"}
|
||||
${optionalString (config.mode != "") "mode ${config.mode}"}
|
||||
${optionalString (config.rate != "") "rate ${config.rate}"}
|
||||
${optionalString (config.rotate != null) "rotate ${config.rotate}"}
|
||||
${optionalString (config.transform != null) (
|
||||
"transform " + concatMapStringsSep "," toString (flatten config.transform)
|
||||
)}
|
||||
'' else ''
|
||||
output ${name}
|
||||
off
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.autorandr = {
|
||||
enable = mkEnableOption "Autorandr";
|
||||
|
||||
hooks = mkOption {
|
||||
type = globalHooksModule;
|
||||
description = "Global hook scripts";
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
postswitch = {
|
||||
"notify-i3" = "''${pkgs.i3}/bin/i3-msg restart";
|
||||
"change-background" = readFile ./change-background.sh;
|
||||
"change-dpi" = '''
|
||||
case "$AUTORANDR_CURRENT_PROFILE" in
|
||||
default)
|
||||
DPI=120
|
||||
;;
|
||||
home)
|
||||
DPI=192
|
||||
;;
|
||||
work)
|
||||
DPI=144
|
||||
;;
|
||||
*)
|
||||
echo "Unknown profle: $AUTORANDR_CURRENT_PROFILE"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
echo "Xft.dpi: $DPI" | ''${pkgs.xorg.xrdb}/bin/xrdb -merge
|
||||
'''
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
profiles = mkOption {
|
||||
type = types.attrsOf profileModule;
|
||||
description = "Autorandr profiles specification.";
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
"work" = {
|
||||
fingerprint = {
|
||||
eDP1 = "<EDID>";
|
||||
DP1 = "<EDID>";
|
||||
};
|
||||
config = {
|
||||
eDP1.enable = false;
|
||||
DP1 = {
|
||||
enable = true;
|
||||
primary = true;
|
||||
position = "0x0";
|
||||
mode = "3840x2160";
|
||||
gamma = "1.0:0.909:0.833";
|
||||
rate = "60.00";
|
||||
rotate = "left";
|
||||
};
|
||||
};
|
||||
hooks.postswitch = readFile ./work-postswitch.sh;
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.autorandr ];
|
||||
xdg.configFile = mkMerge ([
|
||||
(mapAttrs' (hookToFile "postswitch.d") cfg.hooks.postswitch)
|
||||
(mapAttrs' (hookToFile "preswitch.d") cfg.hooks.preswitch)
|
||||
(mapAttrs' (hookToFile "predetect.d") cfg.hooks.predetect)
|
||||
(mkMerge (mapAttrsToList profileToFiles cfg.profiles))
|
||||
]);
|
||||
};
|
||||
|
||||
meta.maintainers = [ maintainers.uvnikita ];
|
||||
}
|
||||
@@ -9,6 +9,8 @@ let
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.bash = {
|
||||
enable = mkEnableOption "GNU Bourne-Again SHell";
|
||||
@@ -19,6 +21,12 @@ in
|
||||
description = "Number of history lines to keep in memory.";
|
||||
};
|
||||
|
||||
historyFile = mkOption {
|
||||
type = types.str;
|
||||
default = "$HOME/.bash_history";
|
||||
description = "Location of the bash history file.";
|
||||
};
|
||||
|
||||
historyFileSize = mkOption {
|
||||
type = types.int;
|
||||
default = 100000;
|
||||
@@ -62,13 +70,21 @@ in
|
||||
description = "Shell options to set.";
|
||||
};
|
||||
|
||||
sessionVariables = mkOption {
|
||||
default = {};
|
||||
type = types.attrs;
|
||||
example = { MAILCHECK = 30; };
|
||||
description = ''
|
||||
Environment variables that will be set for the Bash session.
|
||||
'';
|
||||
};
|
||||
|
||||
shellAliases = mkOption {
|
||||
default = {};
|
||||
example = { ll = "ls -l"; ".." = "cd .."; };
|
||||
description = ''
|
||||
An attribute set that maps aliases (the top level attribute names in
|
||||
this option) to command strings or directly to build outputs. The
|
||||
aliases are added to all users' shells.
|
||||
this option) to command strings or directly to build outputs.
|
||||
'';
|
||||
type = types.attrs;
|
||||
};
|
||||
@@ -82,13 +98,30 @@ in
|
||||
profileExtra = mkOption {
|
||||
default = "";
|
||||
type = types.lines;
|
||||
description = "Extra commands that should be added to .profile.";
|
||||
description = ''
|
||||
Extra commands that should be run when initializing a login
|
||||
shell.
|
||||
'';
|
||||
};
|
||||
|
||||
bashrcExtra = mkOption {
|
||||
# Hide for now, may want to rename in the future.
|
||||
visible = false;
|
||||
default = "";
|
||||
type = types.lines;
|
||||
description = ''
|
||||
Extra commands that should be added to
|
||||
<filename>~/.bashrc</filename>.
|
||||
'';
|
||||
};
|
||||
|
||||
initExtra = mkOption {
|
||||
default = "";
|
||||
type = types.lines;
|
||||
description = "Extra commands that should be added to .bashrc.";
|
||||
description = ''
|
||||
Extra commands that should be run when initializing an
|
||||
interactive shell.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -96,24 +129,46 @@ in
|
||||
config = (
|
||||
let
|
||||
aliasesStr = concatStringsSep "\n" (
|
||||
mapAttrsToList (k: v: "alias ${k}='${v}'") cfg.shellAliases
|
||||
mapAttrsToList (k: v: "alias ${k}=${escapeShellArg v}") cfg.shellAliases
|
||||
);
|
||||
|
||||
shoptsStr = concatStringsSep "\n" (
|
||||
map (v: "shopt -s ${v}") cfg.shellOptions
|
||||
);
|
||||
|
||||
export = n: v: "export ${n}=\"${toString v}\"";
|
||||
exportIfNonNull = n: v: optionalString (v != null) (export n v);
|
||||
exportIfNonEmpty = n: v: optionalString (v != "") (export n v);
|
||||
sessionVarsStr = config.lib.shell.exportAll cfg.sessionVariables;
|
||||
|
||||
histControlStr = concatStringsSep ":" cfg.historyControl;
|
||||
histIgnoreStr = concatStringsSep ":" cfg.historyIgnore;
|
||||
|
||||
envVarsStr = concatStringsSep "\n" (
|
||||
mapAttrsToList export config.home.sessionVariables
|
||||
);
|
||||
historyControlStr =
|
||||
concatStringsSep "\n" (mapAttrsToList (n: v: "${n}=${v}") (
|
||||
{
|
||||
HISTFILE = "\"${cfg.historyFile}\"";
|
||||
HISTFILESIZE = toString cfg.historyFileSize;
|
||||
HISTSIZE = toString cfg.historySize;
|
||||
}
|
||||
// optionalAttrs (cfg.historyControl != []) {
|
||||
HISTCONTROL = concatStringsSep ":" cfg.historyControl;
|
||||
}
|
||||
// optionalAttrs (cfg.historyIgnore != []) {
|
||||
HISTIGNORE = concatStringsSep ":" cfg.historyIgnore;
|
||||
}
|
||||
));
|
||||
in mkIf cfg.enable {
|
||||
programs.bash.bashrcExtra = ''
|
||||
# Commands that should be applied only for interactive shells.
|
||||
if [[ $- == *i* ]]; then
|
||||
${historyControlStr}
|
||||
|
||||
${shoptsStr}
|
||||
|
||||
${aliasesStr}
|
||||
|
||||
${cfg.initExtra}
|
||||
|
||||
${optionalString cfg.enableAutojump
|
||||
". ${pkgs.autojump}/share/autojump/autojump.bash"}
|
||||
fi
|
||||
'';
|
||||
|
||||
home.file.".bash_profile".text = ''
|
||||
# -*- mode: sh -*-
|
||||
|
||||
@@ -127,8 +182,9 @@ in
|
||||
home.file.".profile".text = ''
|
||||
# -*- mode: sh -*-
|
||||
|
||||
${optionalString (config.home.sessionVariableSetter == "bash")
|
||||
envVarsStr}
|
||||
. "${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh"
|
||||
|
||||
${sessionVarsStr}
|
||||
|
||||
${cfg.profileExtra}
|
||||
'';
|
||||
@@ -136,22 +192,7 @@ in
|
||||
home.file.".bashrc".text = ''
|
||||
# -*- mode: sh -*-
|
||||
|
||||
# Skip if not running interactively.
|
||||
[ -z "$PS1" ] && return
|
||||
|
||||
${export "HISTSIZE" cfg.historySize}
|
||||
${export "HISTFILESIZE" cfg.historyFileSize}
|
||||
${exportIfNonEmpty "HISTCONTROL" histControlStr}
|
||||
${exportIfNonEmpty "HISTIGNORE" histIgnoreStr}
|
||||
|
||||
${shoptsStr}
|
||||
|
||||
${aliasesStr}
|
||||
|
||||
${cfg.initExtra}
|
||||
|
||||
${optionalString cfg.enableAutojump
|
||||
". ${pkgs.autojump}/share/autojump/autojump.bash"}
|
||||
${cfg.bashrcExtra}
|
||||
'';
|
||||
|
||||
home.packages =
|
||||
|
||||
@@ -9,8 +9,25 @@ let
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.beets = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default =
|
||||
if versionAtLeast config.home.stateVersion "19.03"
|
||||
then false
|
||||
else cfg.settings != {};
|
||||
defaultText = "false";
|
||||
description = ''
|
||||
Whether to enable the beets music library manager. This
|
||||
defaults to <literal>false</literal> for state
|
||||
version ≥ 19.03. For earlier versions beets is enabled if
|
||||
<option>programs.beets.settings</option> is non-empty.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
@@ -22,10 +39,10 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.settings != {}) {
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.beets ];
|
||||
|
||||
home.file.".config/beets/config.yaml".text =
|
||||
xdg.configFile."beets/config.yaml".text =
|
||||
builtins.toJSON config.programs.beets.settings;
|
||||
};
|
||||
}
|
||||
|
||||
80
modules/programs/browserpass.nix
Normal file
80
modules/programs/browserpass.nix
Normal file
@@ -0,0 +1,80 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
browsers = [
|
||||
"chrome"
|
||||
"chromium"
|
||||
"firefox"
|
||||
"vivaldi"
|
||||
];
|
||||
in {
|
||||
options = {
|
||||
programs.browserpass = {
|
||||
enable = mkEnableOption "the browserpass extension host application";
|
||||
|
||||
browsers = mkOption {
|
||||
type = types.listOf (types.enum browsers);
|
||||
default = browsers;
|
||||
example = [ "firefox" ];
|
||||
description = "Which browsers to install browserpass for";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf config.programs.browserpass.enable {
|
||||
home.file = builtins.concatLists (with pkgs.stdenv; map (x:
|
||||
if x == "chrome" then
|
||||
let dir = if isDarwin
|
||||
then "Library/Application Support/Google/Chrome/NativeMessagingHosts"
|
||||
else ".config/google-chrome/NativeMessagingHosts";
|
||||
in [
|
||||
{
|
||||
target = "${dir}/com.github.browserpass.native.json";
|
||||
source = "${pkgs.browserpass}/etc/chrome-host.json";
|
||||
}
|
||||
{
|
||||
target = "${dir}/../policies/managed/com.github.browserpass.native.json";
|
||||
source = "${pkgs.browserpass}/etc/chrome-policy.json";
|
||||
}
|
||||
]
|
||||
else if x == "chromium" then
|
||||
let dir = if isDarwin
|
||||
then "Library/Application Support/Chromium/NativeMessagingHosts"
|
||||
else ".config/chromium/NativeMessagingHosts";
|
||||
in [
|
||||
{
|
||||
target = "${dir}/com.github.browserpass.native.json";
|
||||
source = "${pkgs.browserpass}/etc/chrome-host.json";
|
||||
}
|
||||
{
|
||||
target = "${dir}/../policies/managed/com.github.browserpass.native.json";
|
||||
source = "${pkgs.browserpass}/etc/chrome-policy.json";
|
||||
}
|
||||
]
|
||||
else if x == "firefox" then
|
||||
[ {
|
||||
target = (if isDarwin
|
||||
then "Library/Application Support/Mozilla/NativeMessagingHosts"
|
||||
else ".mozilla/native-messaging-hosts")
|
||||
+ "/com.github.browserpass.native.json";
|
||||
source = "${pkgs.browserpass}/lib/mozilla/native-messaging-hosts/com.github.browserpass.native.json";
|
||||
} ]
|
||||
else if x == "vivaldi" then
|
||||
let dir = if isDarwin
|
||||
then "Library/Application Support/Vivaldi/NativeMessagingHosts"
|
||||
else ".config/vivaldi/NativeMessagingHosts";
|
||||
in [
|
||||
{
|
||||
target = "${dir}/com.github.browserpass.native.json";
|
||||
source = "${pkgs.browserpass}/etc/chrome-host.json";
|
||||
}
|
||||
{
|
||||
target = "${dir}/../policies/managed/com.github.browserpass.native.json";
|
||||
source = "${pkgs.browserpass}/etc/chrome-policy.json";
|
||||
}
|
||||
]
|
||||
else throw "unknown browser ${x}") config.programs.browserpass.browsers);
|
||||
};
|
||||
}
|
||||
93
modules/programs/chromium.nix
Normal file
93
modules/programs/chromium.nix
Normal file
@@ -0,0 +1,93 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
browserModule = defaultPkg: name: visible:
|
||||
let
|
||||
browser = (builtins.parseDrvName defaultPkg.name).name;
|
||||
in
|
||||
{
|
||||
enable = mkOption {
|
||||
inherit visible;
|
||||
default = false;
|
||||
example = true;
|
||||
description = "Whether to enable ${name}.";
|
||||
type = lib.types.bool;
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
inherit visible;
|
||||
type = types.package;
|
||||
default = defaultPkg;
|
||||
defaultText = "pkgs.${browser}";
|
||||
description = "The ${name} package to use.";
|
||||
};
|
||||
|
||||
extensions = mkOption {
|
||||
inherit visible;
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = literalExample ''
|
||||
[
|
||||
"chlffgpmiacpedhhbkiomidkjlcfhogd" # pushbullet
|
||||
"mbniclmhobmnbdlbpiphghaielnnpgdp" # lightshot
|
||||
"gcbommkclmclpchllfjekcdonpmejbdp" # https everywhere
|
||||
"cjpalhdlnbpafiamejdnhcphjbkeiagm" # ublock origin
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
List of ${name} extensions to install.
|
||||
To find the extension ID, check its URL on the
|
||||
<link xlink:href="https://chrome.google.com/webstore/category/extensions">Chrome Web Store</link>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
browserConfig = cfg:
|
||||
let
|
||||
|
||||
browser = (builtins.parseDrvName cfg.package.name).name;
|
||||
|
||||
darwinDirs = {
|
||||
chromium = "Chromium";
|
||||
google-chrome = "Google/Chrome";
|
||||
google-chrome-beta = "Google/Chrome Beta";
|
||||
google-chrome-dev = "Google/Chrome Dev";
|
||||
};
|
||||
|
||||
configDir = if pkgs.stdenv.isDarwin
|
||||
then "Library/Application Support/${getAttr browser darwinDirs}"
|
||||
else "${config.xdg.configHome}/${browser}";
|
||||
|
||||
extensionJson = ext: {
|
||||
target = "${configDir}/External Extensions/${ext}.json";
|
||||
text = builtins.toJSON {
|
||||
external_update_url = "https://clients2.google.com/service/update2/crx";
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
mkIf cfg.enable {
|
||||
home.packages = [ cfg.package ];
|
||||
home.file = map extensionJson cfg.extensions;
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.programs = {
|
||||
chromium = browserModule pkgs.chromium "Chromium" true;
|
||||
google-chrome = browserModule pkgs.google-chrome "Google Chrome" false;
|
||||
google-chrome-beta = browserModule pkgs.google-chrome-beta "Google Chrome Beta" false;
|
||||
google-chrome-dev = browserModule pkgs.google-chrome-dev "Google Chrome Dev" false;
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
(browserConfig config.programs.chromium)
|
||||
(browserConfig config.programs.google-chrome)
|
||||
(browserConfig config.programs.google-chrome-beta)
|
||||
(browserConfig config.programs.google-chrome-dev)
|
||||
];
|
||||
}
|
||||
57
modules/programs/command-not-found/command-not-found.nix
Normal file
57
modules/programs/command-not-found/command-not-found.nix
Normal file
@@ -0,0 +1,57 @@
|
||||
# Adapted from Nixpkgs.
|
||||
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.programs.command-not-found;
|
||||
commandNotFound = pkgs.substituteAll {
|
||||
name = "command-not-found";
|
||||
dir = "bin";
|
||||
src = ./command-not-found.pl;
|
||||
isExecutable = true;
|
||||
inherit (pkgs) perl;
|
||||
inherit (cfg) dbPath;
|
||||
perlFlags = concatStrings (map (path: "-I ${path}/lib/perl5/site_perl ")
|
||||
[ pkgs.perlPackages.DBI pkgs.perlPackages.DBDSQLite pkgs.perlPackages.StringShellQuote ]);
|
||||
};
|
||||
|
||||
shInit = commandNotFoundHandlerName: ''
|
||||
# This function is called whenever a command is not found.
|
||||
${commandNotFoundHandlerName}() {
|
||||
local p=${commandNotFound}/bin/command-not-found
|
||||
if [ -x $p -a -f ${cfg.dbPath} ]; then
|
||||
# Run the helper program.
|
||||
$p "$@"
|
||||
else
|
||||
echo "$1: command not found" >&2
|
||||
return 127
|
||||
fi
|
||||
}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.programs.command-not-found = {
|
||||
enable = mkEnableOption "command-not-found hook for interactive shell";
|
||||
|
||||
dbPath = mkOption {
|
||||
default = "/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite" ;
|
||||
description = ''
|
||||
Absolute path to <filename>programs.sqlite</filename>. By
|
||||
default this file will be provided by your channel
|
||||
(nixexprs.tar.xz).
|
||||
'';
|
||||
type = types.path;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
programs.bash.initExtra = shInit "command_not_found_handle";
|
||||
programs.zsh.initExtra = shInit "command_not_found_handler";
|
||||
|
||||
home.packages = [ commandNotFound ];
|
||||
};
|
||||
}
|
||||
44
modules/programs/command-not-found/command-not-found.pl
Normal file
44
modules/programs/command-not-found/command-not-found.pl
Normal file
@@ -0,0 +1,44 @@
|
||||
#! @perl@/bin/perl -w @perlFlags@
|
||||
|
||||
use strict;
|
||||
use DBI;
|
||||
use DBD::SQLite;
|
||||
use String::ShellQuote;
|
||||
use Config;
|
||||
|
||||
my $program = $ARGV[0];
|
||||
|
||||
my $dbPath = "@dbPath@";
|
||||
|
||||
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
|
||||
or die "cannot open database `$dbPath'";
|
||||
$dbh->{RaiseError} = 0;
|
||||
$dbh->{PrintError} = 0;
|
||||
|
||||
my $system = $ENV{"NIX_SYSTEM"} // $Config{myarchname};
|
||||
|
||||
my $res = $dbh->selectall_arrayref(
|
||||
"select package from Programs where system = ? and name = ?",
|
||||
{ Slice => {} }, $system, $program);
|
||||
|
||||
if (!defined $res || scalar @$res == 0) {
|
||||
print STDERR "$program: command not found\n";
|
||||
} elsif (scalar @$res == 1) {
|
||||
my $package = @$res[0]->{package};
|
||||
if ($ENV{"NIX_AUTO_RUN"} // "") {
|
||||
exec("nix-shell", "-p", $package, "--run", shell_quote("exec", @ARGV));
|
||||
} else {
|
||||
print STDERR <<EOF;
|
||||
The program ‘$program’ is currently not installed. You can install it by typing:
|
||||
nix-env -iA nixos.$package
|
||||
EOF
|
||||
}
|
||||
} else {
|
||||
print STDERR <<EOF;
|
||||
The program ‘$program’ is currently not installed. It is provided by
|
||||
several packages. You can install it by typing one of the following:
|
||||
EOF
|
||||
print STDERR " nix-env -iA nixos.$_->{package}\n" foreach @$res;
|
||||
}
|
||||
|
||||
exit 127;
|
||||
107
modules/programs/direnv.nix
Normal file
107
modules/programs/direnv.nix
Normal file
@@ -0,0 +1,107 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.direnv;
|
||||
configFile = config:
|
||||
pkgs.runCommand "config.toml"
|
||||
{
|
||||
buildInputs = [ pkgs.remarshal ];
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
}
|
||||
''
|
||||
remarshal -if json -of toml \
|
||||
< ${pkgs.writeText "config.json" (builtins.toJSON config)} \
|
||||
> $out
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options.programs.direnv = {
|
||||
enable = mkEnableOption "direnv, the environment switcher";
|
||||
|
||||
config = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = ''
|
||||
Configuration written to
|
||||
<filename>~/.config/direnv/config.toml</filename>.
|
||||
</para><para>
|
||||
See
|
||||
<citerefentry>
|
||||
<refentrytitle>direnv.toml</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>.
|
||||
for the full list of options.
|
||||
'';
|
||||
};
|
||||
|
||||
stdlib = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Custom stdlib written to
|
||||
<filename>~/.config/direnv/direnvrc</filename>.
|
||||
'';
|
||||
};
|
||||
|
||||
enableBashIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Bash integration.
|
||||
'';
|
||||
};
|
||||
|
||||
enableZshIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Zsh integration.
|
||||
'';
|
||||
};
|
||||
|
||||
enableFishIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Fish integration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.direnv ];
|
||||
|
||||
xdg.configFile."direnv/config.toml" = mkIf (cfg.config != {}) {
|
||||
source = configFile cfg.config;
|
||||
};
|
||||
|
||||
xdg.configFile."direnv/direnvrc" = mkIf (cfg.stdlib != "") {
|
||||
text = cfg.stdlib;
|
||||
};
|
||||
|
||||
programs.bash.initExtra =
|
||||
mkIf cfg.enableBashIntegration (
|
||||
# Using mkAfter to make it more likely to appear after other
|
||||
# manipulations of the prompt.
|
||||
mkAfter ''
|
||||
eval "$(${pkgs.direnv}/bin/direnv hook bash)"
|
||||
''
|
||||
);
|
||||
|
||||
programs.zsh.initExtra = mkIf cfg.enableZshIntegration ''
|
||||
eval "$(${pkgs.direnv}/bin/direnv hook zsh)"
|
||||
'';
|
||||
|
||||
programs.fish.shellInit = mkIf cfg.enableFishIntegration ''
|
||||
eval (${pkgs.direnv}/bin/direnv hook fish)
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -9,10 +9,22 @@ let
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.eclipse = {
|
||||
enable = mkEnableOption "Eclipse";
|
||||
|
||||
enableLombok = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether to enable the Lombok Java Agent in Eclipse. This is
|
||||
necessary to use the Lombok class annotations.
|
||||
'';
|
||||
};
|
||||
|
||||
jvmArgs = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
@@ -31,7 +43,10 @@ in
|
||||
home.packages = [
|
||||
(pkgs.eclipses.eclipseWithPlugins {
|
||||
eclipse = pkgs.eclipses.eclipse-platform;
|
||||
jvmArgs = cfg.jvmArgs;
|
||||
jvmArgs =
|
||||
cfg.jvmArgs
|
||||
++ optional cfg.enableLombok
|
||||
"-javaagent:${pkgs.lombok}/share/java/lombok.jar";
|
||||
plugins = cfg.plugins;
|
||||
})
|
||||
];
|
||||
|
||||
@@ -6,24 +6,66 @@ let
|
||||
|
||||
cfg = config.programs.emacs;
|
||||
|
||||
# Copied from all-packages.nix, with modifications to support
|
||||
# overrides.
|
||||
emacsPackages =
|
||||
let
|
||||
epkgs = pkgs.emacsPackagesNgGen cfg.package;
|
||||
in
|
||||
epkgs.overrideScope' cfg.overrides;
|
||||
emacsWithPackages = emacsPackages.emacsWithPackages;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.emacs = {
|
||||
enable = mkEnableOption "Emacs";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.emacs;
|
||||
defaultText = "pkgs.emacs";
|
||||
example = literalExample "pkgs.emacs25-nox";
|
||||
description = "The Emacs package to use.";
|
||||
};
|
||||
|
||||
extraPackages = mkOption {
|
||||
default = self: [];
|
||||
example = literalExample ''
|
||||
epkgs: [ epkgs.emms epkgs.magit ]
|
||||
'';
|
||||
defaultText = "epkgs: []";
|
||||
example = literalExample "epkgs: [ epkgs.emms epkgs.magit ]";
|
||||
description = "Extra packages available to Emacs.";
|
||||
};
|
||||
|
||||
overrides = mkOption {
|
||||
default = self: super: {};
|
||||
defaultText = "self: super: {}";
|
||||
example = literalExample ''
|
||||
self: super: rec {
|
||||
haskell-mode = self.melpaPackages.haskell-mode;
|
||||
# ...
|
||||
};
|
||||
'';
|
||||
description = ''
|
||||
Allows overriding packages within the Emacs package set.
|
||||
'';
|
||||
};
|
||||
|
||||
finalPackage = mkOption {
|
||||
type = types.package;
|
||||
visible = false;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
The Emacs package including any overrides and extra packages.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ (pkgs.emacsWithPackages cfg.extraPackages) ];
|
||||
home.packages = [ cfg.finalPackage ];
|
||||
programs.emacs.finalPackage = emacsWithPackages cfg.extraPackages;
|
||||
};
|
||||
}
|
||||
|
||||
41
modules/programs/feh.nix
Normal file
41
modules/programs/feh.nix
Normal file
@@ -0,0 +1,41 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.feh;
|
||||
|
||||
disableBinding = func: key: func;
|
||||
enableBinding = func: key: "${func} ${key}";
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.programs.feh = {
|
||||
enable = mkEnableOption "feh - a fast and light image viewer";
|
||||
|
||||
keybindings = mkOption {
|
||||
default = {};
|
||||
type = types.attrs;
|
||||
example = { zoom_in = "plus"; zoom_out = "minus"; };
|
||||
description = ''
|
||||
Set keybindings.
|
||||
See <link xlink:href="https://man.finalrewind.org/1/feh/#x4b455953"/> for
|
||||
default bindings and available commands.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.feh ];
|
||||
|
||||
xdg.configFile."feh/keys".text = ''
|
||||
# Disable default keybindings
|
||||
${concatStringsSep "\n" (mapAttrsToList disableBinding cfg.keybindings)}
|
||||
|
||||
# Enable new keybindings
|
||||
${concatStringsSep "\n" (mapAttrsToList enableBinding cfg.keybindings)}
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -6,9 +6,13 @@ let
|
||||
|
||||
cfg = config.programs.firefox;
|
||||
|
||||
extensionPath = "extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.firefox = {
|
||||
enable = mkEnableOption "Firefox";
|
||||
@@ -20,6 +24,22 @@ in
|
||||
description = "The unwrapped Firefox package to use.";
|
||||
};
|
||||
|
||||
extensions = mkOption {
|
||||
type = types.listOf types.package;
|
||||
default = [];
|
||||
example = literalExample ''
|
||||
with pkgs.nur.repos.rycee.firefox-addons; [
|
||||
https-everywhere
|
||||
privacy-badger
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
List of Firefox add-on packages to install. Note, it is
|
||||
necessary to manually enable these extensions inside Firefox
|
||||
after the first installation.
|
||||
'';
|
||||
};
|
||||
|
||||
enableAdobeFlash = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -31,6 +51,12 @@ in
|
||||
default = false;
|
||||
description = "Whether to enable the unfree Google Talk plugin.";
|
||||
};
|
||||
|
||||
enableIcedTea = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to enable the Java applet plugin.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -44,6 +70,7 @@ in
|
||||
fcfg = setAttrByPath [browserName] {
|
||||
enableAdobeFlash = cfg.enableAdobeFlash;
|
||||
enableGoogleTalkPlugin = cfg.enableGoogleTalk;
|
||||
icedtea = cfg.enableIcedTea;
|
||||
};
|
||||
|
||||
wrapper = pkgs.wrapFirefox.override {
|
||||
@@ -51,5 +78,18 @@ in
|
||||
};
|
||||
in
|
||||
[ (wrapper cfg.package { }) ];
|
||||
|
||||
home.file.".mozilla/${extensionPath}" = mkIf (cfg.extensions != []) (
|
||||
let
|
||||
extensionsEnv = pkgs.buildEnv {
|
||||
name = "hm-firefox-extensions";
|
||||
paths = cfg.extensions;
|
||||
};
|
||||
in
|
||||
{
|
||||
source = "${extensionsEnv}/share/mozilla/${extensionPath}";
|
||||
recursive = true;
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
191
modules/programs/fish.nix
Normal file
191
modules/programs/fish.nix
Normal file
@@ -0,0 +1,191 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.fish;
|
||||
|
||||
abbrsStr = concatStringsSep "\n" (
|
||||
mapAttrsToList (k: v: "abbr --add ${k} '${v}'") cfg.shellAbbrs
|
||||
);
|
||||
|
||||
aliasesStr = concatStringsSep "\n" (
|
||||
mapAttrsToList (k: v: "alias ${k}='${v}'") cfg.shellAliases
|
||||
);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.fish = {
|
||||
enable = mkEnableOption "fish friendly interactive shell";
|
||||
|
||||
package = mkOption {
|
||||
default = pkgs.fish;
|
||||
defaultText = "pkgs.fish";
|
||||
description = ''
|
||||
The fish package to install. May be used to change the version.
|
||||
'';
|
||||
type = types.package;
|
||||
};
|
||||
|
||||
shellAliases = mkOption {
|
||||
default = {};
|
||||
description = ''
|
||||
Set of aliases for fish shell. See
|
||||
<option>environment.shellAliases</option> for an option
|
||||
format description.
|
||||
'';
|
||||
type = types.attrs;
|
||||
};
|
||||
|
||||
shellAbbrs = mkOption {
|
||||
default = {};
|
||||
description = ''
|
||||
Set of abbreviations for fish shell.
|
||||
'';
|
||||
type = types.attrs;
|
||||
};
|
||||
|
||||
shellInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code called during fish shell initialisation.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
|
||||
loginShellInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code called during fish login shell initialisation.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
|
||||
interactiveShellInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code called during interactive fish shell initialisation.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
|
||||
promptInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code used to initialise fish prompt.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
xdg.dataFile."fish/home-manager_generated_completions".source =
|
||||
let
|
||||
# paths later in the list will overwrite those already linked
|
||||
destructiveSymlinkJoin =
|
||||
args_@{ name
|
||||
, paths
|
||||
, preferLocalBuild ? true
|
||||
, allowSubstitutes ? false
|
||||
, postBuild ? ""
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
args = removeAttrs args_ [ "name" "postBuild" ]
|
||||
// { inherit preferLocalBuild allowSubstitutes; }; # pass the defaults
|
||||
in pkgs.runCommand name args
|
||||
''
|
||||
mkdir -p $out
|
||||
for i in $paths; do
|
||||
if [ -z "$(find $i -prune -empty)" ]; then
|
||||
cp -srf $i/* $out
|
||||
fi
|
||||
done
|
||||
${postBuild}
|
||||
'';
|
||||
generateCompletions = package: pkgs.runCommand
|
||||
"${package.name}-fish-completions"
|
||||
{
|
||||
src = package;
|
||||
nativeBuildInputs = [ pkgs.python2 ];
|
||||
buildInputs = [ cfg.package ];
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
}
|
||||
''
|
||||
mkdir -p $out
|
||||
if [ -d $src/share/man ]; then
|
||||
find $src/share/man -type f \
|
||||
| xargs python ${cfg.package}/share/fish/tools/create_manpage_completions.py --directory $out \
|
||||
> /dev/null
|
||||
fi
|
||||
'';
|
||||
in
|
||||
destructiveSymlinkJoin {
|
||||
name = "${config.home.username}-fish-completions";
|
||||
paths =
|
||||
let
|
||||
cmp = (a: b: (a.meta.priority or 0) > (b.meta.priority or 0));
|
||||
in
|
||||
map generateCompletions (sort cmp config.home.packages);
|
||||
};
|
||||
|
||||
programs.fish.interactiveShellInit = ''
|
||||
# add completions generated by Home Manager to $fish_complete_path
|
||||
begin
|
||||
set -l joined (string join " " $fish_complete_path)
|
||||
set -l prev_joined (string replace --regex "[^\s]*generated_completions.*" "" $joined)
|
||||
set -l post_joined (string replace $prev_joined "" $joined)
|
||||
set -l prev (string split " " (string trim $prev_joined))
|
||||
set -l post (string split " " (string trim $post_joined))
|
||||
set fish_complete_path $prev "${config.xdg.dataHome}/fish/home-manager_generated_completions" $post
|
||||
end
|
||||
'';
|
||||
|
||||
xdg.configFile."fish/config.fish".text = ''
|
||||
# ~/.config/fish/config.fish: DO NOT EDIT -- this file has been generated automatically.
|
||||
# if we haven't sourced the general config, do it
|
||||
if not set -q __fish_general_config_sourced
|
||||
set fish_function_path ${pkgs.fish-foreign-env}/share/fish-foreign-env/functions $fish_function_path
|
||||
fenv source ${config.home.profileDirectory}/etc/profile.d/hm-session-vars.sh > /dev/null
|
||||
set -e fish_function_path[1]
|
||||
|
||||
${cfg.shellInit}
|
||||
# and leave a note so we don't source this config section again from
|
||||
# this very shell (children will source the general config anew)
|
||||
set -g __fish_general_config_sourced 1
|
||||
end
|
||||
# if we haven't sourced the login config, do it
|
||||
status --is-login; and not set -q __fish_login_config_sourced
|
||||
and begin
|
||||
|
||||
${cfg.loginShellInit}
|
||||
# and leave a note so we don't source this config section again from
|
||||
# this very shell (children will source the general config anew)
|
||||
set -g __fish_login_config_sourced 1
|
||||
end
|
||||
# if we haven't sourced the interactive config, do it
|
||||
status --is-interactive; and not set -q __fish_interactive_config_sourced
|
||||
and begin
|
||||
# Abbrs
|
||||
${abbrsStr}
|
||||
|
||||
# Aliases
|
||||
${aliasesStr}
|
||||
|
||||
${cfg.promptInit}
|
||||
${cfg.interactiveShellInit}
|
||||
# and leave a note so we don't source this config section again from
|
||||
# this very shell (children will source the general config anew,
|
||||
# allowing configuration changes in, e.g, aliases, to propagate)
|
||||
set -g __fish_interactive_config_sourced 1
|
||||
end
|
||||
'';
|
||||
};
|
||||
}
|
||||
138
modules/programs/fzf.nix
Normal file
138
modules/programs/fzf.nix
Normal file
@@ -0,0 +1,138 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.fzf;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.programs.fzf = {
|
||||
enable = mkEnableOption "fzf - a command-line fuzzy finder";
|
||||
|
||||
defaultCommand = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "fd --type f";
|
||||
description = ''
|
||||
The command that gets executed as the default source for fzf
|
||||
when running.
|
||||
'';
|
||||
};
|
||||
|
||||
defaultOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "--height 40%" "--border" ];
|
||||
description = ''
|
||||
Extra command line options given to fzf by default.
|
||||
'';
|
||||
};
|
||||
|
||||
fileWidgetCommand = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "fd --type f";
|
||||
description = ''
|
||||
The command that gets executed as the source for fzf for the
|
||||
CTRL-T keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
fileWidgetOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "--preview 'head {}'" ];
|
||||
description = ''
|
||||
Command line options for the CTRL-T keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
changeDirWidgetCommand = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "fd --type d" ;
|
||||
description = ''
|
||||
The command that gets executed as the source for fzf for the
|
||||
ALT-C keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
changeDirWidgetOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "--preview 'tree -C {} | head -200'" ];
|
||||
description = ''
|
||||
Command line options for the ALT-C keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
historyWidgetCommand = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
The command that gets executed as the source for fzf for the
|
||||
CTRL-R keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
historyWidgetOptions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "--sort" "--exact" ];
|
||||
description = ''
|
||||
Command line options for the CTRL-R keybinding.
|
||||
'';
|
||||
};
|
||||
|
||||
enableBashIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Bash integration.
|
||||
'';
|
||||
};
|
||||
|
||||
enableZshIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Zsh integration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.fzf ];
|
||||
|
||||
home.sessionVariables =
|
||||
mapAttrs (n: v: toString v) (
|
||||
filterAttrs (n: v: v != [] && v != null) {
|
||||
FZF_ALT_C_COMMAND = cfg.changeDirWidgetCommand;
|
||||
FZF_ALT_C_OPTS = cfg.changeDirWidgetOptions;
|
||||
FZF_CTRL_R_COMMAND = cfg.historyWidgetCommand;
|
||||
FZF_CTRL_R_OPTS = cfg.historyWidgetOptions;
|
||||
FZF_CTRL_T_COMMAND = cfg.fileWidgetCommand;
|
||||
FZF_CTRL_T_OPTS = cfg.fileWidgetOptions;
|
||||
FZF_DEFAULT_COMMAND = cfg.defaultCommand;
|
||||
FZF_DEFAULT_OPTS = cfg.defaultOptions;
|
||||
}
|
||||
);
|
||||
|
||||
programs.bash.initExtra = mkIf cfg.enableBashIntegration ''
|
||||
if [[ :$SHELLOPTS: =~ :(vi|emacs): ]]; then
|
||||
. ${pkgs.fzf}/share/fzf/completion.bash
|
||||
. ${pkgs.fzf}/share/fzf/key-bindings.bash
|
||||
fi
|
||||
'';
|
||||
|
||||
programs.zsh.initExtra = mkIf cfg.enableZshIntegration ''
|
||||
if [[ $options[zle] = on ]]; then
|
||||
. ${pkgs.fzf}/share/fzf/completion.zsh
|
||||
. ${pkgs.fzf}/share/fzf/key-bindings.zsh
|
||||
fi
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -6,35 +6,73 @@ let
|
||||
|
||||
cfg = config.programs.git;
|
||||
|
||||
toINI = (import ../lib/generators.nix).toINI {};
|
||||
gitIniType = with types;
|
||||
let
|
||||
primitiveType = either bool (either int str);
|
||||
in
|
||||
attrsOf (attrsOf primitiveType);
|
||||
|
||||
signModule = types.submodule (
|
||||
{ ... }: {
|
||||
options = {
|
||||
key = mkOption {
|
||||
type = types.str;
|
||||
description = "The default GPG signing key fingerprint.";
|
||||
};
|
||||
|
||||
signByDefault = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether commits should be signed by default.";
|
||||
};
|
||||
|
||||
gpgPath = mkOption {
|
||||
type = types.str;
|
||||
default = "${pkgs.gnupg}/bin/gpg2";
|
||||
defaultText = "\${pkgs.gnupg}/bin/gpg2";
|
||||
description = "Path to GnuPG binary to use.";
|
||||
};
|
||||
signModule = types.submodule {
|
||||
options = {
|
||||
key = mkOption {
|
||||
type = types.str;
|
||||
description = "The default GPG signing key fingerprint.";
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
signByDefault = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether commits should be signed by default.";
|
||||
};
|
||||
|
||||
gpgPath = mkOption {
|
||||
type = types.str;
|
||||
default = "${pkgs.gnupg}/bin/gpg2";
|
||||
defaultText = "\${pkgs.gnupg}/bin/gpg2";
|
||||
description = "Path to GnuPG binary to use.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
includeModule = types.submodule ({ config, ... }: {
|
||||
options = {
|
||||
condition = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Include this configuration only when <varname>condition</varname>
|
||||
matches. Allowed conditions are described in
|
||||
<citerefentry>
|
||||
<refentrytitle>git-config</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>.
|
||||
'';
|
||||
};
|
||||
|
||||
path = mkOption {
|
||||
type = with types; either str path;
|
||||
description = "Path of the configuration file to include.";
|
||||
};
|
||||
|
||||
contents = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = ''
|
||||
Configuration to include. If empty then a path must be given.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config.path = mkIf (config.contents != {}) (
|
||||
mkDefault (pkgs.writeText "contents" (generators.toINI {} config.contents))
|
||||
);
|
||||
});
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.git = {
|
||||
enable = mkEnableOption "Git";
|
||||
@@ -43,22 +81,28 @@ in
|
||||
type = types.package;
|
||||
default = pkgs.git;
|
||||
defaultText = "pkgs.git";
|
||||
description = "Git package to install.";
|
||||
description = ''
|
||||
Git package to install. Use <varname>pkgs.gitAndTools.gitFull</varname>
|
||||
to gain access to <command>git send-email</command> for instance.
|
||||
'';
|
||||
};
|
||||
|
||||
userName = mkOption {
|
||||
type = types.str;
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Default user name to use.";
|
||||
};
|
||||
|
||||
userEmail = mkOption {
|
||||
type = types.str;
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Default user email to use.";
|
||||
};
|
||||
|
||||
aliases = mkOption {
|
||||
type = types.attrs;
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
example = { co = "checkout"; };
|
||||
description = "Git aliases to define.";
|
||||
};
|
||||
|
||||
@@ -69,33 +113,144 @@ in
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
type = types.either types.lines gitIniType;
|
||||
default = {};
|
||||
example = {
|
||||
core = { whitespace = "trailing-space,space-before-tab"; };
|
||||
};
|
||||
description = "Additional configuration to add.";
|
||||
};
|
||||
|
||||
iniContent = mkOption {
|
||||
type = gitIniType;
|
||||
internal = true;
|
||||
};
|
||||
|
||||
ignores = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "*~" "*.swp" ];
|
||||
description = "List of paths that should be globally ignored.";
|
||||
};
|
||||
|
||||
includes = mkOption {
|
||||
type = types.listOf includeModule;
|
||||
default = [];
|
||||
example = literalExample ''
|
||||
[
|
||||
{ path = "~/path/to/config.inc"; }
|
||||
{
|
||||
path = "~/path/to/conditional.inc";
|
||||
condition = "gitdir:~/src/dir";
|
||||
}
|
||||
]
|
||||
'';
|
||||
description = "List of configuration files to include.";
|
||||
};
|
||||
|
||||
lfs = {
|
||||
enable = mkEnableOption "Git Large File Storage";
|
||||
|
||||
skipSmudge = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Skip automatic downloading of objects on clone or pull.
|
||||
This requires a manual <command>git lfs pull</command>
|
||||
every time a new commit is checked out on your repository.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
let
|
||||
ini = {
|
||||
user = {
|
||||
name = cfg.userName;
|
||||
email = cfg.userEmail;
|
||||
} // optionalAttrs (cfg.signing != null) {
|
||||
signingKey = cfg.signing.key;
|
||||
};
|
||||
} // optionalAttrs (cfg.signing != null) {
|
||||
commit.gpgSign = cfg.signing.signByDefault;
|
||||
gpg.program = cfg.signing.gpgPath;
|
||||
} // optionalAttrs (cfg.aliases != {}) {
|
||||
alias = cfg.aliases;
|
||||
};
|
||||
in
|
||||
mkMerge [
|
||||
{
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
home.file.".gitconfig".text = toINI ini + "\n" + cfg.extraConfig;
|
||||
programs.git.iniContent.user = {
|
||||
name = mkIf (cfg.userName != null) cfg.userName;
|
||||
email = mkIf (cfg.userEmail != null) cfg.userEmail;
|
||||
};
|
||||
|
||||
xdg.configFile = {
|
||||
"git/config".text = generators.toINI {} cfg.iniContent;
|
||||
|
||||
"git/ignore" = mkIf (cfg.ignores != []) {
|
||||
text = concatStringsSep "\n" cfg.ignores + "\n";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
programs.git.iniContent =
|
||||
let
|
||||
hasSmtp = name: account: account.smtp != null;
|
||||
|
||||
genIdentity = name: account: with account;
|
||||
nameValuePair "sendemail \"${name}\"" ({
|
||||
smtpEncryption = if smtp.tls.enable then "tls" else "";
|
||||
smtpServer = smtp.host;
|
||||
smtpUser = userName;
|
||||
from = address;
|
||||
}
|
||||
// optionalAttrs (smtp.port != null) {
|
||||
smtpServerPort = smtp.port;
|
||||
});
|
||||
in
|
||||
mapAttrs' genIdentity
|
||||
(filterAttrs hasSmtp config.accounts.email.accounts);
|
||||
}
|
||||
|
||||
(mkIf (cfg.signing != null) {
|
||||
programs.git.iniContent = {
|
||||
user.signingKey = cfg.signing.key;
|
||||
commit.gpgSign = cfg.signing.signByDefault;
|
||||
gpg.program = cfg.signing.gpgPath;
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf (cfg.aliases != {}) {
|
||||
programs.git.iniContent.alias = cfg.aliases;
|
||||
})
|
||||
|
||||
(mkIf (lib.isAttrs cfg.extraConfig) {
|
||||
programs.git.iniContent = cfg.extraConfig;
|
||||
})
|
||||
|
||||
(mkIf (lib.isString cfg.extraConfig) {
|
||||
xdg.configFile."git/config".text = cfg.extraConfig;
|
||||
})
|
||||
|
||||
(mkIf (cfg.includes != []) {
|
||||
xdg.configFile."git/config".text = mkAfter
|
||||
(concatMapStringsSep "\n"
|
||||
(i: with i; ''
|
||||
[${if (condition == null) then "include" else "includeIf \"${condition}\""}]
|
||||
path = ${path}
|
||||
'')
|
||||
cfg.includes);
|
||||
})
|
||||
|
||||
(mkIf cfg.lfs.enable {
|
||||
home.packages = [ pkgs.git-lfs ];
|
||||
|
||||
programs.git.iniContent."filter \"lfs\"" =
|
||||
let
|
||||
skipArg = optional cfg.lfs.skipSmudge "--skip";
|
||||
in
|
||||
{
|
||||
clean = "git-lfs clean -- %f";
|
||||
process = concatStringsSep " " (
|
||||
[ "git-lfs" "filter-process" ] ++ skipArg
|
||||
);
|
||||
required = true;
|
||||
smudge = concatStringsSep " " (
|
||||
[ "git-lfs" "smudge" ] ++ skipArg ++ [ "--" "%f" ]
|
||||
);
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
with import ../lib/dag.nix;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.gnome-terminal;
|
||||
|
||||
vteInitStr = ''
|
||||
# gnome-terminal: Show current directory in the terminal window title.
|
||||
. ${pkgs.gnome3.vte}/etc/profile.d/vte.sh
|
||||
'';
|
||||
|
||||
profileColorsSubModule = types.submodule (
|
||||
{ ... }: {
|
||||
options = {
|
||||
@@ -90,19 +94,6 @@ let
|
||||
}
|
||||
);
|
||||
|
||||
toINI = (import ../lib/generators.nix).toINI { mkKeyValue = mkIniKeyValue; };
|
||||
|
||||
mkIniKeyValue = key: value:
|
||||
let
|
||||
tweakVal = v:
|
||||
if isString v then "'${v}'"
|
||||
else if isList v then "[" + concatStringsSep "," (map tweakVal v) + "]"
|
||||
else if isBool v && v then "true"
|
||||
else if isBool v && !v then "false"
|
||||
else toString v;
|
||||
in
|
||||
"${key}=${tweakVal value}";
|
||||
|
||||
buildProfileSet = pcfg:
|
||||
{
|
||||
visible-name = pcfg.visibleName;
|
||||
@@ -135,28 +126,11 @@ let
|
||||
)
|
||||
);
|
||||
|
||||
buildIniSet = cfg:
|
||||
{
|
||||
"/" = {
|
||||
default-show-menubar = cfg.showMenubar;
|
||||
schema-version = 3;
|
||||
};
|
||||
}
|
||||
//
|
||||
{
|
||||
"profiles:" = {
|
||||
default = head (attrNames (filterAttrs (n: v: v.default) cfg.profile));
|
||||
list = attrNames cfg.profile; #mapAttrsToList (n: v: n) cfg.profile;
|
||||
};
|
||||
}
|
||||
//
|
||||
mapAttrs' (name: value:
|
||||
nameValuePair ("profiles:/:${name}") (buildProfileSet value)
|
||||
) cfg.profile;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.gnome-terminal = {
|
||||
enable = mkEnableOption "Gnome Terminal";
|
||||
@@ -178,19 +152,26 @@ in
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.gnome3.gnome_terminal ];
|
||||
|
||||
# The dconf service needs to be installed and prepared.
|
||||
home.activation.gnomeTerminal = dagEntryAfter ["installPackages"] (
|
||||
dconf.settings =
|
||||
let
|
||||
sf = pkgs.writeText "gnome-terminal.ini" (toINI (buildIniSet cfg));
|
||||
dconfPath = "/org/gnome/terminal/legacy/";
|
||||
dconfPath = "org/gnome/terminal/legacy";
|
||||
in
|
||||
''
|
||||
if [[ -v DRY_RUN ]]; then
|
||||
echo ${pkgs.gnome3.dconf}/bin/dconf load ${dconfPath} "<" ${sf}
|
||||
else
|
||||
${pkgs.gnome3.dconf}/bin/dconf load ${dconfPath} < ${sf}
|
||||
fi
|
||||
''
|
||||
);
|
||||
{
|
||||
"${dconfPath}" = {
|
||||
default-show-menubar = cfg.showMenubar;
|
||||
schema-version = 3;
|
||||
};
|
||||
|
||||
"${dconfPath}/profiles:" = {
|
||||
default = head (attrNames (filterAttrs (n: v: v.default) cfg.profile));
|
||||
list = attrNames cfg.profile;
|
||||
};
|
||||
}
|
||||
// mapAttrs' (n: v:
|
||||
nameValuePair ("${dconfPath}/profiles:/:${n}") (buildProfileSet v)
|
||||
) cfg.profile;
|
||||
|
||||
programs.bash.initExtra = mkBefore vteInitStr;
|
||||
programs.zsh.initExtra = vteInitStr;
|
||||
};
|
||||
}
|
||||
|
||||
75
modules/programs/go.nix
Normal file
75
modules/programs/go.nix
Normal file
@@ -0,0 +1,75 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.go;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rvolosatovs ];
|
||||
|
||||
options = {
|
||||
programs.go = {
|
||||
enable = mkEnableOption "Go";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.go;
|
||||
defaultText = "pkgs.go";
|
||||
description = "The Go package to use.";
|
||||
};
|
||||
|
||||
packages = mkOption {
|
||||
type = with types; attrsOf path;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
"golang.org/x/text" = builtins.fetchGit "https://go.googlesource.com/text";
|
||||
"golang.org/x/time" = builtins.fetchGit "https://go.googlesource.com/time";
|
||||
}
|
||||
'';
|
||||
description = "Packages to add to GOPATH.";
|
||||
};
|
||||
|
||||
goPath = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
example = "go";
|
||||
description = "GOPATH relative to HOME";
|
||||
};
|
||||
|
||||
goBin = mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
example = ".local/bin.go";
|
||||
description = "GOBIN relative to HOME";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (mkMerge [
|
||||
{
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
home.file =
|
||||
let
|
||||
goPath = if cfg.goPath != null then cfg.goPath else "go";
|
||||
|
||||
mkSrc = n: v: {
|
||||
target = "${goPath}/src/${n}";
|
||||
source = v;
|
||||
};
|
||||
in
|
||||
mapAttrsToList mkSrc cfg.packages;
|
||||
}
|
||||
(mkIf (cfg.goPath != null) {
|
||||
home.sessionVariables.GOPATH = builtins.toPath "${config.home.homeDirectory}/${cfg.goPath}";
|
||||
})
|
||||
(mkIf (cfg.goBin != null) {
|
||||
home.sessionVariables.GOBIN = builtins.toPath "${config.home.homeDirectory}/${cfg.goBin}";
|
||||
})
|
||||
]);
|
||||
}
|
||||
43
modules/programs/home-manager.nix
Normal file
43
modules/programs/home-manager.nix
Normal file
@@ -0,0 +1,43 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.home-manager;
|
||||
|
||||
dag = config.lib.dag;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.home-manager = {
|
||||
enable = mkEnableOption "Home Manager";
|
||||
|
||||
path = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = "$HOME/devel/home-manager";
|
||||
description = ''
|
||||
The default path to use for Home Manager. If this path does
|
||||
not exist then
|
||||
<filename>$HOME/.config/nixpkgs/home-manager</filename> and
|
||||
<filename>$HOME/.nixpkgs/home-manager</filename> will be
|
||||
attempted.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf (cfg.enable && !config.submoduleSupport.enable) {
|
||||
home.packages = [
|
||||
(import ../../home-manager {
|
||||
inherit pkgs;
|
||||
inherit (cfg) path;
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
327
modules/programs/htop.nix
Normal file
327
modules/programs/htop.nix
Normal file
@@ -0,0 +1,327 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.programs.htop;
|
||||
|
||||
list = xs: concatMapStrings (x: "${toString x} ") xs;
|
||||
|
||||
bool = b: if b then "1" else "0";
|
||||
|
||||
fields = {
|
||||
PID = 0;
|
||||
COMM = 1;
|
||||
STATE = 2;
|
||||
PPID = 3;
|
||||
PGRP = 4;
|
||||
SESSION = 5;
|
||||
TTY_NR = 6;
|
||||
TPGID = 7;
|
||||
MINFLT = 9;
|
||||
MAJFLT = 11;
|
||||
PRIORITY = 17;
|
||||
NICE = 18;
|
||||
STARTTIME = 20;
|
||||
PROCESSOR = 37;
|
||||
M_SIZE = 38;
|
||||
M_RESIDENT = 39;
|
||||
ST_UID = 45;
|
||||
PERCENT_CPU = 46;
|
||||
PERCENT_MEM = 47;
|
||||
USER = 48;
|
||||
TIME = 49;
|
||||
NLWP = 50;
|
||||
TGID = 51;
|
||||
CMINFLT = 10;
|
||||
CMAJFLT = 12;
|
||||
UTIME = 13;
|
||||
STIME = 14;
|
||||
CUTIME = 15;
|
||||
CSTIME = 16;
|
||||
M_SHARE = 40;
|
||||
M_TRS = 41;
|
||||
M_DRS = 42;
|
||||
M_LRS = 43;
|
||||
M_DT = 44;
|
||||
CTID = 99;
|
||||
VPID = 100;
|
||||
VXID = 102;
|
||||
RCHAR = 102;
|
||||
WCHAR = 103;
|
||||
SYSCR = 104;
|
||||
SYSCW = 105;
|
||||
RBYTES = 106;
|
||||
WBYTES = 107;
|
||||
CNCLWB = 108;
|
||||
IO_READ_RATE = 109;
|
||||
IO_WRITE_RATE = 110;
|
||||
IO_RATE = 111;
|
||||
CGROUP = 112;
|
||||
OOM = 113;
|
||||
IO_PRIORITY = 114;
|
||||
};
|
||||
|
||||
# Mapping from names to defaults
|
||||
meters = {
|
||||
Clock = 2;
|
||||
LoadAverage = 2;
|
||||
Load = 2;
|
||||
Memory = 1;
|
||||
Swap = 1;
|
||||
Tasks = 2;
|
||||
Uptime = 2;
|
||||
Battery = 2;
|
||||
Hostname = 2;
|
||||
AllCPUs = 1;
|
||||
AllCPUs2 = 1;
|
||||
LeftCPUs = 1;
|
||||
RightCPUs = 1;
|
||||
LeftCPUs2 = 1;
|
||||
RightCPUs2 = 1;
|
||||
Blank = 2;
|
||||
CPU = 1;
|
||||
"CPU(1)"= 1;
|
||||
"CPU(2)" = 1;
|
||||
"CPU(3)" = 1;
|
||||
"CPU(4)" = 1;
|
||||
};
|
||||
|
||||
singleMeterType = types.coercedTo
|
||||
(types.enum (attrNames meters))
|
||||
(m: { kind = m; mode = meters.${m}; })
|
||||
(types.submodule {
|
||||
options = {
|
||||
kind = mkOption {
|
||||
type = types.enum (attrNames meters);
|
||||
example = "AllCPUs";
|
||||
description = "What kind of meter.";
|
||||
};
|
||||
|
||||
mode = mkOption {
|
||||
type = types.enum [ 1 2 3 4 ];
|
||||
example = 2;
|
||||
description = "Which mode the meter should use, one of 1(Bar) 2(Text) 3(Graph) 4(LED).";
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
meterType = types.submodule {
|
||||
options = {
|
||||
left = mkOption {
|
||||
description = "Meters shown in the left header.";
|
||||
default = [ "AllCPUs" "Memory" "Swap" ];
|
||||
example = [
|
||||
"Memory"
|
||||
"LeftCPUs2"
|
||||
"RightCPUs2"
|
||||
{ kind = "CPU"; mode = 3; }
|
||||
];
|
||||
type = types.listOf singleMeterType;
|
||||
};
|
||||
right = mkOption {
|
||||
description = "Meters shown in the right header.";
|
||||
default = [ "Tasks" "LoadAverage" "Uptime" ];
|
||||
example = [
|
||||
{ kind = "Clock"; mode = 4; }
|
||||
"Uptime"
|
||||
"Tasks"
|
||||
];
|
||||
type = types.listOf singleMeterType;
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options.programs.htop = {
|
||||
enable = mkEnableOption "htop";
|
||||
|
||||
fields = mkOption {
|
||||
type = types.listOf (types.enum (attrNames fields));
|
||||
default = [ "PID" "USER" "PRIORITY" "NICE" "M_SIZE" "M_RESIDENT" "M_SHARE" "STATE" "PERCENT_CPU" "PERCENT_MEM" "TIME" "COMM" ];
|
||||
example = [ "PID" "USER" "PRIORITY" "PERCENT_CPU" "M_RESIDENT" "PERCENT_MEM" "TIME" "COMM" ];
|
||||
description = "Active fields shown in the table.";
|
||||
};
|
||||
|
||||
sortKey = mkOption {
|
||||
type = types.enum (attrNames fields);
|
||||
default = "PERCENT_CPU";
|
||||
example = "TIME";
|
||||
description = "Which field to use for sorting.";
|
||||
};
|
||||
|
||||
sortDescending = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether to sort descending or not.";
|
||||
};
|
||||
|
||||
hideThreads = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Hide threads.";
|
||||
};
|
||||
|
||||
hideKernelThreads = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Hide kernel threads.";
|
||||
};
|
||||
|
||||
hideUserlandThreads = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Hide userland process threads.";
|
||||
};
|
||||
|
||||
shadowOtherUsers = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Shadow other users' processes.";
|
||||
};
|
||||
|
||||
showThreadNames = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Show custom thread names.";
|
||||
};
|
||||
|
||||
showProgramPath = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Show program path.";
|
||||
};
|
||||
|
||||
highlightBaseName = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Highlight program <quote>basename</quote>.";
|
||||
};
|
||||
|
||||
highlightMegabytes = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Highlight large numbers in memory counters.";
|
||||
};
|
||||
|
||||
highlightThreads = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Display threads in a different color.";
|
||||
};
|
||||
|
||||
treeView = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Tree view.";
|
||||
};
|
||||
|
||||
headerMargin = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Leave a margin around header.";
|
||||
};
|
||||
|
||||
detailedCpuTime = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Detailed CPU time (System/IO-Wait/Hard-IRQ/Soft-IRQ/Steal/Guest).";
|
||||
};
|
||||
|
||||
cpuCountFromZero = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Count CPUs from 0 instead of 1.";
|
||||
};
|
||||
|
||||
updateProcessNames = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Update process names on every refresh.";
|
||||
};
|
||||
|
||||
accountGuestInCpuMeter = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Add guest time in CPU meter percentage.";
|
||||
};
|
||||
|
||||
colorScheme = mkOption {
|
||||
type = types.enum [ 0 1 2 3 4 5 6 ];
|
||||
default = 0;
|
||||
example = 6;
|
||||
description = "Which color scheme to use.";
|
||||
};
|
||||
|
||||
delay = mkOption {
|
||||
type = types.int;
|
||||
default = 15;
|
||||
example = 2;
|
||||
description = "Set the delay between updates, in tenths of seconds.";
|
||||
};
|
||||
|
||||
meters = mkOption {
|
||||
description = "Meters shown in the header.";
|
||||
default = {
|
||||
left = [ "AllCPUs" "Memory" "Swap" ];
|
||||
right = [ "Tasks" "LoadAverage" "Uptime" ];
|
||||
};
|
||||
example = {
|
||||
left = [
|
||||
"Memory"
|
||||
"CPU"
|
||||
"LeftCPUs2"
|
||||
"RightCPUs2"
|
||||
{ kind = "CPU"; mode = 3; }
|
||||
];
|
||||
right = [
|
||||
{ kind = "Clock"; mode = 4; }
|
||||
"Uptime"
|
||||
"Tasks"
|
||||
"LoadAverage"
|
||||
{ kind = "Battery"; mode = 1; }
|
||||
];
|
||||
};
|
||||
type = meterType;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.htop ];
|
||||
|
||||
xdg.configFile."htop/htoprc".text = let
|
||||
leftMeters = map (m: m.kind) cfg.meters.left;
|
||||
leftModes = map (m: m.mode) cfg.meters.left;
|
||||
rightMeters = map (m: m.kind) cfg.meters.right;
|
||||
rightModes = map (m: m.mode) cfg.meters.right;
|
||||
in ''
|
||||
# This file is regenerated by home-manager
|
||||
# when options are changed in the config
|
||||
fields=${list (map (n: fields.${n}) cfg.fields)}
|
||||
sort_key=${toString (fields.${cfg.sortKey})}
|
||||
sort_direction=${bool cfg.sortDescending}
|
||||
hide_threads=${bool cfg.hideThreads}
|
||||
hide_kernel_threads=${bool cfg.hideKernelThreads}
|
||||
hide_userland_threads=${bool cfg.hideUserlandThreads}
|
||||
shadow_other_users=${bool cfg.shadowOtherUsers}
|
||||
show_thread_names=${bool cfg.showThreadNames}
|
||||
show_program_path=${bool cfg.showProgramPath}
|
||||
highlight_base_name=${bool cfg.highlightBaseName}
|
||||
highlight_megabytes=${bool cfg.highlightMegabytes}
|
||||
highlight_threads=${bool cfg.highlightThreads}
|
||||
tree_view=${bool cfg.treeView}
|
||||
header_margin=${bool cfg.headerMargin}
|
||||
detailed_cpu_time=${bool cfg.detailedCpuTime}
|
||||
cpu_count_from_zero=${bool cfg.cpuCountFromZero}
|
||||
update_process_names=${bool cfg.updateProcessNames}
|
||||
account_guest_in_cpu_meter=${bool cfg.accountGuestInCpuMeter}
|
||||
color_scheme=${toString cfg.colorScheme}
|
||||
delay=${toString cfg.delay}
|
||||
left_meters=${list leftMeters}
|
||||
left_meter_modes=${list leftModes}
|
||||
right_meters=${list rightMeters}
|
||||
right_meter_modes=${list rightModes}
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -21,13 +21,15 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
with import ../lib/dag.nix;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.info;
|
||||
|
||||
dag = config.lib.dag;
|
||||
|
||||
# Indexes info files found in this location
|
||||
homeInfoPath = "$HOME/.nix-profile/share/info";
|
||||
homeInfoPath = "${config.home.profileDirectory}/share/info";
|
||||
|
||||
# Installs this package -- the interactive just means that it
|
||||
# includes the curses `info` program. We also use `install-info`
|
||||
@@ -42,7 +44,7 @@ in
|
||||
enable = mkEnableOption "GNU Info";
|
||||
|
||||
homeInfoDirLocation = mkOption {
|
||||
default = "$HOME/.cache/info";
|
||||
default = "\${XDG_CACHE_HOME:-$HOME/.cache}/info";
|
||||
description = ''
|
||||
Directory in which to store the info <filename>dir</filename>
|
||||
file within your home.
|
||||
@@ -52,17 +54,12 @@ in
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [{
|
||||
assertion = config.home.sessionVariableSetter != "pam";
|
||||
message = ''
|
||||
The info module does not work with PAM as a session variable setter.
|
||||
'';
|
||||
}];
|
||||
|
||||
home.sessionVariables.INFOPATH =
|
||||
"${cfg.homeInfoDirLocation}\${INFOPATH:+:}\${INFOPATH}";
|
||||
|
||||
home.activation.createHomeInfoDir = dagEntryAfter ["installPackages"] ''
|
||||
home.activation.createHomeInfoDir = dag.entryAfter ["installPackages"] ''
|
||||
oPATH=$PATH
|
||||
export PATH="${lib.makeBinPath [ pkgs.gzip ]}''${PATH:+:}$PATH"
|
||||
$DRY_RUN_CMD mkdir -p "${cfg.homeInfoDirLocation}"
|
||||
$DRY_RUN_CMD rm -f "${cfg.homeInfoDirLocation}/dir"
|
||||
if [[ -d "${homeInfoPath}" ]]; then
|
||||
@@ -70,8 +67,12 @@ in
|
||||
-exec $DRY_RUN_CMD ${infoPkg}/bin/install-info '{}' \
|
||||
"${cfg.homeInfoDirLocation}/dir" \;
|
||||
fi
|
||||
export PATH="$oPATH"
|
||||
unset oPATH
|
||||
'';
|
||||
|
||||
home.packages = [infoPkg];
|
||||
home.packages = [ infoPkg ];
|
||||
|
||||
home.extraOutputsToInstall = [ "info" ];
|
||||
};
|
||||
}
|
||||
|
||||
211
modules/programs/irssi.nix
Normal file
211
modules/programs/irssi.nix
Normal file
@@ -0,0 +1,211 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.irssi;
|
||||
|
||||
boolStr = b: if b then "yes" else "no";
|
||||
quoteStr = s: escape ["\""] s;
|
||||
|
||||
assignFormat = set:
|
||||
concatStringsSep "\n"
|
||||
(mapAttrsToList (k: v: " ${k} = \"${quoteStr v}\";") set);
|
||||
|
||||
chatnetString =
|
||||
concatStringsSep "\n"
|
||||
(flip mapAttrsToList cfg.networks
|
||||
(k: v: ''
|
||||
${k} = {
|
||||
type = "${v.type}";
|
||||
nick = "${quoteStr v.nick}";
|
||||
autosendcmd = "${concatMapStringsSep ";" quoteStr v.autoCommands}";
|
||||
};
|
||||
''));
|
||||
|
||||
serversString =
|
||||
concatStringsSep ",\n"
|
||||
(flip mapAttrsToList cfg.networks
|
||||
(k: v: ''
|
||||
{
|
||||
chatnet = "${k}";
|
||||
address = "${v.server.address}";
|
||||
port = "${toString v.server.port}";
|
||||
use_ssl = "${boolStr v.server.ssl.enable}";
|
||||
ssl_verify = "${boolStr v.server.ssl.verify}";
|
||||
autoconnect = "${boolStr v.server.autoConnect}";
|
||||
}
|
||||
''));
|
||||
|
||||
channelString =
|
||||
concatStringsSep ",\n"
|
||||
(flip mapAttrsToList cfg.networks
|
||||
(k: v:
|
||||
concatStringsSep ",\n"
|
||||
(flip mapAttrsToList v.channels
|
||||
(c: cv: ''
|
||||
{
|
||||
chatnet = "${k}";
|
||||
name = "${c}";
|
||||
autojoin = "${boolStr cv.autoJoin}";
|
||||
}
|
||||
''))));
|
||||
|
||||
channelType = types.submodule {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
visible = false;
|
||||
default = null;
|
||||
description = "Name of the channel.";
|
||||
};
|
||||
|
||||
autoJoin = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to join this channel on connect.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networkType = types.submodule ({ name, ...}: {
|
||||
options = {
|
||||
name = mkOption {
|
||||
visible = false;
|
||||
default = name;
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
nick = mkOption {
|
||||
type = types.str;
|
||||
description = "Nickname in that network.";
|
||||
};
|
||||
|
||||
type = mkOption {
|
||||
type = types.str;
|
||||
description = "Type of the network.";
|
||||
default = "IRC";
|
||||
};
|
||||
|
||||
autoCommands = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "List of commands to execute on connect.";
|
||||
};
|
||||
|
||||
server = {
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
description = "Address of the chat server.";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.int;
|
||||
default = 6667;
|
||||
description = "Port of the chat server.";
|
||||
};
|
||||
|
||||
ssl = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether SSL should be used.";
|
||||
};
|
||||
|
||||
verify = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether the SSL certificate should be verified.";
|
||||
};
|
||||
};
|
||||
|
||||
autoConnect = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether Irssi connects to the server on launch.";
|
||||
};
|
||||
};
|
||||
|
||||
channels = mkOption {
|
||||
description = "Channels for the given network.";
|
||||
type = types.attrsOf channelType;
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
programs.irssi = {
|
||||
enable = mkEnableOption "the Irssi chat client";
|
||||
|
||||
extraConfig = mkOption {
|
||||
default = "";
|
||||
description = "These lines are appended to the Irssi configuration.";
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
aliases = mkOption {
|
||||
default = {};
|
||||
example = { J = "join"; BYE = "quit";};
|
||||
description = "An attribute set that maps aliases to commands.";
|
||||
type = types.attrsOf types.str;
|
||||
};
|
||||
|
||||
networks = mkOption {
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
freenode = {
|
||||
nick = "hmuser";
|
||||
server = {
|
||||
address = "chat.freenode.net";
|
||||
port = 6697;
|
||||
autoConnect = true;
|
||||
};
|
||||
channels = {
|
||||
nixos.autoJoin = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = "An attribute set of chat networks.";
|
||||
type = types.attrsOf networkType;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.irssi ];
|
||||
|
||||
home.file.".irssi/config".text = ''
|
||||
settings = {
|
||||
core = {
|
||||
settings_autosave = "no";
|
||||
};
|
||||
};
|
||||
|
||||
aliases = {
|
||||
${assignFormat cfg.aliases}
|
||||
};
|
||||
|
||||
chatnets = {
|
||||
${chatnetString}
|
||||
};
|
||||
|
||||
servers = (
|
||||
${serversString}
|
||||
);
|
||||
|
||||
channels = (
|
||||
${channelString}
|
||||
);
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
};
|
||||
}
|
||||
76
modules/programs/jq.nix
Normal file
76
modules/programs/jq.nix
Normal file
@@ -0,0 +1,76 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.jq;
|
||||
|
||||
colorType = mkOption {
|
||||
type = types.str;
|
||||
description = "ANSI color definition";
|
||||
example = "1;31";
|
||||
visible = false;
|
||||
};
|
||||
|
||||
colorsType = types.submodule {
|
||||
options = {
|
||||
null = colorType;
|
||||
false = colorType;
|
||||
true = colorType;
|
||||
numbers = colorType;
|
||||
strings = colorType;
|
||||
arrays = colorType;
|
||||
objects = colorType;
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.jq = {
|
||||
enable = mkEnableOption "the jq command-line JSON processor";
|
||||
|
||||
colors = mkOption {
|
||||
description = ''
|
||||
The colors used in colored JSON output.</para>
|
||||
|
||||
<para>See <link xlink:href="https://stedolan.github.io/jq/manual/#Colors"/>.
|
||||
'';
|
||||
|
||||
example = literalExample ''
|
||||
{
|
||||
null = "1;30";
|
||||
false = "0;31";
|
||||
true = "0;32";
|
||||
numbers = "0;36";
|
||||
strings = "0;33";
|
||||
arrays = "1;35";
|
||||
objects = "1;37";
|
||||
}
|
||||
'';
|
||||
|
||||
default = {
|
||||
null = "1;30";
|
||||
false = "0;39";
|
||||
true = "0;39";
|
||||
numbers = "0;39";
|
||||
strings = "0;32";
|
||||
arrays = "1;39";
|
||||
objects = "1;39";
|
||||
};
|
||||
|
||||
type = colorsType;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.jq ];
|
||||
|
||||
home.sessionVariables = let c = cfg.colors; in {
|
||||
JQ_COLORS = "${c.null}:${c.false}:${c.true}:${c.numbers}:${c.strings}:${c.arrays}:${c.objects}";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
with lib;
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.lesspipe = {
|
||||
enable = mkEnableOption "lesspipe preprocessor for less";
|
||||
|
||||
22
modules/programs/man.nix
Normal file
22
modules/programs/man.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.man.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable manual pages and the <command>man</command>
|
||||
command. This also includes "man" outputs of all
|
||||
<literal>home.packages</literal>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf config.programs.man.enable {
|
||||
home.packages = [ pkgs.man ];
|
||||
home.extraOutputsToInstall = [ "man" ];
|
||||
};
|
||||
}
|
||||
64
modules/programs/matplotlib.nix
Normal file
64
modules/programs/matplotlib.nix
Normal file
@@ -0,0 +1,64 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.matplotlib;
|
||||
|
||||
formatLine = o: n: v:
|
||||
let
|
||||
formatValue = v:
|
||||
if isBool v then (if v then "True" else "False")
|
||||
else toString v;
|
||||
in
|
||||
if isAttrs v
|
||||
then concatStringsSep "\n" (mapAttrsToList (formatLine "${o}${n}.") v)
|
||||
else (if v == "" then "" else "${o}${n}: ${formatValue v}");
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rprospero ];
|
||||
|
||||
options.programs.matplotlib = {
|
||||
enable = mkEnableOption "matplotlib, a plotting library for python";
|
||||
|
||||
config = mkOption {
|
||||
default = { };
|
||||
type = types.attrs;
|
||||
description = ''
|
||||
Add terms to the <filename>matplotlibrc</filename> file to
|
||||
control the default matplotlib behavior.
|
||||
'';
|
||||
example = literalExample ''
|
||||
{
|
||||
backend = "Qt5Agg";
|
||||
axes = {
|
||||
grid = true;
|
||||
facecolor = "black";
|
||||
edgecolor = "FF9900";
|
||||
};
|
||||
grid.color = "FF9900";
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Additional commands for matplotlib that will be added to the
|
||||
<filename>matplotlibrc</filename> file.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
xdg.configFile."matplotlib/matplotlibrc".text =
|
||||
concatStringsSep "\n" ([]
|
||||
++ mapAttrsToList (formatLine "") cfg.config
|
||||
++ optional (cfg.extraConfig != "") cfg.extraConfig
|
||||
) + "\n";
|
||||
};
|
||||
}
|
||||
107
modules/programs/mbsync-accounts.nix
Normal file
107
modules/programs/mbsync-accounts.nix
Normal file
@@ -0,0 +1,107 @@
|
||||
{ lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
extraConfigType = with lib.types; attrsOf (either (either str int) bool);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.mbsync = {
|
||||
enable = mkEnableOption "synchronization using mbsync";
|
||||
|
||||
flatten = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
example = ".";
|
||||
description = ''
|
||||
If set, flattens the hierarchy within the maildir by
|
||||
substituting the canonical hierarchy delimiter
|
||||
<literal>/</literal> with this value.
|
||||
'';
|
||||
};
|
||||
|
||||
create = mkOption {
|
||||
type = types.enum [ "none" "maildir" "imap" "both" ];
|
||||
default = "none";
|
||||
example = "maildir";
|
||||
description = ''
|
||||
Automatically create missing mailboxes within the
|
||||
given mail store.
|
||||
'';
|
||||
};
|
||||
|
||||
remove = mkOption {
|
||||
type = types.enum [ "none" "maildir" "imap" "both" ];
|
||||
default = "none";
|
||||
example = "imap";
|
||||
description = ''
|
||||
Propagate mailbox deletions to the given mail store.
|
||||
'';
|
||||
};
|
||||
|
||||
expunge = mkOption {
|
||||
type = types.enum [ "none" "maildir" "imap" "both" ];
|
||||
default = "none";
|
||||
example = "both";
|
||||
description = ''
|
||||
Permanently remove messages marked for deletion from
|
||||
the given mail store.
|
||||
'';
|
||||
};
|
||||
|
||||
patterns = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "*" ];
|
||||
description = ''
|
||||
Pattern of mailboxes to synchronize.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.channel = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
MaxMessages = 10000;
|
||||
MaxSize = "1m";
|
||||
};
|
||||
'';
|
||||
description = ''
|
||||
Per channel extra configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.local = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
description = ''
|
||||
Local store extra configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.remote = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
description = ''
|
||||
Remote store extra configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.account = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
PipelineDepth = 10;
|
||||
Timeout = 60;
|
||||
};
|
||||
'';
|
||||
description = ''
|
||||
Account section extra configuration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
188
modules/programs/mbsync.nix
Normal file
188
modules/programs/mbsync.nix
Normal file
@@ -0,0 +1,188 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
dag = config.lib.dag;
|
||||
|
||||
cfg = config.programs.mbsync;
|
||||
|
||||
# Accounts for which mbsync is enabled.
|
||||
mbsyncAccounts =
|
||||
filter (a: a.mbsync.enable) (attrValues config.accounts.email.accounts);
|
||||
|
||||
genTlsConfig = tls: {
|
||||
SSLType =
|
||||
if !tls.enable then "None"
|
||||
else if tls.useStartTls then "STARTTLS"
|
||||
else "IMAPS";
|
||||
}
|
||||
//
|
||||
optionalAttrs (tls.enable && tls.certificatesFile != null) {
|
||||
CertificateFile = tls.certificatesFile;
|
||||
};
|
||||
|
||||
masterSlaveMapping = {
|
||||
none = "None";
|
||||
imap = "Master";
|
||||
maildir = "Slave";
|
||||
both = "Both";
|
||||
};
|
||||
|
||||
genSection = header: entries:
|
||||
let
|
||||
escapeValue = escape [ "\"" ];
|
||||
hasSpace = v: builtins.match ".* .*" v != null;
|
||||
genValue = n: v:
|
||||
if isList v
|
||||
then concatMapStringsSep " " (genValue n) v
|
||||
else if isBool v then (if v then "yes" else "no")
|
||||
else if isInt v then toString v
|
||||
else if isString v && hasSpace v then "\"${escapeValue v}\""
|
||||
else if isString v then v
|
||||
else
|
||||
let prettyV = lib.generators.toPretty {} v;
|
||||
in throw "mbsync: unexpected value for option ${n}: '${prettyV}'";
|
||||
in
|
||||
''
|
||||
${header}
|
||||
${concatStringsSep "\n"
|
||||
(mapAttrsToList (n: v: "${n} ${genValue n v}") entries)}
|
||||
'';
|
||||
|
||||
genAccountConfig = account: with account;
|
||||
genSection "IMAPAccount ${name}" (
|
||||
{
|
||||
Host = imap.host;
|
||||
User = userName;
|
||||
PassCmd = toString passwordCommand;
|
||||
}
|
||||
// genTlsConfig imap.tls
|
||||
// optionalAttrs (imap.port != null) { Port = toString imap.port; }
|
||||
// mbsync.extraConfig.account
|
||||
)
|
||||
+ "\n"
|
||||
+ genSection "IMAPStore ${name}-remote" (
|
||||
{
|
||||
Account = name;
|
||||
}
|
||||
// mbsync.extraConfig.remote
|
||||
)
|
||||
+ "\n"
|
||||
+ genSection "MaildirStore ${name}-local" (
|
||||
{
|
||||
Path = "${maildir.absPath}/";
|
||||
Inbox = "${maildir.absPath}/${folders.inbox}";
|
||||
SubFolders = "Verbatim";
|
||||
}
|
||||
// optionalAttrs (mbsync.flatten != null) { Flatten = mbsync.flatten; }
|
||||
// mbsync.extraConfig.local
|
||||
)
|
||||
+ "\n"
|
||||
+ genSection "Channel ${name}" (
|
||||
{
|
||||
Master = ":${name}-remote:";
|
||||
Slave = ":${name}-local:";
|
||||
Patterns = mbsync.patterns;
|
||||
Create = masterSlaveMapping.${mbsync.create};
|
||||
Remove = masterSlaveMapping.${mbsync.remove};
|
||||
Expunge = masterSlaveMapping.${mbsync.expunge};
|
||||
SyncState = "*";
|
||||
}
|
||||
// mbsync.extraConfig.channel
|
||||
)
|
||||
+ "\n";
|
||||
|
||||
genGroupConfig = name: channels:
|
||||
let
|
||||
genGroupChannel = n: boxes: "Channel ${n}:${concatStringsSep "," boxes}";
|
||||
in
|
||||
concatStringsSep "\n" (
|
||||
[ "Group ${name}" ] ++ mapAttrsToList genGroupChannel channels
|
||||
);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.mbsync = {
|
||||
enable = mkEnableOption "mbsync IMAP4 and Maildir mailbox synchronizer";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.isync;
|
||||
defaultText = "pkgs.isync";
|
||||
example = literalExample "pkgs.isync";
|
||||
description = "The package to use for the mbsync binary.";
|
||||
};
|
||||
|
||||
groups = mkOption {
|
||||
type = types.attrsOf (types.attrsOf (types.listOf types.str));
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
inboxes = {
|
||||
account1 = [ "Inbox" ];
|
||||
account2 = [ "Inbox" ];
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Definition of groups.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra configuration lines to add to the mbsync configuration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions =
|
||||
let
|
||||
checkAccounts = pred: msg:
|
||||
let
|
||||
badAccounts = filter pred mbsyncAccounts;
|
||||
in {
|
||||
assertion = badAccounts == [];
|
||||
message = "mbsync: ${msg} for accounts: "
|
||||
+ concatMapStringsSep ", " (a: a.name) badAccounts;
|
||||
};
|
||||
in
|
||||
[
|
||||
(checkAccounts (a: a.maildir == null) "Missing maildir configuration")
|
||||
(checkAccounts (a: a.imap == null) "Missing IMAP configuration")
|
||||
(checkAccounts (a: a.passwordCommand == null) "Missing passwordCommand")
|
||||
(checkAccounts (a: a.userName == null) "Missing username")
|
||||
];
|
||||
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
programs.notmuch.new.ignore = [ ".uidvalidity" ".mbsyncstate" ];
|
||||
|
||||
home.file.".mbsyncrc".text =
|
||||
let
|
||||
accountsConfig = map genAccountConfig mbsyncAccounts;
|
||||
groupsConfig = mapAttrsToList genGroupConfig cfg.groups;
|
||||
in
|
||||
concatStringsSep "\n" (
|
||||
[ "# Generated by Home Manager.\n" ]
|
||||
++ accountsConfig
|
||||
++ groupsConfig
|
||||
++ optional (cfg.extraConfig != "") cfg.extraConfig
|
||||
) + "\n";
|
||||
|
||||
home.activation.createMaildir =
|
||||
dag.entryBetween [ "linkGeneration" ] [ "writeBoundary" ] ''
|
||||
$DRY_RUN_CMD mkdir -m700 -p $VERBOSE_ARG ${
|
||||
concatMapStringsSep " " (a: a.maildir.absPath) mbsyncAccounts
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
||||
102
modules/programs/mercurial.nix
Normal file
102
modules/programs/mercurial.nix
Normal file
@@ -0,0 +1,102 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.mercurial;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
programs.mercurial = {
|
||||
enable = mkEnableOption "Mercurial";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.mercurial;
|
||||
defaultText = "pkgs.mercurial";
|
||||
description = "Mercurial package to install.";
|
||||
};
|
||||
|
||||
userName = mkOption {
|
||||
type = types.str;
|
||||
description = "Default user name to use.";
|
||||
};
|
||||
|
||||
userEmail = mkOption {
|
||||
type = types.str;
|
||||
description = "Default user email to use.";
|
||||
};
|
||||
|
||||
aliases = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = "Mercurial aliases to define.";
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.either types.attrs types.lines;
|
||||
default = {};
|
||||
description = "Additional configuration to add.";
|
||||
};
|
||||
|
||||
iniContent = mkOption {
|
||||
type = types.attrsOf types.attrs;
|
||||
internal = true;
|
||||
};
|
||||
|
||||
ignores = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "*~" "*.swp" ];
|
||||
description = "List of globs for files to be globally ignored.";
|
||||
};
|
||||
|
||||
ignoresRegexp = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = [ "^.*~$" "^.*\\.swp$" ];
|
||||
description =
|
||||
"List of regular expressions for files to be globally ignored.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
mkMerge [
|
||||
{
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
programs.mercurial.iniContent.ui = {
|
||||
username = cfg.userName + " <" + cfg.userEmail + ">";
|
||||
};
|
||||
|
||||
xdg.configFile."hg/hgrc".text = generators.toINI {} cfg.iniContent;
|
||||
}
|
||||
|
||||
(mkIf (cfg.ignores != [] || cfg.ignoresRegexp != []) {
|
||||
programs.mercurial.iniContent.ui.ignore =
|
||||
"${config.xdg.configHome}/hg/hgignore_global";
|
||||
|
||||
xdg.configFile."hg/hgignore_global".text =
|
||||
"syntax: glob\n" + concatStringsSep "\n" cfg.ignores + "\n" +
|
||||
"syntax: regexp\n" + concatStringsSep "\n" cfg.ignoresRegexp + "\n";
|
||||
})
|
||||
|
||||
(mkIf (cfg.aliases != {}) {
|
||||
programs.mercurial.iniContent.alias = cfg.aliases;
|
||||
})
|
||||
|
||||
(mkIf (lib.isAttrs cfg.extraConfig) {
|
||||
programs.mercurial.iniContent = cfg.extraConfig;
|
||||
})
|
||||
|
||||
(mkIf (lib.isString cfg.extraConfig) {
|
||||
xdg.configFile."hg/hgrc".text = cfg.extraConfig;
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
36
modules/programs/msmtp-accounts.nix
Normal file
36
modules/programs/msmtp-accounts.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
options.msmtp = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable msmtp.
|
||||
</para><para>
|
||||
If enabled then it is possible to use the
|
||||
<parameter class="command">--account</parameter> command line
|
||||
option to send a message for a given account using the
|
||||
<command>msmtp</command> or <command>msmtpq</command> tool.
|
||||
For example, <command>msmtp --account=private</command> would
|
||||
send using the account defined in
|
||||
<option>accounts.email.accounts.private</option>. If the
|
||||
<parameter class="command">--account</parameter> option is not
|
||||
given then the primary account will be used.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = { };
|
||||
example = { auth = "login"; };
|
||||
description = ''
|
||||
Extra configuration options to add to <filename>~/.msmtprc</filename>.
|
||||
See <link xlink:href="https://marlam.de/msmtp/msmtprc.txt"/> for
|
||||
examples.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
76
modules/programs/msmtp.nix
Normal file
76
modules/programs/msmtp.nix
Normal file
@@ -0,0 +1,76 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.msmtp;
|
||||
|
||||
msmtpAccounts = filter (a: a.msmtp.enable)
|
||||
(attrValues config.accounts.email.accounts);
|
||||
|
||||
onOff = p: if p then "on" else "off";
|
||||
|
||||
accountStr = account: with account;
|
||||
concatStringsSep "\n" (
|
||||
[ "account ${name}" ]
|
||||
++ mapAttrsToList (n: v: n + " " + v) (
|
||||
{
|
||||
host = smtp.host;
|
||||
from = address;
|
||||
auth = "on";
|
||||
user = userName;
|
||||
tls = onOff smtp.tls.enable;
|
||||
tls_starttls = onOff smtp.tls.useStartTls;
|
||||
tls_trust_file = smtp.tls.certificatesFile;
|
||||
}
|
||||
// optionalAttrs (smtp.port != null) {
|
||||
port = toString smtp.port;
|
||||
}
|
||||
// optionalAttrs (passwordCommand != null) {
|
||||
# msmtp requires the password to finish with a newline.
|
||||
passwordeval = ''${pkgs.bash}/bin/bash -c "${toString passwordCommand}; echo"'';
|
||||
}
|
||||
// msmtp.extraConfig
|
||||
)
|
||||
++ optional primary "\naccount default : ${name}"
|
||||
);
|
||||
|
||||
configFile = mailAccounts: ''
|
||||
# Generated by Home Manager.
|
||||
|
||||
${cfg.extraConfig}
|
||||
|
||||
${concatStringsSep "\n\n" (map accountStr mailAccounts)}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
programs.msmtp = {
|
||||
enable = mkEnableOption "msmtp";
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra configuration lines to add to <filename>~/.msmtprc</filename>.
|
||||
See <link xlink:href="https://marlam.de/msmtp/msmtprc.txt"/> for examples.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.msmtp ];
|
||||
|
||||
xdg.configFile."msmtp/config".text = configFile msmtpAccounts;
|
||||
|
||||
home.sessionVariables = {
|
||||
MSMTP_QUEUE = "${config.xdg.dataHome}/msmtp/queue";
|
||||
MSMTP_LOG = "${config.xdg.dataHome}/msmtp/queue.log";
|
||||
};
|
||||
};
|
||||
}
|
||||
139
modules/programs/neovim.nix
Normal file
139
modules/programs/neovim.nix
Normal file
@@ -0,0 +1,139 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.neovim;
|
||||
|
||||
extraPythonPackageType = mkOptionType {
|
||||
name = "extra-python-packages";
|
||||
description = "python packages in python.withPackages format";
|
||||
check = with types; (x: if isFunction x
|
||||
then isList (x pkgs.pythonPackages)
|
||||
else false);
|
||||
merge = mergeOneOption;
|
||||
};
|
||||
|
||||
extraPython3PackageType = mkOptionType {
|
||||
name = "extra-python3-packages";
|
||||
description = "python3 packages in python.withPackages format";
|
||||
check = with types; (x: if isFunction x
|
||||
then isList (x pkgs.python3Packages)
|
||||
else false);
|
||||
merge = mergeOneOption;
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.neovim = {
|
||||
enable = mkEnableOption "Neovim";
|
||||
|
||||
viAlias = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Symlink `vi` to `nvim` binary.
|
||||
'';
|
||||
};
|
||||
|
||||
vimAlias = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Symlink `vim` to `nvim` binary.
|
||||
'';
|
||||
};
|
||||
|
||||
withPython = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Enable Python 2 provider. Set to <literal>true</literal> to
|
||||
use Python 2 plugins.
|
||||
'';
|
||||
};
|
||||
|
||||
extraPythonPackages = mkOption {
|
||||
type = with types; either extraPythonPackageType (listOf package);
|
||||
default = (_: []);
|
||||
defaultText = "ps: []";
|
||||
example = literalExample "(ps: with ps; [ pandas jedi ])";
|
||||
description = ''
|
||||
A function in python.withPackages format, which returns a
|
||||
list of Python 2 packages required for your plugins to work.
|
||||
'';
|
||||
};
|
||||
|
||||
withRuby = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Enable ruby provider.
|
||||
'';
|
||||
};
|
||||
|
||||
withPython3 = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Enable Python 3 provider. Set to <literal>true</literal> to
|
||||
use Python 3 plugins.
|
||||
'';
|
||||
};
|
||||
|
||||
extraPython3Packages = mkOption {
|
||||
type = with types; either extraPython3PackageType (listOf package);
|
||||
default = (_: []);
|
||||
defaultText = "ps: []";
|
||||
example = literalExample "(ps: with ps; [ python-language-server ])";
|
||||
description = ''
|
||||
A function in python.withPackages format, which returns a
|
||||
list of Python 3 packages required for your plugins to work.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.neovim-unwrapped;
|
||||
defaultText = "pkgs.neovim-unwrapped";
|
||||
description = "The package to use for the neovim binary.";
|
||||
};
|
||||
|
||||
configure = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
configure = {
|
||||
customRC = $''''
|
||||
" here your custom configuration goes!
|
||||
$'''';
|
||||
packages.myVimPackage = with pkgs.vimPlugins; {
|
||||
# loaded on launch
|
||||
start = [ fugitive ];
|
||||
# manually loadable by calling `:packadd $plugin-name`
|
||||
opt = [ ];
|
||||
};
|
||||
};
|
||||
'';
|
||||
description = ''
|
||||
Generate your init file from your list of plugins and custom commands,
|
||||
and loads it from the store via <command>nvim -u /nix/store/hash-vimrc</command>
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [
|
||||
(pkgs.wrapNeovim cfg.package {
|
||||
inherit (cfg)
|
||||
extraPython3Packages withPython3
|
||||
extraPythonPackages withPython
|
||||
withRuby viAlias vimAlias configure;
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
98
modules/programs/newsboat.nix
Normal file
98
modules/programs/newsboat.nix
Normal file
@@ -0,0 +1,98 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.programs.newsboat;
|
||||
wrapQuote = x: "\"${x}\"";
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.newsboat = {
|
||||
enable = mkEnableOption "the Newsboat feed reader";
|
||||
|
||||
urls = mkOption {
|
||||
type = types.listOf types.attrs;
|
||||
default = [];
|
||||
example = [{url = "http://example.com"; tags = ["foo" "bar"];}];
|
||||
description = "List of urls and tokens.";
|
||||
};
|
||||
|
||||
maxItems = mkOption {
|
||||
type = types.int;
|
||||
default = 0;
|
||||
description = "Maximum number of items per feed, 0 for infinite.";
|
||||
};
|
||||
|
||||
reloadThreads = mkOption {
|
||||
type = types.int;
|
||||
default = 5;
|
||||
description = "How many threads to use for updating the feeds.";
|
||||
};
|
||||
|
||||
autoReload = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to enable automatic reloading while newsboat is running.";
|
||||
};
|
||||
|
||||
reloadTime = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = 60;
|
||||
description = "Time in minutes between reloads.";
|
||||
};
|
||||
|
||||
browser = mkOption {
|
||||
type = types.str;
|
||||
default = "${pkgs.xdg_utils}/bin/xdg-open";
|
||||
description = "External browser to use.";
|
||||
};
|
||||
|
||||
queries = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
example = {
|
||||
"foo" = "rssurl =~ \"example.com\"";
|
||||
};
|
||||
description = "A list of queries to use.";
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Extra configuration values that will be appended to the end.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.newsboat ];
|
||||
home.file.".newsboat/urls".text =
|
||||
let
|
||||
urls = builtins.concatStringsSep "\n" (
|
||||
map (u: builtins.concatStringsSep " " ([u.url] ++ (map wrapQuote u.tags)))
|
||||
cfg.urls);
|
||||
queries = builtins.concatStringsSep "\n" (
|
||||
mapAttrsToList (n: v: "\"query:${n}:${escape ["\""] v}\"") cfg.queries);
|
||||
|
||||
in
|
||||
|
||||
''
|
||||
${urls}
|
||||
|
||||
${queries}
|
||||
'';
|
||||
home.file.".newsboat/config".text = ''
|
||||
max-items ${toString cfg.maxItems}
|
||||
browser ${cfg.browser}
|
||||
reload-threads ${toString cfg.reloadThreads}
|
||||
auto-reload ${if cfg.autoReload then "yes" else "no"}
|
||||
${optionalString (cfg.reloadTime != null) (toString "reload-time ${toString cfg.reloadTime}")}
|
||||
prepopulate-query-feeds yes
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
};
|
||||
}
|
||||
53
modules/programs/noti.nix
Normal file
53
modules/programs/noti.nix
Normal file
@@ -0,0 +1,53 @@
|
||||
{ config, lib, pkgs, ...}:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.noti;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.marsam ];
|
||||
|
||||
options.programs.noti = {
|
||||
enable = mkEnableOption "Noti";
|
||||
|
||||
settings = mkOption {
|
||||
type = types.attrsOf (types.attrsOf types.str);
|
||||
default = {};
|
||||
description = ''
|
||||
Configuration written to
|
||||
<filename>~/.config/noti/noti.yaml</filename>.
|
||||
</para><para>
|
||||
See
|
||||
<citerefentry>
|
||||
<refentrytitle>noti.yaml</refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
</citerefentry>.
|
||||
for the full list of options.
|
||||
'';
|
||||
example = literalExample ''
|
||||
{
|
||||
say = {
|
||||
voice = "Alex";
|
||||
};
|
||||
slack = {
|
||||
token = "1234567890abcdefg";
|
||||
channel = "@jaime";
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.noti ];
|
||||
|
||||
xdg.configFile."noti/noti.yaml" = mkIf (cfg.settings != {}) {
|
||||
text = generators.toYAML {} cfg.settings;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
7
modules/programs/notmuch-accounts.nix
Normal file
7
modules/programs/notmuch-accounts.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ lib, ... }:
|
||||
|
||||
{
|
||||
options.notmuch = {
|
||||
enable = lib.mkEnableOption "notmuch indexing";
|
||||
};
|
||||
}
|
||||
196
modules/programs/notmuch.nix
Normal file
196
modules/programs/notmuch.nix
Normal file
@@ -0,0 +1,196 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.notmuch;
|
||||
|
||||
mkIniKeyValue = key: value:
|
||||
let
|
||||
tweakVal = v:
|
||||
if isString v then v
|
||||
else if isList v then concatMapStringsSep ";" tweakVal v
|
||||
else if isBool v then (if v then "true" else "false")
|
||||
else toString v;
|
||||
in
|
||||
"${key}=${tweakVal value}";
|
||||
|
||||
notmuchIni =
|
||||
recursiveUpdate
|
||||
{
|
||||
database = {
|
||||
path = config.accounts.email.maildirBasePath;
|
||||
};
|
||||
|
||||
maildir = {
|
||||
synchronize_flags = cfg.maildir.synchronizeFlags;
|
||||
};
|
||||
|
||||
new = {
|
||||
ignore = cfg.new.ignore;
|
||||
tags = cfg.new.tags;
|
||||
};
|
||||
|
||||
user =
|
||||
let
|
||||
accounts =
|
||||
filter (a: a.notmuch.enable)
|
||||
(attrValues config.accounts.email.accounts);
|
||||
primary = filter (a: a.primary) accounts;
|
||||
secondaries = filter (a: !a.primary) accounts;
|
||||
in {
|
||||
name = catAttrs "realName" primary;
|
||||
primary_email = catAttrs "address" primary;
|
||||
other_email = catAttrs "address" secondaries;
|
||||
};
|
||||
|
||||
search = {
|
||||
exclude_tags = [ "deleted" "spam" ];
|
||||
};
|
||||
}
|
||||
cfg.extraConfig;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.notmuch = {
|
||||
enable = mkEnableOption "Notmuch mail indexer";
|
||||
|
||||
new = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
ignore = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = ''
|
||||
A list to specify files and directories that will not be
|
||||
searched for messages by <command>notmuch new</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
tags = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ "unread" "inbox" ];
|
||||
example = [ "new" ];
|
||||
description = ''
|
||||
A list of tags that will be added to all messages
|
||||
incorporated by <command>notmuch new</command>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
default = {};
|
||||
description = ''
|
||||
Options related to email processing performed by
|
||||
<command>notmuch new</command>.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.attrsOf (types.attrsOf types.str);
|
||||
default = {};
|
||||
description = ''
|
||||
Options that should be appended to the notmuch configuration file.
|
||||
'';
|
||||
};
|
||||
|
||||
hooks = {
|
||||
preNew = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = "mbsync --all";
|
||||
description = ''
|
||||
Bash statements run before scanning or importing new
|
||||
messages into the database.
|
||||
'';
|
||||
};
|
||||
|
||||
postNew = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = ''
|
||||
notmuch tag +nixos -- tag:new and from:nixos1@discoursemail.com
|
||||
'';
|
||||
description = ''
|
||||
Bash statements run after new messages have been imported
|
||||
into the database and initial tags have been applied.
|
||||
'';
|
||||
};
|
||||
|
||||
postInsert = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Bash statements run after a message has been inserted
|
||||
into the database and initial tags have been applied.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
maildir = {
|
||||
synchronizeFlags = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to synchronize Maildir flags.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = notmuchIni.user.name != [];
|
||||
message = "notmuch: Must have a user name set.";
|
||||
}
|
||||
{
|
||||
assertion = notmuchIni.user.primary_email != [];
|
||||
message = "notmuch: Must have a user primary email address set.";
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = [ pkgs.notmuch ];
|
||||
|
||||
home.sessionVariables = {
|
||||
NOTMUCH_CONFIG = "${config.xdg.configHome}/notmuch/notmuchrc";
|
||||
NMBGIT = "${config.xdg.dataHome}/notmuch/nmbug";
|
||||
};
|
||||
|
||||
xdg.configFile."notmuch/notmuchrc".text =
|
||||
let
|
||||
toIni = generators.toINI { mkKeyValue = mkIniKeyValue; };
|
||||
in
|
||||
"# Generated by Home Manager.\n\n"
|
||||
+ toIni notmuchIni;
|
||||
|
||||
home.file =
|
||||
let
|
||||
hook = name: cmds:
|
||||
{
|
||||
target = "${notmuchIni.database.path}/.notmuch/hooks/${name}";
|
||||
source = pkgs.writeScript name ''
|
||||
#!${pkgs.stdenv.shell}
|
||||
|
||||
export PATH="${pkgs.notmuch}/bin''${PATH:+:}$PATH"
|
||||
export NOTMUCH_CONFIG="${config.xdg.configHome}/notmuch/notmuchrc"
|
||||
export NMBGIT="${config.xdg.dataHome}/notmuch/nmbug"
|
||||
|
||||
${cmds}
|
||||
'';
|
||||
executable = true;
|
||||
};
|
||||
in
|
||||
optional (cfg.hooks.preNew != "")
|
||||
(hook "pre-new" cfg.hooks.preNew)
|
||||
++
|
||||
optional (cfg.hooks.postNew != "")
|
||||
(hook "post-new" cfg.hooks.postNew)
|
||||
++
|
||||
optional (cfg.hooks.postInsert != "")
|
||||
(hook "post-insert" cfg.hooks.postInsert);
|
||||
};
|
||||
}
|
||||
53
modules/programs/obs-studio.nix
Normal file
53
modules/programs/obs-studio.nix
Normal file
@@ -0,0 +1,53 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.obs-studio;
|
||||
package = pkgs.obs-studio;
|
||||
|
||||
mkPluginEnv = packages:
|
||||
let
|
||||
pluginDirs = map (pkg: "${pkg}/share/obs/obs-plugins") packages;
|
||||
plugins = concatMapStringsSep " " (p: "${p}/*") pluginDirs;
|
||||
in
|
||||
pkgs.runCommand "obs-studio-plugins"
|
||||
{
|
||||
preferLocalBuild = true;
|
||||
allowSubstitutes = false;
|
||||
}
|
||||
''
|
||||
mkdir $out
|
||||
[[ '${plugins}' ]] || exit 0
|
||||
for plugin in ${plugins}; do
|
||||
ln -s "$plugin" $out/
|
||||
done
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.adisbladis ];
|
||||
|
||||
options = {
|
||||
programs.obs-studio = {
|
||||
enable = mkEnableOption "obs-studio";
|
||||
|
||||
plugins = mkOption {
|
||||
default = [];
|
||||
example = literalExample "[ pkgs.obs-linuxbrowser ]";
|
||||
description = "Optional OBS plugins.";
|
||||
type = types.listOf types.package;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ package ];
|
||||
|
||||
xdg.configFile."obs-studio/plugins" = mkIf (cfg.plugins != []) {
|
||||
source = mkPluginEnv cfg.plugins;
|
||||
};
|
||||
};
|
||||
}
|
||||
57
modules/programs/offlineimap-accounts.nix
Normal file
57
modules/programs/offlineimap-accounts.nix
Normal file
@@ -0,0 +1,57 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
extraConfigType = with types; attrsOf (either (either str int) bool);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.offlineimap = {
|
||||
enable = mkEnableOption "OfflineIMAP";
|
||||
|
||||
extraConfig.account = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = {
|
||||
autorefresh = 20;
|
||||
};
|
||||
description = ''
|
||||
Extra configuration options to add to the account section.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.local = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = {
|
||||
sync_deletes = true;
|
||||
};
|
||||
description = ''
|
||||
Extra configuration options to add to the local account
|
||||
section.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.remote = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = {
|
||||
maxconnections = 2;
|
||||
expunge = false;
|
||||
};
|
||||
description = ''
|
||||
Extra configuration options to add to the remote account
|
||||
section.
|
||||
'';
|
||||
};
|
||||
|
||||
postSyncHookCommand = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = "Command to run after fetching new mails.";
|
||||
};
|
||||
};
|
||||
}
|
||||
207
modules/programs/offlineimap.nix
Normal file
207
modules/programs/offlineimap.nix
Normal file
@@ -0,0 +1,207 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.offlineimap;
|
||||
|
||||
accounts = filter (a: a.offlineimap.enable)
|
||||
(attrValues config.accounts.email.accounts);
|
||||
|
||||
toIni = generators.toINI {
|
||||
mkKeyValue = key: value:
|
||||
let
|
||||
value' =
|
||||
if isBool value then (if value then "yes" else "no")
|
||||
else toString value;
|
||||
in
|
||||
"${key} = ${value'}";
|
||||
};
|
||||
|
||||
# Generates a script to fetch only a specific account.
|
||||
#
|
||||
# Note, these scripts are not actually created and installed at the
|
||||
# moment. It will need some thinking on whether this is a good idea
|
||||
# and whether other modules should have some similar functionality.
|
||||
#
|
||||
# Perhaps have a single tool `email` that wraps the command?
|
||||
# Something like
|
||||
#
|
||||
# $ email <account name> <program name> <program args>
|
||||
genOfflineImapScript = account: with account;
|
||||
pkgs.writeShellScriptBin "offlineimap-${name}" ''
|
||||
exec ${pkgs.offlineimap}/bin/offlineimap -a${account.name} "$@"
|
||||
'';
|
||||
|
||||
accountStr = account: with account;
|
||||
let
|
||||
postSyncHook = optionalAttrs (offlineimap.postSyncHookCommand != "") {
|
||||
postsynchook =
|
||||
pkgs.writeShellScriptBin
|
||||
"postsynchook"
|
||||
offlineimap.postSyncHookCommand
|
||||
+ "/bin/postsynchook";
|
||||
};
|
||||
|
||||
localType =
|
||||
if account.flavor == "gmail.com"
|
||||
then "GmailMaildir"
|
||||
else "Maildir";
|
||||
|
||||
remoteType =
|
||||
if account.flavor == "gmail.com"
|
||||
then "Gmail"
|
||||
else "IMAP";
|
||||
|
||||
remoteHost = optionalAttrs (imap.host != null) {
|
||||
remotehost = imap.host;
|
||||
};
|
||||
|
||||
remotePort = optionalAttrs ((imap.port or null) != null) {
|
||||
remoteport = imap.port;
|
||||
};
|
||||
|
||||
ssl =
|
||||
if imap.tls.enable
|
||||
then
|
||||
{
|
||||
ssl = true;
|
||||
sslcacertfile = imap.tls.certificatesFile;
|
||||
starttls = imap.tls.useStartTls;
|
||||
}
|
||||
else
|
||||
{
|
||||
ssl = false;
|
||||
};
|
||||
|
||||
remotePassEval =
|
||||
let
|
||||
arglist = concatMapStringsSep "," (x: "'${x}'") passwordCommand;
|
||||
in
|
||||
optionalAttrs (passwordCommand != null) {
|
||||
remotepasseval = ''get_pass("${name}", [${arglist}])'';
|
||||
};
|
||||
in
|
||||
toIni {
|
||||
"Account ${name}" = {
|
||||
localrepository = "${name}-local";
|
||||
remoterepository = "${name}-remote";
|
||||
}
|
||||
// postSyncHook
|
||||
// offlineimap.extraConfig.account;
|
||||
|
||||
"Repository ${name}-local" = {
|
||||
type = localType;
|
||||
localfolders = maildir.absPath;
|
||||
}
|
||||
// offlineimap.extraConfig.local;
|
||||
|
||||
"Repository ${name}-remote" = {
|
||||
type = remoteType;
|
||||
remoteuser = userName;
|
||||
}
|
||||
// remoteHost
|
||||
// remotePort
|
||||
// remotePassEval
|
||||
// ssl
|
||||
// offlineimap.extraConfig.remote;
|
||||
};
|
||||
|
||||
extraConfigType = with types; attrsOf (either (either str int) bool);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.offlineimap = {
|
||||
enable = mkEnableOption "OfflineIMAP";
|
||||
|
||||
pythonFile = mkOption {
|
||||
type = types.lines;
|
||||
default = ''
|
||||
import subprocess
|
||||
|
||||
def get_pass(service, cmd):
|
||||
return subprocess.check_output(cmd, )
|
||||
'';
|
||||
description = ''
|
||||
Python code that can then be used in other parts of the
|
||||
configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.general = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = {
|
||||
maxage = 30;
|
||||
ui = "blinkenlights";
|
||||
};
|
||||
description = ''
|
||||
Extra configuration options added to the
|
||||
<option>general</option> section.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.default = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = {
|
||||
gmailtrashfolder = "[Gmail]/Papierkorb";
|
||||
};
|
||||
description = ''
|
||||
Extra configuration options added to the
|
||||
<option>DEFAULT</option> section.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig.mbnames = mkOption {
|
||||
type = extraConfigType;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
filename = "~/.config/mutt/mailboxes";
|
||||
header = "'mailboxes '";
|
||||
peritem = "'+%(accountname)s/%(foldername)s'";
|
||||
sep = "' '";
|
||||
footer = "'\\n'";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Extra configuration options added to the
|
||||
<code>mbnames</code> section.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.offlineimap ];
|
||||
|
||||
xdg.configFile."offlineimap/get_settings.py".text = cfg.pythonFile;
|
||||
|
||||
xdg.configFile."offlineimap/config".text =
|
||||
''
|
||||
# Generated by Home Manager.
|
||||
# See https://github.com/OfflineIMAP/offlineimap/blob/master/offlineimap.conf
|
||||
# for an exhaustive list of options.
|
||||
''
|
||||
+ toIni ({
|
||||
general = {
|
||||
accounts = concatMapStringsSep "," (a: a.name) accounts;
|
||||
pythonfile = "${config.xdg.configHome}/offlineimap/get_settings.py";
|
||||
metadata = "${config.xdg.dataHome}/offlineimap";
|
||||
}
|
||||
// cfg.extraConfig.general;
|
||||
}
|
||||
// optionalAttrs (cfg.extraConfig.mbnames != {}) {
|
||||
mbnames = { enabled = true; } // cfg.extraConfig.mbnames;
|
||||
}
|
||||
// optionalAttrs (cfg.extraConfig.default != {}) {
|
||||
DEFAULT = cfg.extraConfig.default;
|
||||
})
|
||||
+ "\n"
|
||||
+ concatStringsSep "\n" (map accountStr accounts);
|
||||
};
|
||||
}
|
||||
52
modules/programs/opam.nix
Normal file
52
modules/programs/opam.nix
Normal file
@@ -0,0 +1,52 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.opam;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.marsam ];
|
||||
|
||||
options.programs.opam = {
|
||||
enable = mkEnableOption "Opam";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.opam;
|
||||
defaultText = "pkgs.opam";
|
||||
description = "Opam package to install.";
|
||||
};
|
||||
|
||||
enableBashIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Bash integration.
|
||||
'';
|
||||
};
|
||||
|
||||
enableZshIntegration = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether to enable Zsh integration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
programs.bash.initExtra = mkIf cfg.enableBashIntegration ''
|
||||
eval "$(${cfg.package}/bin/opam env --shell=bash)"
|
||||
'';
|
||||
|
||||
programs.zsh.initExtra = mkIf cfg.enableZshIntegration ''
|
||||
eval "$(${cfg.package}/bin/opam env --shell=zsh)"
|
||||
'';
|
||||
};
|
||||
}
|
||||
36
modules/programs/pidgin.nix
Normal file
36
modules/programs/pidgin.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.pidgin;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.pidgin = {
|
||||
enable = mkEnableOption "Pidgin messaging client";
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.pidgin;
|
||||
defaultText = "pkgs.pidgin";
|
||||
description = "The Pidgin package to use.";
|
||||
};
|
||||
|
||||
plugins = mkOption {
|
||||
default = [];
|
||||
example = literalExample "[ pkgs.pidgin-otr pkgs.pidgin-osd ]";
|
||||
description = "Plugins that should be available to Pidgin.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ (cfg.package.override { inherit (cfg) plugins; }) ];
|
||||
};
|
||||
}
|
||||
339
modules/programs/rofi.nix
Normal file
339
modules/programs/rofi.nix
Normal file
@@ -0,0 +1,339 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
with builtins;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.rofi;
|
||||
|
||||
colorOption = description: mkOption {
|
||||
type = types.str;
|
||||
description = description;
|
||||
};
|
||||
|
||||
rowColorSubmodule = types.submodule {
|
||||
options = {
|
||||
background = colorOption "Background color";
|
||||
foreground = colorOption "Foreground color";
|
||||
backgroundAlt = colorOption "Alternative background color";
|
||||
highlight = mkOption {
|
||||
type = types.submodule {
|
||||
options = {
|
||||
background = colorOption "Highlight background color";
|
||||
foreground = colorOption "Highlight foreground color";
|
||||
};
|
||||
};
|
||||
description = "Color settings for highlighted row.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
windowColorSubmodule = types.submodule {
|
||||
options = {
|
||||
background = colorOption "Window background color";
|
||||
border = colorOption "Window border color";
|
||||
separator = colorOption "Separator color";
|
||||
};
|
||||
};
|
||||
|
||||
colorsSubmodule = types.submodule {
|
||||
options = {
|
||||
window = mkOption {
|
||||
default = null;
|
||||
type = windowColorSubmodule;
|
||||
description = "Window color settings.";
|
||||
};
|
||||
rows = mkOption {
|
||||
default = null;
|
||||
type = types.submodule {
|
||||
options = {
|
||||
normal = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr rowColorSubmodule;
|
||||
description = "Normal row color settings.";
|
||||
};
|
||||
active = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr rowColorSubmodule;
|
||||
description = "Active row color settings.";
|
||||
};
|
||||
urgent = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr rowColorSubmodule;
|
||||
description = "Urgent row color settings.";
|
||||
};
|
||||
};
|
||||
};
|
||||
description = "Rows color settings.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
valueToString = value:
|
||||
if isBool value
|
||||
then (if value then "true" else "else")
|
||||
else toString value;
|
||||
|
||||
windowColorsToString = window: concatStringsSep ", " (with window; [
|
||||
background
|
||||
border
|
||||
separator
|
||||
]);
|
||||
|
||||
rowsColorsToString = rows: ''
|
||||
${optionalString
|
||||
(rows.normal != null)
|
||||
(setOption "color-normal" (rowColorsToString rows.normal))}
|
||||
${optionalString
|
||||
(rows.active != null)
|
||||
(setOption "color-active" (rowColorsToString rows.active))}
|
||||
${optionalString
|
||||
(rows.urgent != null)
|
||||
(setOption "color-urgent" (rowColorsToString rows.urgent))}
|
||||
'';
|
||||
|
||||
rowColorsToString = row: concatStringsSep ", " (with row; [
|
||||
background
|
||||
foreground
|
||||
backgroundAlt
|
||||
highlight.background
|
||||
highlight.foreground
|
||||
]);
|
||||
|
||||
setOption = name: value:
|
||||
optionalString (value != null) "rofi.${name}: ${valueToString value}";
|
||||
|
||||
setColorScheme = colors: optionalString (colors != null) ''
|
||||
${optionalString
|
||||
(colors.window != null)
|
||||
setOption "color-window" (windowColorsToString colors.window)}
|
||||
${optionalString
|
||||
(colors.rows != null)
|
||||
(rowsColorsToString colors.rows)}
|
||||
'';
|
||||
|
||||
locationsMap = {
|
||||
center = 0;
|
||||
top-left = 1;
|
||||
top = 2;
|
||||
top-right = 3;
|
||||
right = 4;
|
||||
bottom-right = 5;
|
||||
bottom = 6;
|
||||
bottom-left = 7;
|
||||
left = 8;
|
||||
};
|
||||
|
||||
themeName =
|
||||
if (cfg.theme == null) then null
|
||||
else if (lib.isString cfg.theme) then cfg.theme
|
||||
else lib.removeSuffix ".rasi" (baseNameOf cfg.theme);
|
||||
|
||||
themePath = if (lib.isString cfg.theme) then null else cfg.theme;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options.programs.rofi = {
|
||||
enable = mkEnableOption "Rofi: A window switcher, application launcher and dmenu replacement";
|
||||
|
||||
width = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.int;
|
||||
description = "Window width";
|
||||
example = 100;
|
||||
};
|
||||
|
||||
lines = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.int;
|
||||
description = "Number of lines";
|
||||
example = 10;
|
||||
};
|
||||
|
||||
borderWidth = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.int;
|
||||
description = "Border width";
|
||||
example = 1;
|
||||
};
|
||||
|
||||
rowHeight = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.int;
|
||||
description = "Row height (in chars)";
|
||||
example = 1;
|
||||
};
|
||||
|
||||
padding = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.int;
|
||||
description = "Padding";
|
||||
example = 400;
|
||||
};
|
||||
|
||||
font = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
example = "Droid Sans Mono 14";
|
||||
description = "Font to use.";
|
||||
};
|
||||
|
||||
scrollbar = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = "Whether to show a scrollbar.";
|
||||
};
|
||||
|
||||
terminal = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
description = ''
|
||||
Path to the terminal which will be used to run console applications
|
||||
'';
|
||||
example = "\${pkgs.gnome3.gnome_terminal}/bin/gnome-terminal";
|
||||
};
|
||||
|
||||
separator = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr (types.enum [ "none" "dash" "solid" ]);
|
||||
description = "Separator style";
|
||||
example = "solid";
|
||||
};
|
||||
|
||||
cycle = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = "Whether to cycle through the results list.";
|
||||
};
|
||||
|
||||
fullscreen = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = "Whether to run rofi fullscreen.";
|
||||
};
|
||||
|
||||
location = mkOption {
|
||||
default = "center";
|
||||
type = types.enum (builtins.attrNames locationsMap);
|
||||
description = "The location rofi appears on the screen.";
|
||||
};
|
||||
|
||||
xoffset = mkOption {
|
||||
default = 0;
|
||||
type = types.int;
|
||||
description = ''
|
||||
Offset in the x-axis in pixels relative to the chosen location.
|
||||
'';
|
||||
};
|
||||
|
||||
yoffset = mkOption {
|
||||
default = 0;
|
||||
type = types.int;
|
||||
description = ''
|
||||
Offset in the y-axis in pixels relative to the chosen location.
|
||||
'';
|
||||
};
|
||||
|
||||
colors = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr colorsSubmodule;
|
||||
description = ''
|
||||
Color scheme settings. Colors can be specified in CSS color
|
||||
formats. This option may become deprecated in the future and
|
||||
therefore the <varname>programs.rofi.theme</varname> option
|
||||
should be used whenever possible.
|
||||
'';
|
||||
example = literalExample ''
|
||||
colors = {
|
||||
window = {
|
||||
background = "argb:583a4c54";
|
||||
border = "argb:582a373e";
|
||||
separator = "#c3c6c8";
|
||||
};
|
||||
|
||||
rows = {
|
||||
normal = {
|
||||
background = "argb:58455a64";
|
||||
foreground = "#fafbfc";
|
||||
backgroundAlt = "argb:58455a64";
|
||||
highlight = {
|
||||
background = "#00bcd4";
|
||||
foreground = "#fafbfc";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
'';
|
||||
};
|
||||
|
||||
theme = mkOption {
|
||||
default = null;
|
||||
type = with types; nullOr (either string path);
|
||||
example = "Arc";
|
||||
description = ''
|
||||
Name of theme or path to theme file in rasi format. Available
|
||||
named themes can be viewed using the
|
||||
<command>rofi-theme-selector</command> tool.
|
||||
'';
|
||||
};
|
||||
|
||||
configPath = mkOption {
|
||||
default = "${config.xdg.configHome}/rofi/config";
|
||||
defaultText = "$XDG_CONFIG_HOME/rofi/config";
|
||||
type = types.str;
|
||||
description = "Path where to put generated configuration file.";
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
default = "";
|
||||
type = types.lines;
|
||||
description = "Additional configuration to add.";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.theme == null || cfg.colors == null;
|
||||
message = ''
|
||||
Cannot use the rofi options 'theme' and 'colors' simultaneously.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = [ pkgs.rofi ];
|
||||
|
||||
home.file."${cfg.configPath}".text = ''
|
||||
${setOption "width" cfg.width}
|
||||
${setOption "lines" cfg.lines}
|
||||
${setOption "font" cfg.font}
|
||||
${setOption "bw" cfg.borderWidth}
|
||||
${setOption "eh" cfg.rowHeight}
|
||||
${setOption "padding" cfg.padding}
|
||||
${setOption "separator-style" cfg.separator}
|
||||
${setOption "hide-scrollbar" (
|
||||
if (cfg.scrollbar != null)
|
||||
then (! cfg.scrollbar)
|
||||
else cfg.scrollbar
|
||||
)}
|
||||
${setOption "terminal" cfg.terminal}
|
||||
${setOption "cycle" cfg.cycle}
|
||||
${setOption "fullscreen" cfg.fullscreen}
|
||||
${setOption "location" (builtins.getAttr cfg.location locationsMap)}
|
||||
${setOption "xoffset" cfg.xoffset}
|
||||
${setOption "yoffset" cfg.yoffset}
|
||||
|
||||
${setColorScheme cfg.colors}
|
||||
${setOption "theme" themeName}
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
|
||||
xdg.dataFile = mkIf (themePath != null) {
|
||||
"rofi/themes/${themeName}.rasi".source = themePath;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -8,7 +8,9 @@ let
|
||||
|
||||
yn = flag: if flag then "yes" else "no";
|
||||
|
||||
matchBlockModule = types.submodule {
|
||||
unwords = builtins.concatStringsSep " ";
|
||||
|
||||
matchBlockModule = types.submodule ({ name, ... }: {
|
||||
options = {
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
@@ -24,6 +26,15 @@ let
|
||||
description = "Specifies port number to connect on remote host.";
|
||||
};
|
||||
|
||||
forwardAgent = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = ''
|
||||
Whether the connection to the authentication agent (if any)
|
||||
will be forwarded to the remote machine.
|
||||
'';
|
||||
};
|
||||
|
||||
forwardX11 = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -55,10 +66,15 @@ let
|
||||
};
|
||||
|
||||
identityFile = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
type = with types; either (listOf str) (nullOr str);
|
||||
default = [];
|
||||
apply = p:
|
||||
if p == null then []
|
||||
else if isString p then [p]
|
||||
else p;
|
||||
description = ''
|
||||
Specifies a file from which the user identity is read.
|
||||
Specifies files from which the user identity is read.
|
||||
Identities will be tried in the given order.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -81,6 +97,24 @@ let
|
||||
"Set timeout in seconds after which response will be requested.";
|
||||
};
|
||||
|
||||
sendEnv = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = ''
|
||||
Environment variables to send from the local host to the
|
||||
server.
|
||||
'';
|
||||
};
|
||||
|
||||
compression = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = null;
|
||||
description = ''
|
||||
Specifies whether to use compression. Omitted from the host
|
||||
block when <literal>null</literal>.
|
||||
'';
|
||||
};
|
||||
|
||||
checkHostIP = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@@ -95,27 +129,66 @@ let
|
||||
default = null;
|
||||
description = "The command to use to connect to the server.";
|
||||
};
|
||||
|
||||
proxyJump = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "The proxy host to use to connect to the server.";
|
||||
};
|
||||
|
||||
certificateFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
Specifies a file from which the user certificate is read.
|
||||
'';
|
||||
};
|
||||
|
||||
addressFamily = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr (types.enum ["any" "inet" "inet6"]);
|
||||
description = ''
|
||||
Specifies which address family to use when connecting.
|
||||
'';
|
||||
};
|
||||
|
||||
extraOptions = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = "Extra configuration options for the host.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config.host = mkDefault name;
|
||||
});
|
||||
|
||||
matchBlockStr = cf: concatStringsSep "\n" (
|
||||
["Host ${cf.host}"]
|
||||
++ optional (cf.port != null) " Port ${toString cf.port}"
|
||||
++ optional cf.forwardX11 " ForwardX11 yes"
|
||||
++ optional cf.forwardX11Trusted " ForwardX11Trusted yes"
|
||||
++ optional cf.identitiesOnly " IdentitiesOnly yes"
|
||||
++ optional (cf.user != null) " User ${cf.user}"
|
||||
++ optional (cf.identityFile != null) " IdentityFile ${cf.identityFile}"
|
||||
++ optional (cf.hostname != null) " HostName ${cf.hostname}"
|
||||
++ optional (cf.port != null) " Port ${toString cf.port}"
|
||||
++ optional (cf.forwardAgent != null) " ForwardAgent ${yn cf.forwardAgent}"
|
||||
++ optional cf.forwardX11 " ForwardX11 yes"
|
||||
++ optional cf.forwardX11Trusted " ForwardX11Trusted yes"
|
||||
++ optional cf.identitiesOnly " IdentitiesOnly yes"
|
||||
++ optional (cf.user != null) " User ${cf.user}"
|
||||
++ optional (cf.certificateFile != null) " CertificateFile ${cf.certificateFile}"
|
||||
++ optional (cf.hostname != null) " HostName ${cf.hostname}"
|
||||
++ optional (cf.addressFamily != null) " AddressFamily ${cf.addressFamily}"
|
||||
++ optional (cf.sendEnv != []) " SendEnv ${unwords cf.sendEnv}"
|
||||
++ optional (cf.serverAliveInterval != 0)
|
||||
" ServerAliveInterval ${toString cf.serverAliveInterval}"
|
||||
++ optional (!cf.checkHostIP) " CheckHostIP no"
|
||||
++ optional (cf.proxyCommand != null) " ProxyCommand ${cf.proxyCommand}"
|
||||
++ optional (cf.compression != null) " Compression ${yn cf.compression}"
|
||||
++ optional (!cf.checkHostIP) " CheckHostIP no"
|
||||
++ optional (cf.proxyCommand != null) " ProxyCommand ${cf.proxyCommand}"
|
||||
++ optional (cf.proxyJump != null) " ProxyJump ${cf.proxyJump}"
|
||||
++ map (file: " IdentityFile ${file}") cf.identityFile
|
||||
++ mapAttrsToList (n: v: " ${n} ${v}") cf.extraOptions
|
||||
);
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options.programs.ssh = {
|
||||
enable = mkEnableOption "SSH client configuration";
|
||||
|
||||
@@ -123,8 +196,46 @@ in
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Whether connection to authentication agent (if any) will be forwarded
|
||||
to remote machine.
|
||||
Whether the connection to the authentication agent (if any)
|
||||
will be forwarded to the remote machine.
|
||||
'';
|
||||
};
|
||||
|
||||
compression = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = "Specifies whether to use compression.";
|
||||
};
|
||||
|
||||
serverAliveInterval = mkOption {
|
||||
type = types.int;
|
||||
default = 0;
|
||||
description = ''
|
||||
Set default timeout in seconds after which response will be requested.
|
||||
'';
|
||||
};
|
||||
|
||||
hashKnownHosts = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Indicates that
|
||||
<citerefentry>
|
||||
<refentrytitle>ssh</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>
|
||||
should hash host names and addresses when they are added to
|
||||
the known hosts file.
|
||||
'';
|
||||
};
|
||||
|
||||
userKnownHostsFile = mkOption {
|
||||
type = types.str;
|
||||
default = "~/.ssh/known_hosts";
|
||||
description = ''
|
||||
Specifies one or more files to use for the user host key
|
||||
database, separated by whitespace. The default is
|
||||
<filename>~/.ssh/known_hosts</filename>.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -138,28 +249,84 @@ in
|
||||
|
||||
controlPath = mkOption {
|
||||
type = types.str;
|
||||
default = "~/.ssh/master-%r@%h:%p";
|
||||
default = "~/.ssh/master-%r@%n:%p";
|
||||
description = ''
|
||||
Specify path to the control socket used for connection sharing.
|
||||
'';
|
||||
};
|
||||
|
||||
matchBlocks = mkOption {
|
||||
type = types.listOf matchBlockModule;
|
||||
default = [];
|
||||
controlPersist = mkOption {
|
||||
type = types.str;
|
||||
default = "no";
|
||||
example = "10m";
|
||||
description = ''
|
||||
Specify per-host settings.
|
||||
Whether control socket should remain open in the background.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
extraOptionOverrides = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {};
|
||||
description = ''
|
||||
Extra SSH configuration options that take precedence over any
|
||||
host specific configuration.
|
||||
'';
|
||||
};
|
||||
|
||||
matchBlocks = mkOption {
|
||||
type = types.loaOf matchBlockModule;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
"john.example.com" = {
|
||||
hostname = "example.com";
|
||||
user = "john";
|
||||
};
|
||||
foo = {
|
||||
hostname = "example.com";
|
||||
identityFile = "/home/john/.ssh/foo_rsa";
|
||||
};
|
||||
};
|
||||
'';
|
||||
description = ''
|
||||
Specify per-host settings. Note, if the order of rules matter
|
||||
then this must be a list. See
|
||||
<citerefentry>
|
||||
<refentrytitle>ssh_config</refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
</citerefentry>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.file.".ssh/config".text = ''
|
||||
ForwardAgent ${yn cfg.forwardAgent}
|
||||
ControlMaster ${cfg.controlMaster}
|
||||
ControlPath ${cfg.controlPath}
|
||||
${concatStringsSep "\n" (
|
||||
mapAttrsToList (n: v: "${n} ${v}") cfg.extraOptionOverrides)}
|
||||
|
||||
${concatStringsSep "\n\n" (map matchBlockStr cfg.matchBlocks)}
|
||||
${concatStringsSep "\n\n" (
|
||||
map matchBlockStr (
|
||||
builtins.attrValues cfg.matchBlocks))}
|
||||
|
||||
Host *
|
||||
ForwardAgent ${yn cfg.forwardAgent}
|
||||
Compression ${yn cfg.compression}
|
||||
ServerAliveInterval ${toString cfg.serverAliveInterval}
|
||||
HashKnownHosts ${yn cfg.hashKnownHosts}
|
||||
UserKnownHostsFile ${cfg.userKnownHostsFile}
|
||||
ControlMaster ${cfg.controlMaster}
|
||||
ControlPath ${cfg.controlPath}
|
||||
ControlPersist ${cfg.controlPersist}
|
||||
|
||||
${replaceStrings ["\n"] ["\n "] cfg.extraConfig}
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
112
modules/programs/taskwarrior.nix
Normal file
112
modules/programs/taskwarrior.nix
Normal file
@@ -0,0 +1,112 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.taskwarrior;
|
||||
|
||||
themePath = theme: "${pkgs.taskwarrior}/share/doc/task/rc/${theme}.theme";
|
||||
|
||||
includeTheme = location:
|
||||
if location == null then ""
|
||||
else if isString location then "include ${themePath location}"
|
||||
else "include ${location}";
|
||||
|
||||
formatValue = value:
|
||||
if isBool value then if value then "true" else "false"
|
||||
else if isList value then concatMapStringsSep "," formatValue value
|
||||
else toString value;
|
||||
|
||||
formatLine = key: value:
|
||||
"${key}=${formatValue value}";
|
||||
|
||||
formatSet = key: values:
|
||||
(concatStringsSep "\n"
|
||||
(mapAttrsToList
|
||||
(subKey: subValue: formatPair "${key}.${subKey}" subValue)
|
||||
values));
|
||||
|
||||
formatPair = key: value:
|
||||
if isAttrs value then formatSet key value
|
||||
else formatLine key value;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.taskwarrior = {
|
||||
enable = mkEnableOption "Task Warrior";
|
||||
|
||||
config = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
example = literalExample ''
|
||||
{
|
||||
confirmation = false;
|
||||
report.minimal.filter = "status:pending";
|
||||
report.active.columns = [ "id" "start" "entry.age" "priority" "project" "due" "description" ];
|
||||
report.active.labels = [ "ID" "Started" "Age" "Priority" "Project" "Due" "Description" ];
|
||||
taskd = {
|
||||
certificate = "/path/to/cert";
|
||||
key = "/path/to/key";
|
||||
ca = "/path/to/ca";
|
||||
server = "host.domain:53589";
|
||||
credentials = "Org/First Last/cf31f287-ee9e-43a8-843e-e8bbd5de4294";
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Key-value configuration written to
|
||||
<filename>~/.taskrc</filename>.
|
||||
'';
|
||||
};
|
||||
|
||||
dataLocation = mkOption {
|
||||
type = types.str;
|
||||
default = "${config.xdg.dataHome}/task";
|
||||
defaultText = "$XDG_DATA_HOME/task";
|
||||
description = ''
|
||||
Location where Task Warrior will store its data.
|
||||
</para><para>
|
||||
Home Manager will attempt to create this directory.
|
||||
'';
|
||||
};
|
||||
|
||||
colorTheme = mkOption {
|
||||
type = with types; nullOr (either str path);
|
||||
default = null;
|
||||
example = "dark-blue-256";
|
||||
description = ''
|
||||
Either one of the default provided theme as string, or a
|
||||
path to a theme configuration file.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Additional content written at the end of
|
||||
<filename>~/.taskrc</filename>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [ pkgs.taskwarrior ];
|
||||
|
||||
home.file."${cfg.dataLocation}/.keep".text = "";
|
||||
|
||||
home.file.".taskrc".text = ''
|
||||
data.location=${cfg.dataLocation}
|
||||
${includeTheme cfg.colorTheme}
|
||||
|
||||
${concatStringsSep "\n" (
|
||||
mapAttrsToList formatPair cfg.config)}
|
||||
|
||||
${cfg.extraConfig}
|
||||
'';
|
||||
};
|
||||
}
|
||||
378
modules/programs/termite.nix
Normal file
378
modules/programs/termite.nix
Normal file
@@ -0,0 +1,378 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.programs.termite;
|
||||
|
||||
vteInitStr = ''
|
||||
# See https://github.com/thestinger/termite#id1
|
||||
if [[ $TERM == xterm-termite ]]; then
|
||||
. ${pkgs.gnome3.vte-ng}/etc/profile.d/vte.sh
|
||||
fi
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
programs.termite = {
|
||||
enable = mkEnableOption "Termite VTE-based terminal";
|
||||
|
||||
allowBold = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = ''
|
||||
Allow the output of bold characters when the bold escape sequence appears.
|
||||
'';
|
||||
};
|
||||
|
||||
audibleBell = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = "Have the terminal beep on the terminal bell.";
|
||||
};
|
||||
|
||||
clickableUrl = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = ''
|
||||
Auto-detected URLs can be clicked on to open them in your browser.
|
||||
Only enabled if a browser is configured or detected.
|
||||
'';
|
||||
};
|
||||
|
||||
dynamicTitle = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = ''
|
||||
Settings dynamic title allows the terminal and the shell to
|
||||
update the terminal's title.
|
||||
'';
|
||||
};
|
||||
|
||||
fullscreen = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = "Enables entering fullscreen mode by pressing F11.";
|
||||
};
|
||||
|
||||
mouseAutohide = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = "Automatically hide the mouse pointer when you start typing.";
|
||||
};
|
||||
|
||||
scrollOnOutput = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = "Scroll to the bottom when the shell generates output.";
|
||||
};
|
||||
|
||||
scrollOnKeystroke = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = "Scroll to the bottom automatically when a key is pressed.";
|
||||
};
|
||||
|
||||
searchWrap = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = "Search from top again when you hit the bottom.";
|
||||
};
|
||||
|
||||
urgentOnBell = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = "Sets the window as urgent on the terminal bell.";
|
||||
};
|
||||
|
||||
font = mkOption {
|
||||
default = null;
|
||||
example = "Monospace 12";
|
||||
type = types.nullOr types.str;
|
||||
description = "The font description for the terminal's font.";
|
||||
};
|
||||
|
||||
geometry = mkOption {
|
||||
default = null;
|
||||
example = "640x480";
|
||||
type = types.nullOr types.str;
|
||||
description = "The default window geometry for new terminal windows.";
|
||||
};
|
||||
|
||||
iconName = mkOption {
|
||||
default = null;
|
||||
example = "terminal";
|
||||
type = types.nullOr types.str;
|
||||
description = "The name of the icon to be used for the terminal process.";
|
||||
};
|
||||
|
||||
scrollbackLines = mkOption {
|
||||
default = null;
|
||||
example = 10000;
|
||||
type = types.nullOr types.int;
|
||||
description = "Set the number of lines to limit the terminal's scrollback.";
|
||||
};
|
||||
|
||||
browser = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.str;
|
||||
example = "${pkgs.xdg_utils}/xdg-open";
|
||||
description = ''
|
||||
Set the default browser for opening links. If its not set, $BROWSER is read.
|
||||
If that's not set, url hints will be disabled.
|
||||
'';
|
||||
};
|
||||
|
||||
cursorBlink = mkOption {
|
||||
default = null;
|
||||
example = "system";
|
||||
type = types.nullOr (types.enum [ "system" "on" "off" ]);
|
||||
description = ''
|
||||
Specify the how the terminal's cursor should behave.
|
||||
Accepts system to respect the gtk global configuration,
|
||||
on and off to explicitly enable or disable them.
|
||||
'';
|
||||
};
|
||||
|
||||
cursorShape = mkOption {
|
||||
default = null;
|
||||
example = "block";
|
||||
type = types.nullOr (types.enum [ "block" "underline" "ibeam" ]);
|
||||
description = ''
|
||||
Specify how the cursor should look. Accepts block, ibeam and underline.
|
||||
'';
|
||||
};
|
||||
|
||||
filterUnmatchedUrls = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = "Whether to hide url hints not matching input in url hints mode.";
|
||||
};
|
||||
|
||||
modifyOtherKeys = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = ''
|
||||
Emit escape sequences for extra keys,
|
||||
like the modifyOtherKeys resource for
|
||||
<citerefentry>
|
||||
<refentrytitle>xterm</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</citerefentry>.
|
||||
'';
|
||||
};
|
||||
|
||||
sizeHints = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.bool;
|
||||
description = ''
|
||||
Enable size hints. Locks the terminal resizing
|
||||
to increments of the terminal's cell size.
|
||||
Requires a window manager that respects scroll hints.
|
||||
'';
|
||||
};
|
||||
|
||||
scrollbar = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr (types.enum [ "off" "left" "right" ]);
|
||||
description = "Scroll to the bottom when the shell generates output.";
|
||||
};
|
||||
|
||||
backgroundColor = mkOption {
|
||||
default = null;
|
||||
example = "rgba(63, 63, 63, 0.8)";
|
||||
type = types.nullOr types.str;
|
||||
description = "Background color value.";
|
||||
};
|
||||
|
||||
cursorColor = mkOption {
|
||||
default = null;
|
||||
example = "#dcdccc";
|
||||
type = types.nullOr types.str;
|
||||
description = "Cursor color value.";
|
||||
};
|
||||
|
||||
cursorForegroundColor = mkOption {
|
||||
default = null;
|
||||
example = "#dcdccc";
|
||||
type = types.nullOr types.str;
|
||||
description = "Cursor foreground color value.";
|
||||
};
|
||||
|
||||
foregroundColor = mkOption {
|
||||
default = null;
|
||||
example = "#dcdccc";
|
||||
type = types.nullOr types.str;
|
||||
description = "Foreground color value.";
|
||||
};
|
||||
|
||||
foregroundBoldColor = mkOption {
|
||||
default = null;
|
||||
example = "#ffffff";
|
||||
type = types.nullOr types.str;
|
||||
description = "Foreground bold color value.";
|
||||
};
|
||||
|
||||
highlightColor = mkOption {
|
||||
default = null;
|
||||
example = "#2f2f2f";
|
||||
type = types.nullOr types.str;
|
||||
description = "highlight color value.";
|
||||
};
|
||||
|
||||
hintsActiveBackgroundColor = mkOption {
|
||||
default = null;
|
||||
example = "#3f3f3f";
|
||||
type = types.nullOr types.str;
|
||||
description = "Hints active background color value.";
|
||||
};
|
||||
|
||||
hintsActiveForegroundColor = mkOption {
|
||||
default = null;
|
||||
example = "#e68080";
|
||||
type = types.nullOr types.str;
|
||||
description = "Hints active foreground color value.";
|
||||
};
|
||||
|
||||
hintsBackgroundColor = mkOption {
|
||||
default = null;
|
||||
example = "#3f3f3f";
|
||||
type = types.nullOr types.str;
|
||||
description = "Hints background color value.";
|
||||
};
|
||||
|
||||
hintsForegroundColor = mkOption {
|
||||
default = null;
|
||||
example = "#dcdccc";
|
||||
type = types.nullOr types.str;
|
||||
description = "Hints foreground color value.";
|
||||
};
|
||||
|
||||
hintsBorderColor = mkOption {
|
||||
default = null;
|
||||
example = "#3f3f3f";
|
||||
type = types.nullOr types.str;
|
||||
description = "Hints border color value.";
|
||||
};
|
||||
|
||||
hintsBorderWidth = mkOption {
|
||||
default = null;
|
||||
example = "0.5";
|
||||
type = types.nullOr types.str;
|
||||
description = "Hints border width.";
|
||||
};
|
||||
|
||||
hintsFont = mkOption {
|
||||
default = null;
|
||||
example = "Monospace 12";
|
||||
type = types.nullOr types.str;
|
||||
description = "The font description for the hints font.";
|
||||
};
|
||||
|
||||
hintsPadding = mkOption {
|
||||
default = null;
|
||||
example = 2;
|
||||
type = types.nullOr types.int;
|
||||
description = "Hints padding.";
|
||||
};
|
||||
|
||||
hintsRoundness = mkOption {
|
||||
default = null;
|
||||
example = "0.2";
|
||||
type = types.nullOr types.str;
|
||||
description = "Hints roundness.";
|
||||
};
|
||||
|
||||
optionsExtra = mkOption {
|
||||
default = "";
|
||||
example = "fullscreen = true";
|
||||
type = types.lines;
|
||||
description = "Extra options that should be added to [options] section.";
|
||||
};
|
||||
|
||||
colorsExtra = mkOption {
|
||||
default = "";
|
||||
example = ''
|
||||
color0 = #3f3f3f
|
||||
color1 = #705050
|
||||
color2 = #60b48a
|
||||
'';
|
||||
type = types.lines;
|
||||
description = "Extra colors options that should be added to [colors] section.";
|
||||
};
|
||||
|
||||
hintsExtra = mkOption {
|
||||
default = "";
|
||||
example = "border = #3f3f3f";
|
||||
type = types.lines;
|
||||
description = "Extra hints options that should be added to [hints] section.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = (
|
||||
let
|
||||
boolToString = v: if v then "true" else "false";
|
||||
optionalBoolean = name: val: lib.optionalString (val != null) "${name} = ${boolToString val}";
|
||||
optionalInteger = name: val: lib.optionalString (val != null) "${name} = ${toString val}";
|
||||
optionalString = name: val: lib.optionalString (val != null) "${name} = ${val}";
|
||||
in mkIf cfg.enable {
|
||||
home.packages = [ pkgs.termite ];
|
||||
xdg.configFile."termite/config".text = ''
|
||||
[options]
|
||||
${optionalBoolean "allow_bold" cfg.allowBold}
|
||||
${optionalBoolean "audible_bell" cfg.audibleBell}
|
||||
${optionalString "browser" cfg.browser}
|
||||
${optionalBoolean "clickable_url" cfg.clickableUrl}
|
||||
${optionalString "cursor_blink" cfg.cursorBlink}
|
||||
${optionalString "cursor_shape" cfg.cursorShape}
|
||||
${optionalBoolean "dynamic_title" cfg.dynamicTitle}
|
||||
${optionalBoolean "filter_unmatched_urls" cfg.filterUnmatchedUrls}
|
||||
${optionalString "font" cfg.font}
|
||||
${optionalBoolean "fullscreen" cfg.fullscreen}
|
||||
${optionalString "geometry" cfg.geometry}
|
||||
${optionalString "icon_name" cfg.iconName}
|
||||
${optionalBoolean "modify_other_keys" cfg.modifyOtherKeys}
|
||||
${optionalBoolean "mouse_autohide" cfg.mouseAutohide}
|
||||
${optionalBoolean "scroll_on_keystroke" cfg.scrollOnKeystroke}
|
||||
${optionalBoolean "scroll_on_output" cfg.scrollOnOutput}
|
||||
${optionalInteger "scrollback_lines" cfg.scrollbackLines}
|
||||
${optionalString "scrollbar" cfg.scrollbar}
|
||||
${optionalBoolean "search_wrap" cfg.searchWrap}
|
||||
${optionalBoolean "size_hints" cfg.sizeHints}
|
||||
${optionalBoolean "urgent_on_bell" cfg.urgentOnBell}
|
||||
|
||||
${cfg.optionsExtra}
|
||||
|
||||
[colors]
|
||||
${optionalString "background" cfg.backgroundColor}
|
||||
${optionalString "cursor" cfg.cursorColor}
|
||||
${optionalString "cursor_foreground" cfg.cursorForegroundColor}
|
||||
${optionalString "foreground" cfg.foregroundColor}
|
||||
${optionalString "foregroundBold" cfg.foregroundBoldColor}
|
||||
${optionalString "highlight" cfg.highlightColor}
|
||||
|
||||
${cfg.colorsExtra}
|
||||
|
||||
[hints]
|
||||
${optionalString "active_background" cfg.hintsActiveBackgroundColor}
|
||||
${optionalString "active_foreground" cfg.hintsActiveForegroundColor}
|
||||
${optionalString "background" cfg.hintsBackgroundColor}
|
||||
${optionalString "border" cfg.hintsBorderColor}
|
||||
${optionalInteger "border_width" cfg.hintsBorderWidth}
|
||||
${optionalString "font" cfg.hintsFont}
|
||||
${optionalString "foreground" cfg.hintsForegroundColor}
|
||||
${optionalInteger "padding" cfg.hintsPadding}
|
||||
${optionalInteger "roundness" cfg.hintsRoundness}
|
||||
|
||||
${cfg.hintsExtra}
|
||||
'';
|
||||
|
||||
programs.bash.initExtra = vteInitStr;
|
||||
programs.zsh.initExtra = vteInitStr;
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -6,27 +6,45 @@ let
|
||||
|
||||
cfg = config.programs.texlive;
|
||||
|
||||
texlivePkgs = cfg.extraPackages pkgs.texlive;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = [ maintainers.rycee ];
|
||||
|
||||
options = {
|
||||
programs.texlive = {
|
||||
enable = mkEnableOption "Texlive";
|
||||
|
||||
extraPackages = mkOption {
|
||||
default = self: {};
|
||||
default = tpkgs: { inherit (tpkgs) collection-basic; };
|
||||
defaultText = "tpkgs: { inherit (tpkgs) collection-basic; }";
|
||||
example = literalExample ''
|
||||
tpkgs: { inherit (tpkgs) collection-fontsrecommended algorithms; }
|
||||
'';
|
||||
description = "Extra packages available to Texlive.";
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
description = "Resulting customized Texlive package.";
|
||||
readOnly = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = [
|
||||
(pkgs.texlive.combine (cfg.extraPackages pkgs.texlive))
|
||||
assertions = [
|
||||
{
|
||||
assertion = texlivePkgs != {};
|
||||
message = "Must provide at least one extra package in"
|
||||
+ " 'programs.texlive.extraPackages'.";
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
programs.texlive.package = pkgs.texlive.combine texlivePkgs;
|
||||
};
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user