mirror of
https://github.com/nix-community/home-manager.git
synced 2026-01-11 09:29:41 +08:00
Compare commits
202 Commits
backport/r
...
4fee4bd14b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fee4bd14b | ||
|
|
c068188a8e | ||
|
|
bdaa374383 | ||
|
|
d28cc9f4a6 | ||
|
|
a97b0a0999 | ||
|
|
a4a571c2d6 | ||
|
|
aea57993a8 | ||
|
|
1c7be243ea | ||
|
|
93da26b426 | ||
|
|
0d3183953c | ||
|
|
4e8b7bef66 | ||
|
|
6e94d8157c | ||
|
|
6e3931c01f | ||
|
|
c91dbdf61a | ||
|
|
38e187fd2f | ||
|
|
9bfca5b3a7 | ||
|
|
bfaba198af | ||
|
|
b1421bdfe5 | ||
|
|
4cd7ae4cd4 | ||
|
|
e43f7c3321 | ||
|
|
6841643203 | ||
|
|
a755d94ab0 | ||
|
|
33fe25dbe5 | ||
|
|
337d3602c0 | ||
|
|
5d814af6af | ||
|
|
787784fb6f | ||
|
|
2379f704b0 | ||
|
|
a26335db1b | ||
|
|
d016674f6a | ||
|
|
c2d3a75ebe | ||
|
|
93af99ec02 | ||
|
|
c8b68aafed | ||
|
|
bca7415de4 | ||
|
|
d070d83048 | ||
|
|
048104c098 | ||
|
|
af894fbbc7 | ||
|
|
53084c95ce | ||
|
|
a65c04965c | ||
|
|
c4eabb884b | ||
|
|
156b698b75 | ||
|
|
9d1c71f390 | ||
|
|
47e195783e | ||
|
|
f894bc4ffd | ||
|
|
73f5a5ecc9 | ||
|
|
7d5927b63c | ||
|
|
8f7d6bacb6 | ||
|
|
12cc14271b | ||
|
|
c211298f7e | ||
|
|
1cfa305fba | ||
|
|
3e87b442b5 | ||
|
|
99a037de18 | ||
|
|
3b3164dfe3 | ||
|
|
bc43546503 | ||
|
|
78a8fae57f | ||
|
|
b558d54215 | ||
|
|
9ef24320f1 | ||
|
|
18f9d668aa | ||
|
|
2f06b72606 | ||
|
|
d4e4d5cfa3 | ||
|
|
e4e78a2cbe | ||
|
|
ae1ea768ef | ||
|
|
365cbc13c4 | ||
|
|
d99b4ca5de | ||
|
|
64f4dadb80 | ||
|
|
7a7b43c723 | ||
|
|
a84cccefd4 | ||
|
|
9d32c214db | ||
|
|
87785ddbc7 | ||
|
|
113b155fe8 | ||
|
|
398bc87bc8 | ||
|
|
3613abcbd7 | ||
|
|
d7e794fe12 | ||
|
|
8969535f1c | ||
|
|
80cca72314 | ||
|
|
d2e0458d65 | ||
|
|
b3ae822959 | ||
|
|
d761c0ce89 | ||
|
|
f84f474c1b | ||
|
|
ea6dfabe3c | ||
|
|
5432dc5bc4 | ||
|
|
bec08ef6e3 | ||
|
|
4067ca1ffb | ||
|
|
2d36a6de2f | ||
|
|
91cdb0e2d5 | ||
|
|
7eca7f7081 | ||
|
|
20728df08f | ||
|
|
af3c24de76 | ||
|
|
624c7e80fb | ||
|
|
9c790e687e | ||
|
|
527ad07e66 | ||
|
|
57a02fd7d9 | ||
|
|
3fe66908e0 | ||
|
|
61fcc9de76 | ||
|
|
7b73a6e98f | ||
|
|
4dc3c91c50 | ||
|
|
a7d6bba358 | ||
|
|
bdb807dc28 | ||
|
|
0a583021ea | ||
|
|
ab01ea24b2 | ||
|
|
c764a377a0 | ||
|
|
28b3622b80 | ||
|
|
c848303f1e | ||
|
|
bb35f07cc9 | ||
|
|
9bf54edf10 | ||
|
|
89c9508bbe | ||
|
|
22202ff0d8 | ||
|
|
09de9577d4 | ||
|
|
f575cb24f6 | ||
|
|
3a92ffa192 | ||
|
|
6cdf765eed | ||
|
|
8315c1544f | ||
|
|
58bf3ecb2d | ||
|
|
d787ec69c3 | ||
|
|
07d79726f1 | ||
|
|
4767a9c719 | ||
|
|
39cb677ed9 | ||
|
|
0cf525a5be | ||
|
|
9b5ac85d79 | ||
|
|
574f6d3526 | ||
|
|
e52be4fb78 | ||
|
|
dd18018d06 | ||
|
|
7b34e428f3 | ||
|
|
af7c726e8b | ||
|
|
13cc1efd78 | ||
|
|
e5b1f87841 | ||
|
|
caa47b637d | ||
|
|
a788734077 | ||
|
|
6bdf2a68e1 | ||
|
|
f9d45d664e | ||
|
|
082822b8a6 | ||
|
|
27a6182347 | ||
|
|
012cfcc44a | ||
|
|
36817384a6 | ||
|
|
571c5eed1d | ||
|
|
2e02e22e28 | ||
|
|
ccd22c13b2 | ||
|
|
519828bf1c | ||
|
|
1a99a515a1 | ||
|
|
6bcb2395ab | ||
|
|
f16bfa59e3 | ||
|
|
35545f71dd | ||
|
|
6bbc48804b | ||
|
|
a8b6296a1e | ||
|
|
68f7b34179 | ||
|
|
24cc5c080c | ||
|
|
df7bac2b2b | ||
|
|
05a56dbf24 | ||
|
|
9379fbf4f5 | ||
|
|
a521eab881 | ||
|
|
2f93d7333e | ||
|
|
d441981b20 | ||
|
|
fca4cba863 | ||
|
|
af324afa72 | ||
|
|
12e7786854 | ||
|
|
28741978a3 | ||
|
|
43173abcb4 | ||
|
|
bcc7afa1d8 | ||
|
|
281e9398cc | ||
|
|
93d907a205 | ||
|
|
eca5f967cd | ||
|
|
db44f38047 | ||
|
|
06f81463bb | ||
|
|
ab8e4b2b5a | ||
|
|
c3d1e5c65a | ||
|
|
bf003999ed | ||
|
|
ff067cfc61 | ||
|
|
effe4c007d | ||
|
|
6cedf24ada | ||
|
|
e4e25a8c31 | ||
|
|
13b089b586 | ||
|
|
784a83782c | ||
|
|
704b6ffa8a | ||
|
|
83053e1d33 | ||
|
|
ae400a1dcc | ||
|
|
edbb012a21 | ||
|
|
b1bb534c17 | ||
|
|
780be8ef50 | ||
|
|
40c18076d8 | ||
|
|
d13041d6f0 | ||
|
|
ae9f38e889 | ||
|
|
86ff0ef506 | ||
|
|
c220f242cd | ||
|
|
1ed596c638 | ||
|
|
9f31ea236b | ||
|
|
b414c94d4e | ||
|
|
5b8d259ee6 | ||
|
|
29b672194d | ||
|
|
f302550865 | ||
|
|
23f2ba7ae0 | ||
|
|
470d24d809 | ||
|
|
740134d4af | ||
|
|
c23379a330 | ||
|
|
9651819d75 | ||
|
|
8220473f95 | ||
|
|
946907fa6a | ||
|
|
201c883d0d | ||
|
|
cc0425becf | ||
|
|
ee7f4646da | ||
|
|
ad0b497533 | ||
|
|
089d5bf615 | ||
|
|
4d5fbb182e | ||
|
|
8433591183 |
3
.github/dependabot.yml
vendored
3
.github/dependabot.yml
vendored
@@ -7,10 +7,9 @@ updates:
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: "ci:"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "release-25.05"
|
||||
target-branch: "release-25.11"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
|
||||
2
.github/workflows/backport.yml
vendored
2
.github/workflows/backport.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Create backport PRs
|
||||
id: backport
|
||||
uses: korthout/backport-action@v3
|
||||
uses: korthout/backport-action@v4
|
||||
with:
|
||||
# See https://github.com/korthout/backport-action#inputs
|
||||
github_token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
|
||||
|
||||
5
.github/workflows/update-flake.yml
vendored
5
.github/workflows/update-flake.yml
vendored
@@ -9,8 +9,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'schedule' || github.repository_owner == 'nix-community'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: [master, release-25.05]
|
||||
branch: [master, release-25.11]
|
||||
steps:
|
||||
- name: Create GitHub App token
|
||||
uses: actions/create-github-app-token@v2
|
||||
@@ -41,7 +42,7 @@ jobs:
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v31
|
||||
- name: Update flake.lock
|
||||
uses: DeterminateSystems/update-flake-lock@v27
|
||||
uses: DeterminateSystems/update-flake-lock@v28
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }}
|
||||
git-committer-name: ${{ steps.user-info.outputs.name || 'github-actions[bot]' }}
|
||||
|
||||
@@ -121,6 +121,22 @@ Reference commits:
|
||||
- Change `isReleaseBranch` from `false` to `true`
|
||||
- Do NOT change the `release` field (it's already correct from Step 1)
|
||||
|
||||
2. **flake.nix**
|
||||
- Update the nixpkgs input to track the corresponding stable branch
|
||||
- Example: For `release-25.11`, change from:
|
||||
```nix
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
```
|
||||
to:
|
||||
```nix
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
|
||||
```
|
||||
- Run `nix flake update` to update flake.lock to the stable branch
|
||||
- Commit the flake.nix and flake.lock changes
|
||||
|
||||
**Note**: The release branch should track the stable NixOS release channel
|
||||
(e.g., `nixos-25.11`), while master continues to track `nixos-unstable`.
|
||||
|
||||
#### Step 3.5: On master - Update CI for the New Release Branch
|
||||
|
||||
**When**: After marking the release branch as a release branch (Step 3)
|
||||
@@ -150,6 +166,37 @@ Reference commits:
|
||||
- This ensures automated flake.lock updates run on the current stable branch
|
||||
- Note: We only maintain CI for the latest stable release, not older releases
|
||||
|
||||
2. **.github/dependabot.yml** (on master)
|
||||
- Replace the old stable branch with the new release branch
|
||||
- Example: When creating `release-25.11`, update the target-branch from:
|
||||
|
||||
```yaml
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "release-25.05"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: "ci:"
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```yaml
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
target-branch: "release-25.11"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: "ci:"
|
||||
```
|
||||
|
||||
- This ensures automated dependency updates for GitHub Actions on the current
|
||||
stable branch
|
||||
- Note: We only maintain dependabot for the latest stable release, not older
|
||||
releases
|
||||
|
||||
**Important**: CI workflows are executed from master, so this change must be
|
||||
committed to the master branch.
|
||||
|
||||
|
||||
@@ -361,6 +361,11 @@
|
||||
email = "nixpkgs@perchun.it";
|
||||
github = "PerchunPak";
|
||||
githubId = 68118654;
|
||||
keys = [
|
||||
{
|
||||
fingerprint = "BBB5 1142 959D 8549 A3D2 F6C5 313F 67D1 EAB7 70F9";
|
||||
}
|
||||
];
|
||||
name = "Perchun Pak";
|
||||
source = "nixpkgs";
|
||||
};
|
||||
@@ -629,6 +634,13 @@
|
||||
name = "Arjan Schrijver";
|
||||
source = "nixpkgs";
|
||||
};
|
||||
arunoruto = {
|
||||
email = "mirza.arnaut45@gmail.com";
|
||||
github = "arunoruto";
|
||||
githubId = 21687187;
|
||||
name = "Mirza Arnaut";
|
||||
source = "nixpkgs";
|
||||
};
|
||||
asymmetric = {
|
||||
email = "lorenzo@mailbox.org";
|
||||
github = "asymmetric";
|
||||
@@ -1085,19 +1097,6 @@
|
||||
name = "Hoang Nguyen";
|
||||
source = "home-manager";
|
||||
};
|
||||
foo-dogsquared = {
|
||||
email = "foodogsquared@foodogsquared.one";
|
||||
github = "foo-dogsquared";
|
||||
githubId = 34962634;
|
||||
keys = [
|
||||
{
|
||||
fingerprint = "DDD7 D0BD 602E 564B AA04 FC35 1431 0D91 4115 2B92";
|
||||
}
|
||||
];
|
||||
matrix = "@foodogsquared:matrix.org";
|
||||
name = "Gabriel Arazas";
|
||||
source = "nixpkgs";
|
||||
};
|
||||
fpob = {
|
||||
email = "fpob@proton.me";
|
||||
github = "fpob";
|
||||
@@ -2066,7 +2065,7 @@
|
||||
source = "nixpkgs";
|
||||
};
|
||||
shikanime = {
|
||||
email = "deva.shikanime@protonmail.com";
|
||||
email = "william.phetsinorath@shikanime.studio";
|
||||
github = "shikanime";
|
||||
githubId = 22115108;
|
||||
name = "William Phetsinorath";
|
||||
@@ -2304,6 +2303,13 @@
|
||||
name = "Florian Peter";
|
||||
source = "nixpkgs";
|
||||
};
|
||||
xavwe = {
|
||||
email = "git@xavwe.dev";
|
||||
github = "xavwe";
|
||||
githubId = 125409009;
|
||||
name = "Xaver Wenhart";
|
||||
source = "nixpkgs";
|
||||
};
|
||||
xlambein = {
|
||||
email = "xlambein@gmail.com";
|
||||
github = "xlambein";
|
||||
|
||||
6
docs/flake.lock
generated
6
docs/flake.lock
generated
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1743938762,
|
||||
"narHash": "sha256-UgFYn8sGv9B8PoFpUfCa43CjMZBl1x/ShQhRDHBFQdI=",
|
||||
"lastModified": 1764081664,
|
||||
"narHash": "sha256-sUoHmPr/EwXzRMpv1u/kH+dXuvJEyyF2Q7muE+t0EU4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "74a40410369a1c35ee09b8a1abee6f4acbedc059",
|
||||
"rev": "dc205f7b4fdb04c8b7877b43edb7b73be7730081",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Home Manager Manual {#home-manager-manual}
|
||||
|
||||
## Version 25.11
|
||||
## Version 26.05 (unstable)
|
||||
|
||||
|
||||
```{=include=} preface
|
||||
|
||||
@@ -4,6 +4,7 @@ This section lists the release notes for stable versions of Home Manager
|
||||
and the current unstable version.
|
||||
|
||||
```{=include=} chapters
|
||||
rl-2605.md
|
||||
rl-2511.md
|
||||
rl-2505.md
|
||||
rl-2411.md
|
||||
|
||||
@@ -57,3 +57,9 @@ changes are only active if the `home.stateVersion` option is set to
|
||||
|
||||
now default to `true` which is consistent with the default values
|
||||
for those options used by `i3` and `sway`.
|
||||
|
||||
- The [](#opt-programs.swaylock.enable) option now defaults to `false`
|
||||
and must be explicitly enabled. Previously, it would be implicitly
|
||||
enabled when `programs.swaylock.settings` was non-empty. Users with
|
||||
`home.stateVersion` set to earlier versions will continue to get the
|
||||
old implicit behavior.
|
||||
|
||||
@@ -27,4 +27,8 @@ The state version in this release includes the changes below. These
|
||||
changes are only active if the `home.stateVersion` option is set to
|
||||
\"25.05\" or later.
|
||||
|
||||
- No changes.
|
||||
- The [](#opt-programs.git.signing.format) option no longer defaults to
|
||||
`"openpgp"`. Users who use Git signing with GPG should explicitly set
|
||||
this option to `"openpgp"` to maintain the previous behavior. Users
|
||||
with `home.stateVersion` set to earlier versions will continue to get
|
||||
the `"openpgp"` default for backwards compatibility.
|
||||
|
||||
@@ -80,3 +80,10 @@ changes are only active if the `home.stateVersion` option is set to
|
||||
`{ PASSWORD_STORE_DIR = $XDG_DATA_HOME/password-store; }` anymore by its
|
||||
default value. This will revert to the default behaviour of the program,
|
||||
namely `$HOME/.password-store` to be used as the store path.
|
||||
|
||||
- On macOS, [](#opt-targets.darwin.copyApps.enable) is now enabled by
|
||||
default instead of [](#opt-targets.darwin.linkApps.enable). This means
|
||||
applications from `home.packages` will be copied to
|
||||
`~/Applications/Home Manager Apps` rather than symlinked, making them
|
||||
work properly with Spotlight. Users with `home.stateVersion` set to
|
||||
earlier versions will continue to use `linkApps` by default.
|
||||
|
||||
25
docs/release-notes/rl-2605.md
Normal file
25
docs/release-notes/rl-2605.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Release 26.05 {#sec-release-26.05}
|
||||
|
||||
This is the current unstable branch and the information in this
|
||||
section is therefore not final.
|
||||
|
||||
## Highlights {#sec-release-26.05-highlights}
|
||||
|
||||
This release has the following notable changes:
|
||||
|
||||
- The [](#opt-programs.anki.uiScale) option now expects a value in the
|
||||
range 1.0–2.0, previously it erroneously expected values in the
|
||||
range `0.0–1.0`.
|
||||
|
||||
## State Version Changes {#sec-release-26.05-state-version-changes}
|
||||
|
||||
The state version in this release includes the changes below. These
|
||||
changes are only active if the `home.stateVersion` option is set to
|
||||
\"26.05\" or later.
|
||||
|
||||
- The [](#opt-gtk.gtk4.theme) option does not mirror
|
||||
[](#opt-gtk.theme) by default anymore.
|
||||
|
||||
- The [](#opt-programs.zsh.dotDir) option now defaults to the XDG
|
||||
configuration directory (usually `~/.config/zsh`) when
|
||||
[](#opt-xdg.enable) is true.
|
||||
6
flake.lock
generated
6
flake.lock
generated
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1763678758,
|
||||
"narHash": "sha256-+hBiJ+kG5IoffUOdlANKFflTT5nO3FrrR2CA3178Y5s=",
|
||||
"lastModified": 1767640445,
|
||||
"narHash": "sha256-UWYqmD7JFBEDBHWYcqE6s6c77pWdcU/i+bwD6XxMb8A=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "117cc7f94e8072499b0a7aa4c52084fa4e11cc9b",
|
||||
"rev": "9f0c42f8bc7151b8e7e5840fb3bd454ad850d8c5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -1277,7 +1277,7 @@ while [[ $# -gt 0 ]]; do
|
||||
export VERBOSE=1
|
||||
;;
|
||||
--version)
|
||||
echo 25.11-pre
|
||||
echo 26.05-pre
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: Home Manager\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
|
||||
"POT-Creation-Date: 2025-07-22 10:59+0200\n"
|
||||
"PO-Revision-Date: 2025-08-23 20:02+0000\n"
|
||||
"PO-Revision-Date: 2025-11-30 14:00+0000\n"
|
||||
"Last-Translator: Brian E <brianellingsgaard9@gmail.com>\n"
|
||||
"Language-Team: Faroese <https://hosted.weblate.org/projects/home-manager/cli/"
|
||||
"fo/>\n"
|
||||
@@ -17,12 +17,12 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.13\n"
|
||||
"X-Generator: Weblate 5.15-dev\n"
|
||||
|
||||
#. translators: For example: "home-manager: missing argument for --cores"
|
||||
#: home-manager/home-manager:16
|
||||
msgid "%s: missing argument for %s"
|
||||
msgstr ""
|
||||
msgstr "%s: manglar eitt ávirki fyri %s"
|
||||
|
||||
#. translators: For example: "home-manager: --rollback can only be used after switch"
|
||||
#: home-manager/home-manager:22
|
||||
@@ -31,7 +31,7 @@ msgstr "%s: %s kann bert brúkast aftaná %s"
|
||||
|
||||
#: home-manager/home-manager:71
|
||||
msgid "No configuration file found at %s"
|
||||
msgstr ""
|
||||
msgstr "Eingin samansetingsfíla funni hjá %s"
|
||||
|
||||
#. translators: The first '%s' specifier will be replaced by either
|
||||
#. 'home.nix' or 'flake.nix'.
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: Home Manager\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
|
||||
"POT-Creation-Date: 2025-07-22 10:59+0200\n"
|
||||
"PO-Revision-Date: 2025-03-07 18:58+0000\n"
|
||||
"Last-Translator: 807 <s10855168@gmail.com>\n"
|
||||
"PO-Revision-Date: 2025-12-04 09:16+0000\n"
|
||||
"Last-Translator: \"Urocissa Caerulea.Tw\" <urocissa.tw@proton.me>\n"
|
||||
"Language-Team: Chinese (Traditional Han script) <https://hosted.weblate.org/"
|
||||
"projects/home-manager/cli/zh_Hant/>\n"
|
||||
"Language: zh_Hant\n"
|
||||
@@ -17,21 +17,21 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Weblate 5.10.3-dev\n"
|
||||
"X-Generator: Weblate 5.15-dev\n"
|
||||
|
||||
#. translators: For example: "home-manager: missing argument for --cores"
|
||||
#: home-manager/home-manager:16
|
||||
msgid "%s: missing argument for %s"
|
||||
msgstr "%s: 缺少參數 %s"
|
||||
msgstr "%s:缺少 %s 的引數"
|
||||
|
||||
#. translators: For example: "home-manager: --rollback can only be used after switch"
|
||||
#: home-manager/home-manager:22
|
||||
msgid "%s: %s can only be used after %s"
|
||||
msgstr ""
|
||||
msgstr "%s:%s 只能在 %s 之後使用"
|
||||
|
||||
#: home-manager/home-manager:71
|
||||
msgid "No configuration file found at %s"
|
||||
msgstr "未在 %s 處找到配置檔案"
|
||||
msgstr "在 %s 找不到設定檔"
|
||||
|
||||
#. translators: The first '%s' specifier will be replaced by either
|
||||
#. 'home.nix' or 'flake.nix'.
|
||||
@@ -41,12 +41,12 @@ msgid ""
|
||||
"Keeping your Home Manager %s in %s is deprecated,\n"
|
||||
"please move it to %s"
|
||||
msgstr ""
|
||||
"保持你的 Home Manager 在 %s 中,%s 已被拋棄,\n"
|
||||
"請將它移動到 %s"
|
||||
"將 Home Manager 的 %s 放在 %s 中, 已經被棄用,\n"
|
||||
"請改放到 %s"
|
||||
|
||||
#: home-manager/home-manager:99
|
||||
msgid "No configuration file found. Please create one at %s"
|
||||
msgstr "未找到配置檔案。請在 %s 處建立一份"
|
||||
msgstr "找不到設定檔。請在 %s 建立新的設定檔"
|
||||
|
||||
#: home-manager/home-manager:114
|
||||
msgid "Home Manager not found at %s."
|
||||
@@ -57,7 +57,7 @@ msgstr "在 %s 中找不到 Home Manager。"
|
||||
msgid ""
|
||||
"The fallback Home Manager path %s has been deprecated and a file/directory "
|
||||
"was found there."
|
||||
msgstr "備用的 Home Manager 路徑 %s 已被拋棄,但一個檔案/資料夾在這被找到。"
|
||||
msgstr "備用的 Home Manager 路徑 %s 已被棄用,且在該處找到了檔案/目錄。"
|
||||
|
||||
#. translators: This message will be seen by very few users that likely are familiar with English. So feel free to leave this untranslated.
|
||||
#: home-manager/home-manager:125
|
||||
@@ -80,21 +80,21 @@ msgid ""
|
||||
"\n"
|
||||
" $ rm -r \"%s\""
|
||||
msgstr ""
|
||||
"要消除這個警告,請做以下其中一步。\n"
|
||||
"若要移除此警告,請執行下列其中一項。\n"
|
||||
"\n"
|
||||
"1. 告訴Home Manager去使用路徑,例如加入\n"
|
||||
"1. 明確告知 Home Manager 使用該路徑,例如在\n"
|
||||
"\n"
|
||||
" { programs.home-manager.path = \"%s\"; }\n"
|
||||
"\n"
|
||||
" 到你的配置中。\n"
|
||||
" 中,加入您的設定。\n"
|
||||
"\n"
|
||||
" 如果你想要直接引入Home Manager, 請你使用 `path` 參數r\n"
|
||||
" 如果想直接匯入 Home Manager,可以在呼叫時使用 `path` 參數來指定路徑:\n"
|
||||
"\n"
|
||||
" pkgs.callPackage /path/to/home-manager-package { path = \"%s\"; }\n"
|
||||
"\n"
|
||||
" 當呼叫 Home Manager 模組。\n"
|
||||
" 這樣就能正確傳遞 Home Manager 的路徑。\n"
|
||||
"\n"
|
||||
"2. 刪除無效的路徑\n"
|
||||
"2. 移除已棄用的路徑。\n"
|
||||
"\n"
|
||||
" $ rm -r \"%s\""
|
||||
|
||||
@@ -104,33 +104,33 @@ msgstr "正在進行 Nix 完整性檢查"
|
||||
|
||||
#: home-manager/home-manager:173
|
||||
msgid "Could not find suitable profile directory, tried %s and %s"
|
||||
msgstr "找不到合適的 profile 目錄,已經嘗試 %s 和 %s"
|
||||
msgstr "找不到合適的設定檔目錄,已嘗試 %s 和 %s"
|
||||
|
||||
#. translators: Here "flake" is a noun that refers to the Nix Flakes feature.
|
||||
#: home-manager/home-manager:230
|
||||
msgid "Can't inspect options of a flake configuration"
|
||||
msgstr "無法檢查 flake 配置中的選項"
|
||||
msgstr "無法檢查 flake 設定的選項"
|
||||
|
||||
#: home-manager/home-manager:305 home-manager/home-manager:328
|
||||
#: home-manager/home-manager:734 home-manager/home-manager:1237
|
||||
msgid "%s: unknown option '%s'"
|
||||
msgstr "%s:未知選項 ‘%s’"
|
||||
msgstr "%s:未知選項 '%s'"
|
||||
|
||||
#: home-manager/home-manager:310 home-manager/home-manager:1238
|
||||
msgid "Run '%s --help' for usage help"
|
||||
msgstr "執行 ‘%s --help’ 獲取用法幫助"
|
||||
msgstr "執行 '%s --help' 以取得使用說明"
|
||||
|
||||
#: home-manager/home-manager:336 home-manager/home-manager:441
|
||||
msgid "The file %s already exists, leaving it unchanged..."
|
||||
msgstr "檔案 %s 已經存在,不更改它..."
|
||||
msgstr "檔案 %s 已存在,保持不變..."
|
||||
|
||||
#: home-manager/home-manager:338 home-manager/home-manager:443
|
||||
msgid "Creating %s..."
|
||||
msgstr "創建 %s 中..."
|
||||
msgstr "正在建立 %s..."
|
||||
|
||||
#: home-manager/home-manager:487
|
||||
msgid "Creating initial Home Manager generation..."
|
||||
msgstr "正在建立初始 Home Manager 世代 ..."
|
||||
msgstr "正在建立初始 Home Manager 世代..."
|
||||
|
||||
#. translators: The "%s" specifier will be replaced by a file path.
|
||||
#: home-manager/home-manager:492
|
||||
@@ -142,12 +142,12 @@ msgid ""
|
||||
"to configure Home Manager. Run 'man home-configuration.nix' to\n"
|
||||
"see all available options."
|
||||
msgstr ""
|
||||
"全部工作完成了!home-manager 工具現應已安裝,您可以編輯\n"
|
||||
"全部完成!home-manager 工具現在應該已被安裝,您可以編輯\n"
|
||||
"\n"
|
||||
" %s\n"
|
||||
"\n"
|
||||
"來配置 Home Manager。執行 ‘man home-configuration.nix’\n"
|
||||
"來檢視所有可用選項。"
|
||||
"來設定 Home Manager。執行 'man home-configuration.nix' 時\n"
|
||||
"可查看所有可用選項。"
|
||||
|
||||
#. translators: The "%s" specifier will be replaced by a URL.
|
||||
#: home-manager/home-manager:497
|
||||
@@ -158,16 +158,16 @@ msgid ""
|
||||
"\n"
|
||||
"if the error seems to be the fault of Home Manager."
|
||||
msgstr ""
|
||||
"啊哦,安裝失敗了!如果感覺是 Home Manager 造成的錯誤,請在下方\n"
|
||||
"糟糕,安裝失敗了!如果感覺是 Home Manager 所造成的錯誤,請在此連結\n"
|
||||
"\n"
|
||||
" %s\n"
|
||||
"\n"
|
||||
"處建立 Issue 告知我們。"
|
||||
"中,建立 Issue 告知我們。"
|
||||
|
||||
#. translators: Here "flake" is a noun that refers to the Nix Flakes feature.
|
||||
#: home-manager/home-manager:508
|
||||
msgid "Can't instantiate a flake configuration"
|
||||
msgstr "無法建立 flake 配置例項"
|
||||
msgstr "無法實例化 flake 設定"
|
||||
|
||||
#: home-manager/home-manager:584
|
||||
msgid ""
|
||||
@@ -177,12 +177,12 @@ msgid_plural ""
|
||||
"There are %d unread and relevant news items.\n"
|
||||
"Read them by running the command \"%s news\"."
|
||||
msgstr[0] ""
|
||||
"有 %d 條未讀的相關新聞或訊息。\n"
|
||||
"可執行 “%s news” 命令進行閱讀。"
|
||||
"有 %d 則未讀且相關的消息項目。\n"
|
||||
"執行指令 \"%s news\" 來進行確認。"
|
||||
|
||||
#: home-manager/home-manager:598
|
||||
msgid "Unknown \"news.display\" setting \"%s\"."
|
||||
msgstr "未知的 “news.display” 設定項 “%s”。"
|
||||
msgstr "未知的 \"news.display\" 設定值 \"%s\"。"
|
||||
|
||||
#: home-manager/home-manager:606
|
||||
#, sh-format
|
||||
@@ -191,11 +191,11 @@ msgstr "請設定 $EDITOR 或 $VISUAL 環境變數"
|
||||
|
||||
#: home-manager/home-manager:624
|
||||
msgid "Cannot run build in read-only directory"
|
||||
msgstr "無法在唯讀目錄中執行構建"
|
||||
msgstr "無法在唯讀目錄中執行建置"
|
||||
|
||||
#: home-manager/home-manager:787
|
||||
msgid "The configuration did not contain the specialisation \"%s\""
|
||||
msgstr ""
|
||||
msgstr "設定中不包含特化設定 \"%s\""
|
||||
|
||||
#: home-manager/home-manager:841
|
||||
msgid "No generation with ID %s"
|
||||
@@ -203,7 +203,7 @@ msgstr "沒有 ID 為 %s 的世代"
|
||||
|
||||
#: home-manager/home-manager:843
|
||||
msgid "Cannot remove the current generation %s"
|
||||
msgstr "無法移除當前世代 %s"
|
||||
msgstr "無法移除目前的世代 %s"
|
||||
|
||||
#: home-manager/home-manager:845
|
||||
msgid "Removing generation %s"
|
||||
@@ -215,7 +215,7 @@ msgstr "沒有即將過期的世代"
|
||||
|
||||
#: home-manager/home-manager:877
|
||||
msgid "No home-manager packages seem to be installed."
|
||||
msgstr "似乎沒有安裝 home-manager 軟體包。"
|
||||
msgstr "似乎沒有安裝 home-manager 套件。"
|
||||
|
||||
#: home-manager/home-manager:962
|
||||
msgid "Unknown argument %s"
|
||||
@@ -223,11 +223,11 @@ msgstr "未知引數 %s"
|
||||
|
||||
#: home-manager/home-manager:987
|
||||
msgid "This will remove Home Manager from your system."
|
||||
msgstr "這將會從系統中移除 Home Manager。"
|
||||
msgstr "這將會從您的系統中移除 Home Manager。"
|
||||
|
||||
#: home-manager/home-manager:990
|
||||
msgid "This is a dry run, nothing will actually be uninstalled."
|
||||
msgstr "這是試執行結果,沒有實際解除安裝任何軟體包。"
|
||||
msgstr "這是模擬執行,實際上並不會解除安裝任何內容。"
|
||||
|
||||
#: home-manager/home-manager:994
|
||||
msgid "Really uninstall Home Manager?"
|
||||
@@ -235,27 +235,27 @@ msgstr "確定要解除安裝 Home Manager 嗎?"
|
||||
|
||||
#: home-manager/home-manager:1000
|
||||
msgid "Switching to empty Home Manager configuration..."
|
||||
msgstr "正在切換至空的 Home Manager 配置 ..."
|
||||
msgstr "正在切換至空的 Home Manager 設定..."
|
||||
|
||||
#: home-manager/home-manager:1015
|
||||
msgid "Yay!"
|
||||
msgstr "好耶!"
|
||||
msgstr "太好了!"
|
||||
|
||||
#: home-manager/home-manager:1020
|
||||
msgid "Home Manager is uninstalled but your home.nix is left untouched."
|
||||
msgstr "Home Manager 已解除安裝,但未改動您的 home.nix 配置檔案。"
|
||||
msgstr "Home Manager 已解除安裝,但您的 home.nix 保持不變。"
|
||||
|
||||
#: home-manager/home-manager:1285
|
||||
msgid "expire-generations expects one argument, got %d."
|
||||
msgstr "expire-generations 須要一個引數,但獲取到了 %d 個。"
|
||||
msgstr "expire-generations 預期一個引數,但得到了 %d 個。"
|
||||
|
||||
#: home-manager/home-manager:1310
|
||||
msgid "Unknown command: %s"
|
||||
msgstr "未知命令:%s"
|
||||
msgstr "未知指令:%s"
|
||||
|
||||
#: home-manager/install.nix:21
|
||||
msgid "This derivation is not buildable, please run it using nix-shell."
|
||||
msgstr "此配置檔案/變體不可構建,請在 nix-shell 中執行它。"
|
||||
msgstr "此 derivation 無法建置,請使用 nix-shell 執行。"
|
||||
|
||||
#, sh-format
|
||||
#~ msgid "Please set the $EDITOR environment variable"
|
||||
|
||||
@@ -102,8 +102,8 @@ let
|
||||
};
|
||||
|
||||
local = mkOption {
|
||||
type = types.nullOr (localModule name);
|
||||
default = null;
|
||||
type = localModule name;
|
||||
default = { };
|
||||
description = ''
|
||||
Local configuration for the contacts.
|
||||
'';
|
||||
|
||||
@@ -57,9 +57,8 @@ let
|
||||
let
|
||||
module = moduleChecks rawModule;
|
||||
in
|
||||
{
|
||||
inherit (module) options config;
|
||||
|
||||
module
|
||||
// {
|
||||
activationPackage = module.config.home.activationPackage;
|
||||
|
||||
# For backwards compatibility. Please use activationPackage instead.
|
||||
|
||||
@@ -193,6 +193,13 @@ in
|
||||
description = "The user's username.";
|
||||
};
|
||||
|
||||
home.uid = mkOption {
|
||||
type = types.nullOr types.ints.unsigned;
|
||||
default = null;
|
||||
example = 1000;
|
||||
description = "The user's uid.";
|
||||
};
|
||||
|
||||
home.homeDirectory = mkOption {
|
||||
type = types.path;
|
||||
defaultText = literalExpression ''
|
||||
@@ -570,14 +577,25 @@ in
|
||||
warnings =
|
||||
let
|
||||
hmRelease = config.home.version.release;
|
||||
nixpkgsRelease = lib.trivial.release;
|
||||
releaseMismatch = config.home.enableNixpkgsReleaseCheck && hmRelease != nixpkgsRelease;
|
||||
libRelease = lib.trivial.release;
|
||||
pkgsRelease = pkgs.lib.trivial.release;
|
||||
releaseMismatch = hmRelease != libRelease || hmRelease != pkgsRelease;
|
||||
|
||||
versionsSummary =
|
||||
if libRelease == pkgsRelease then
|
||||
''
|
||||
Home Manager version ${hmRelease} and
|
||||
Nixpkgs version ${libRelease}.''
|
||||
else
|
||||
''
|
||||
Home Manager version: ${hmRelease}
|
||||
Nixpkgs version used to evaluate Home Manager: ${libRelease}
|
||||
Nixpkgs version used for packages (`pkgs`): ${pkgsRelease}'';
|
||||
in
|
||||
lib.optional releaseMismatch ''
|
||||
lib.optional (config.home.enableNixpkgsReleaseCheck && releaseMismatch) ''
|
||||
You are using
|
||||
|
||||
Home Manager version ${hmRelease} and
|
||||
Nixpkgs version ${nixpkgsRelease}.
|
||||
${lib.replaceString "\n" "\n " versionsSummary}
|
||||
|
||||
Using mismatched versions is likely to cause errors and unexpected
|
||||
behavior. It is therefore highly recommended to use a release of Home
|
||||
@@ -831,6 +849,9 @@ in
|
||||
if [[ ! -v SKIP_SANITY_CHECKS ]]; then
|
||||
checkUsername ${lib.escapeShellArg config.home.username}
|
||||
checkHomeDirectory ${lib.escapeShellArg config.home.homeDirectory}
|
||||
${lib.optionalString (config.home.uid != null) ''
|
||||
checkUid ${toString config.home.uid}
|
||||
''}
|
||||
fi
|
||||
|
||||
${lib.optionalString config.home.activationGenerateGcRoot ''
|
||||
|
||||
@@ -270,9 +270,7 @@ in
|
||||
setupLaunchAgents
|
||||
|
||||
# Restore errexit
|
||||
if [[ -o errexit ]]; then
|
||||
set -e
|
||||
fi
|
||||
set -e
|
||||
'';
|
||||
})
|
||||
];
|
||||
|
||||
@@ -117,6 +117,17 @@ function checkHomeDirectory() {
|
||||
fi
|
||||
}
|
||||
|
||||
function checkUid() {
|
||||
local expectedUid="$1"
|
||||
local actualUid
|
||||
actualUid="$(id -u)"
|
||||
|
||||
if [[ "$actualUid" != "$expectedUid" ]]; then
|
||||
_iError 'Error: UID is "%s" but we expect "%s"' "$actualUid" "$expectedUid"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Note, the VERBOSE_ECHO variable is deprecated and should not be used inside
|
||||
# the Home Manager project. It is provided here for backwards compatibility.
|
||||
if [[ -v VERBOSE ]]; then
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
isList
|
||||
mapAttrsToList
|
||||
replicate
|
||||
attrNames
|
||||
;
|
||||
|
||||
initialIndent = concatStrings (replicate indentLevel " ");
|
||||
@@ -28,31 +29,36 @@
|
||||
toHyprconf' =
|
||||
indent: attrs:
|
||||
let
|
||||
sections = filterAttrs (n: v: isAttrs v || (isList v && all isAttrs v)) attrs;
|
||||
isImportantField =
|
||||
n: _: foldl (acc: prev: if hasPrefix prev n then true else acc) false importantPrefixes;
|
||||
importantFields = filterAttrs isImportantField attrs;
|
||||
withoutImportantFields = fields: removeAttrs fields (attrNames importantFields);
|
||||
|
||||
allSections = filterAttrs (n: v: isAttrs v || isList v) attrs;
|
||||
sections = withoutImportantFields allSections;
|
||||
|
||||
mkSection =
|
||||
n: attrs:
|
||||
if lib.isList attrs then
|
||||
(concatMapStringsSep "\n" (a: mkSection n a) attrs)
|
||||
else
|
||||
if isList attrs then
|
||||
let
|
||||
separator = if all isAttrs attrs then "\n" else "";
|
||||
in
|
||||
(concatMapStringsSep separator (a: mkSection n a) attrs)
|
||||
else if isAttrs attrs then
|
||||
''
|
||||
${indent}${n} {
|
||||
${toHyprconf' " ${indent}" attrs}${indent}}
|
||||
'';
|
||||
''
|
||||
else
|
||||
toHyprconf' indent { ${n} = attrs; };
|
||||
|
||||
mkFields = generators.toKeyValue {
|
||||
listsAsDuplicateKeys = true;
|
||||
inherit indent;
|
||||
};
|
||||
|
||||
allFields = filterAttrs (n: v: !(isAttrs v || (isList v && all isAttrs v))) attrs;
|
||||
|
||||
isImportantField =
|
||||
n: _: foldl (acc: prev: if hasPrefix prev n then true else acc) false importantPrefixes;
|
||||
|
||||
importantFields = filterAttrs isImportantField allFields;
|
||||
|
||||
fields = builtins.removeAttrs allFields (mapAttrsToList (n: _: n) importantFields);
|
||||
allFields = filterAttrs (n: v: !(isAttrs v || isList v)) attrs;
|
||||
fields = withoutImportantFields allFields;
|
||||
in
|
||||
mkFields importantFields
|
||||
+ concatStringsSep "\n" (mapAttrsToList mkSection sections)
|
||||
|
||||
@@ -17,15 +17,29 @@ let
|
||||
# The dconf keys managed by this configuration. We store this as part of the
|
||||
# generation state to be able to reset keys that become unmanaged during
|
||||
# switch.
|
||||
stateDconfKeys = pkgs.writeText "dconf-keys.json" (
|
||||
builtins.toJSON (
|
||||
lib.concatLists (
|
||||
lib.mapAttrsToList (
|
||||
dir: entries: lib.mapAttrsToList (key: _: "/${dir}/${key}") entries
|
||||
) cfg.settings
|
||||
mkStateDconfKeys =
|
||||
nameSuffix: settings:
|
||||
pkgs.writeText "dconf-keys${nameSuffix}.json" (
|
||||
builtins.toJSON (
|
||||
lib.concatLists (
|
||||
lib.mapAttrsToList (dir: entries: lib.mapAttrsToList (key: _: "/${dir}/${key}") entries) settings
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
);
|
||||
|
||||
databases =
|
||||
lib.optional (cfg.settings != { }) {
|
||||
dconfProfile = null;
|
||||
stateDconfKeys = mkStateDconfKeys "" cfg.settings;
|
||||
inherit (cfg) settings;
|
||||
}
|
||||
++ lib.mapAttrsToList (name: value: {
|
||||
dconfProfile = pkgs.writeText "dconf-profile-${name}" ''
|
||||
user-db:${name}
|
||||
'';
|
||||
stateDconfKeys = mkStateDconfKeys "-${name}" value;
|
||||
settings = value;
|
||||
}) cfg.databases;
|
||||
|
||||
in
|
||||
{
|
||||
@@ -81,73 +95,87 @@ in
|
||||
to convert dconf database dumps into compatible Nix expression.
|
||||
'';
|
||||
};
|
||||
databases = lib.mkOption {
|
||||
type = with types; attrsOf (attrsOf (attrsOf lib.hm.types.gvariant));
|
||||
default = { };
|
||||
description = ''
|
||||
Settings to write to specific dconf user databases.
|
||||
See [](#opt-dconf.settings) for details.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (cfg.enable && cfg.settings != { }) {
|
||||
config = lib.mkIf (cfg.enable && databases != [ ]) {
|
||||
# Make sure the dconf directory exists.
|
||||
xdg.configFile."dconf/.keep".source = builtins.toFile "keep" "";
|
||||
|
||||
home.extraBuilderCommands = ''
|
||||
mkdir -p $out/state/
|
||||
ln -s ${stateDconfKeys} $out/state/${stateDconfKeys.name}
|
||||
'';
|
||||
''
|
||||
+ lib.concatMapStrings (db: ''
|
||||
ln -s ${db.stateDconfKeys} $out/state/${db.stateDconfKeys.name}
|
||||
'') databases;
|
||||
|
||||
home.activation.dconfSettings = lib.hm.dag.entryAfter [ "installPackages" ] (
|
||||
let
|
||||
iniFile = pkgs.writeText "hm-dconf.ini" (toDconfIni cfg.settings);
|
||||
lib.concatMapStrings (
|
||||
db:
|
||||
let
|
||||
iniFile = pkgs.writeText "hm-dconf.ini" (toDconfIni db.settings);
|
||||
|
||||
statePath = "state/${stateDconfKeys.name}";
|
||||
statePath = "state/${db.stateDconfKeys.name}";
|
||||
|
||||
cleanup = pkgs.writeShellScript "dconf-cleanup" ''
|
||||
set -euo pipefail
|
||||
cleanup = pkgs.writeShellScript "dconf-cleanup" ''
|
||||
set -euo pipefail
|
||||
|
||||
${config.lib.bash.initHomeManagerLib}
|
||||
${config.lib.bash.initHomeManagerLib}
|
||||
|
||||
PATH=${
|
||||
lib.makeBinPath [
|
||||
pkgs.dconf
|
||||
pkgs.jq
|
||||
]
|
||||
}''${PATH:+:}$PATH
|
||||
PATH=${
|
||||
lib.makeBinPath [
|
||||
pkgs.dconf
|
||||
pkgs.jq
|
||||
]
|
||||
}''${PATH:+:}$PATH
|
||||
|
||||
oldState="$1"
|
||||
newState="$2"
|
||||
oldState="$1"
|
||||
newState="$2"
|
||||
|
||||
# Can't do cleanup if we don't know the old state.
|
||||
if [[ ! -f $oldState ]]; then
|
||||
exit 0
|
||||
# Can't do cleanup if we don't know the old state.
|
||||
if [[ ! -f $oldState ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Reset all keys that are present in the old generation but not the new
|
||||
# one.
|
||||
jq -r -n \
|
||||
--slurpfile old "$oldState" \
|
||||
--slurpfile new "$newState" \
|
||||
'($old[] - $new[])[]' \
|
||||
| while read -r key; do
|
||||
verboseEcho "Resetting dconf key \"$key\""
|
||||
run $DCONF_DBUS_RUN_SESSION dconf reset "$key"
|
||||
done
|
||||
'';
|
||||
envCommand = lib.optionalString (db.dconfProfile != null) "env DCONF_PROFILE=${db.dconfProfile}";
|
||||
in
|
||||
''
|
||||
if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then
|
||||
export DCONF_DBUS_RUN_SESSION="${envCommand}"
|
||||
else
|
||||
export DCONF_DBUS_RUN_SESSION="${pkgs.dbus}/bin/dbus-run-session --dbus-daemon=${pkgs.dbus}/bin/dbus-daemon ${envCommand}"
|
||||
fi
|
||||
|
||||
# Reset all keys that are present in the old generation but not the new
|
||||
# one.
|
||||
jq -r -n \
|
||||
--slurpfile old "$oldState" \
|
||||
--slurpfile new "$newState" \
|
||||
'($old[] - $new[])[]' \
|
||||
| while read -r key; do
|
||||
verboseEcho "Resetting dconf key \"$key\""
|
||||
run $DCONF_DBUS_RUN_SESSION dconf reset "$key"
|
||||
done
|
||||
'';
|
||||
in
|
||||
''
|
||||
if [[ -v DBUS_SESSION_BUS_ADDRESS ]]; then
|
||||
export DCONF_DBUS_RUN_SESSION=""
|
||||
else
|
||||
export DCONF_DBUS_RUN_SESSION="${pkgs.dbus}/bin/dbus-run-session --dbus-daemon=${pkgs.dbus}/bin/dbus-daemon"
|
||||
fi
|
||||
if [[ -v oldGenPath ]]; then
|
||||
${cleanup} \
|
||||
"$oldGenPath/${statePath}" \
|
||||
"$newGenPath/${statePath}"
|
||||
fi
|
||||
|
||||
if [[ -v oldGenPath ]]; then
|
||||
${cleanup} \
|
||||
"$oldGenPath/${statePath}" \
|
||||
"$newGenPath/${statePath}"
|
||||
fi
|
||||
run $DCONF_DBUS_RUN_SESSION ${pkgs.dconf}/bin/dconf load / < ${iniFile}
|
||||
|
||||
run $DCONF_DBUS_RUN_SESSION ${pkgs.dconf}/bin/dconf load / < ${iniFile}
|
||||
|
||||
unset DCONF_DBUS_RUN_SESSION
|
||||
''
|
||||
unset DCONF_DBUS_RUN_SESSION
|
||||
''
|
||||
) databases
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ in
|
||||
theme = mkOption {
|
||||
type = types.nullOr themeType;
|
||||
default = null;
|
||||
description = "Default theme for all GTK versions.";
|
||||
description = "Default theme for GTK 2/3.";
|
||||
};
|
||||
|
||||
iconTheme = mkOption {
|
||||
|
||||
@@ -45,9 +45,17 @@ in
|
||||
packageExample = "pkgs.gnome.gnome-themes-extra";
|
||||
}
|
||||
);
|
||||
default = cfg.theme;
|
||||
defaultText = literalExpression "config.gtk.theme";
|
||||
description = "Theme for GTK 4 applications.";
|
||||
default = if lib.versionOlder config.home.stateVersion "26.05" then cfg.theme else null;
|
||||
defaultText = literalExpression ''if lib.versionOlder config.home.stateVersion "26.05" then cfg.theme else null'';
|
||||
description = ''
|
||||
Theme for GTK 4 applications.
|
||||
|
||||
Warning: This is not officially supported and applied using a workaround.
|
||||
It may cause issues with some apps.
|
||||
|
||||
For context, see [Please don’t theme our apps](https://stopthemingmy.app/)
|
||||
and [Restyling apps at scale](https://blogs.gnome.org/tbernard/2018/10/15/restyling-apps-at-scale/).
|
||||
'';
|
||||
};
|
||||
|
||||
iconTheme = mkOption {
|
||||
|
||||
9
modules/misc/news/2025/10/2025-10-15_10-44-58.nix
Normal file
9
modules/misc/news/2025/10/2025-10-15_10-44-58.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
time = "2025-10-14T23:44:58+00:00";
|
||||
condition = true;
|
||||
message = ''
|
||||
A new module is available: `services.colima`
|
||||
|
||||
Colima is a tool for orchestrating container runtimes under a linux VM.
|
||||
'';
|
||||
}
|
||||
9
modules/misc/news/2025/11/2025-11-26_06-33-49.nix
Normal file
9
modules/misc/news/2025/11/2025-11-26_06-33-49.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
time = "2025-11-26T05:33:49+00:00";
|
||||
condition = true;
|
||||
message = ''
|
||||
A new module is available: 'programs.cargo'.
|
||||
|
||||
cargo is the build system and package manager of Rust.
|
||||
'';
|
||||
}
|
||||
11
modules/misc/news/2025/11/2025-11-26_11-55-28.nix
Normal file
11
modules/misc/news/2025/11/2025-11-26_11-55-28.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
time = "2025-11-26T10:55:28+00:00";
|
||||
condition = true;
|
||||
message = ''
|
||||
The option 'gtk.theme' does not apply to GTK 4 automatically anymore for new
|
||||
installations (with `home.stateVersion` >= "26.05"). Using a custom theme is
|
||||
not officially supported by GTK 4, and implemented by home-manager using a
|
||||
workaround that may cause issues in some cases. If you still want to use a GTK
|
||||
4 theme, you need to explicitly set 'gtk.gtk4.theme'.
|
||||
'';
|
||||
}
|
||||
10
modules/misc/news/2025/11/2025-11-27_08-22-14.nix
Normal file
10
modules/misc/news/2025/11/2025-11-27_08-22-14.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
time = "2025-11-27T07:22:14+00:00";
|
||||
condition = pkgs.stdenv.hostPlatform.isDarwin;
|
||||
message = ''
|
||||
A new module is available: 'programs.infat'.
|
||||
Infat is a command line tool to set default openers
|
||||
for file formats and url schemes on macOS.
|
||||
'';
|
||||
}
|
||||
7
modules/misc/news/2025/11/2025-11-30_00-04-38.nix
Normal file
7
modules/misc/news/2025/11/2025-11-30_00-04-38.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
time = "2025-11-29T23:04:38+00:00";
|
||||
condition = true;
|
||||
message = ''
|
||||
A new module is available: 'programs.parallel'.
|
||||
'';
|
||||
}
|
||||
16
modules/misc/news/2025/12/2025-12-01_09-35-38.nix
Normal file
16
modules/misc/news/2025/12/2025-12-01_09-35-38.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
time = "2025-12-01T12:35:38+00:00";
|
||||
condition = config.services.ludusavi.enable;
|
||||
message = ''
|
||||
BREAKING CHANGE:
|
||||
|
||||
The `ludusavi` module has changed its default backup and restore path.
|
||||
The new module implements a mechanism to automatically migrate the backups
|
||||
to the new path, but if it doesn't work and you can't find your backups in
|
||||
`ludusavi`, they should be in the old path: ~/\$XDG_STATE_HOME/backups/ludusavi/
|
||||
(that means a directory literally called $XDG_STATE_HOME in your home, rather than
|
||||
the env var expanded). For more info, see pull #8234.
|
||||
'';
|
||||
}
|
||||
12
modules/misc/news/2025/12/2025-12-03_10-14-53.nix
Normal file
12
modules/misc/news/2025/12/2025-12-03_10-14-53.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
time = "2025-12-03T13:14:53+00:00";
|
||||
condition = true;
|
||||
message = ''
|
||||
A new module is available: `programs.calibre`
|
||||
|
||||
Calibre is a powerful and easy to use e-book manager. Users say it’s outstanding
|
||||
and a must-have. It’ll allow you to do nearly everything and it takes things a
|
||||
step beyond normal e-book software. It’s also completely free and open source
|
||||
and great for both casual users and computer experts.
|
||||
'';
|
||||
}
|
||||
12
modules/misc/news/2025/12/2025-12-04_16-34-38.nix
Normal file
12
modules/misc/news/2025/12/2025-12-04_16-34-38.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
time = "2025-12-04T19:34:38+00:00";
|
||||
condition = true;
|
||||
message = ''
|
||||
A new module is available: `programs.screen`
|
||||
|
||||
GNU Screen is a terminal multiplexer, a software application that can
|
||||
be used to multiplex several virtual consoles, allowing a user to access
|
||||
multiple separate login sessions inside a single terminal window, or detach
|
||||
and reattach sessions from a terminal.
|
||||
'';
|
||||
}
|
||||
12
modules/misc/news/2025/12/2025-12-04_22-50-03.nix
Normal file
12
modules/misc/news/2025/12/2025-12-04_22-50-03.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
time = "2025-12-05T01:50:03+00:00";
|
||||
condition = pkgs.stdenv.hostPlatform.isLinux;
|
||||
message = ''
|
||||
A new module is available: `programs.hyprlauncher`
|
||||
|
||||
Hyprlauncher is a multipurpose and versatile launcher/picker
|
||||
for hyprland. It’s fast, simple, and provides various modules.
|
||||
'';
|
||||
}
|
||||
10
modules/misc/news/2025/12/2025-12-06_11-03-01.nix
Normal file
10
modules/misc/news/2025/12/2025-12-06_11-03-01.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
time = "2025-12-06T10:03:01+00:00";
|
||||
condition = true;
|
||||
message = ''
|
||||
A new module is available: `programs.npm`
|
||||
|
||||
It allows you manage your npm user configuration (`.npmrc`)
|
||||
and install a specific version of the package.
|
||||
'';
|
||||
}
|
||||
10
modules/misc/news/2025/12/2025-12-06_11-05-43.nix
Normal file
10
modules/misc/news/2025/12/2025-12-06_11-05-43.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
time = "2025-12-06T10:05:43+00:00";
|
||||
condition = true;
|
||||
message = ''
|
||||
A new module is available: `programs.ty`
|
||||
|
||||
It allows to manage the configuration and package
|
||||
of the Python language server `ty` by Astral.
|
||||
'';
|
||||
}
|
||||
32
modules/misc/news/2025/12/2025-12-11_13-04-30.nix
Normal file
32
modules/misc/news/2025/12/2025-12-11_13-04-30.nix
Normal file
@@ -0,0 +1,32 @@
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
time = "2025-12-11T19:04:30+00:00";
|
||||
condition =
|
||||
let
|
||||
helixEnabled = config.programs.helix.enable && config.programs.helix.defaultEditor;
|
||||
kakouneEnabled = config.programs.kakoune.enable && config.programs.kakoune.defaultEditor;
|
||||
neovimEnabled = config.programs.neovim.enable && config.programs.neovim.defaultEditor;
|
||||
vimEnabled = config.programs.vim.enable && config.programs.vim.defaultEditor;
|
||||
emacsEnabled = config.services.emacs.enable && config.services.emacs.defaultEditor;
|
||||
in
|
||||
helixEnabled || kakouneEnabled || neovimEnabled || vimEnabled || emacsEnabled;
|
||||
message = ''
|
||||
The 'defaultEditor' option now sets both {env}`EDITOR` and {env}`VISUAL`
|
||||
environment variables.
|
||||
|
||||
Previously, only {env}`EDITOR` was set. The {env}`VISUAL` variable is now
|
||||
also configured to point to the same editor, which is the expected behavior
|
||||
for modern terminal editors.
|
||||
|
||||
This change affects the following modules:
|
||||
- programs.helix
|
||||
- programs.kakoune
|
||||
- programs.neovim
|
||||
- programs.vim
|
||||
- services.emacs
|
||||
|
||||
No action is required. This change should improve compatibility with tools
|
||||
that check {env}`VISUAL` before {env}`EDITOR`.
|
||||
'';
|
||||
}
|
||||
12
modules/misc/news/2025/12/2025-12-12_19-20-28.nix
Normal file
12
modules/misc/news/2025/12/2025-12-12_19-20-28.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
time = "2025-12-12T19:20:28+00:00";
|
||||
condition = config.xsession.windowManager.herbstluftwm.enable;
|
||||
message = ''
|
||||
It is now possible to disable the `herbstclient` alias in the autostart
|
||||
script by setting `xsession.windowManagers.herbsluftwm.enableAlias = false`.
|
||||
This makes it possible to use the `herbstclient` command in bash functions,
|
||||
though may cause flickering while the autostart script runs.
|
||||
'';
|
||||
}
|
||||
20
modules/misc/news/2025/12/2025-12-27_13-32-14.nix
Normal file
20
modules/misc/news/2025/12/2025-12-27_13-32-14.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
time = "2025-12-27T19:00:00+00:00";
|
||||
condition = config.programs.zsh.enable;
|
||||
|
||||
message = ''
|
||||
The default value of `programs.zsh.dotDir` has changed.
|
||||
|
||||
When `home.stateVersion` is set to "26.05" or later, and `xdg.enable` is
|
||||
`true` (the default), `programs.zsh.dotDir` now defaults to
|
||||
`''${config.xdg.configHome}/zsh`. Previously, it defaulted to the home
|
||||
directory.
|
||||
|
||||
This means your Zsh configuration files (`.zshrc`, `.zshenv`, etc.) will be
|
||||
moved to `~/.config/zsh` (or your configured XDG config home).
|
||||
|
||||
If you prefer the old behavior, you can explicitly set:
|
||||
`programs.zsh.dotDir = config.home.homeDirectory;`
|
||||
'';
|
||||
}
|
||||
10
modules/misc/news/2026/01/2026-01-02_00-03-48.nix
Normal file
10
modules/misc/news/2026/01/2026-01-02_00-03-48.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{ config, ... }:
|
||||
{
|
||||
time = "2026-01-02T00:03:48+00:00";
|
||||
condition = config.services.mpd.enable;
|
||||
message = ''
|
||||
`MPD_HOST` and `MPD_PORT` environment variables are now set automatically.
|
||||
|
||||
This can be disabled with `services.mpd.enableSessionVariables = false`.
|
||||
'';
|
||||
}
|
||||
@@ -8,6 +8,10 @@
|
||||
let
|
||||
cfg = config.qt;
|
||||
|
||||
qtctFormat = pkgs.formats.ini {
|
||||
listToValue = values: lib.concatStringsSep ", " values;
|
||||
};
|
||||
|
||||
# Map platform names to their packages.
|
||||
platformPackages = with pkgs; {
|
||||
gnome = [
|
||||
@@ -286,7 +290,34 @@ in
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
// (lib.genAttrs' [ "qt5ct" "qt6ct" ] (
|
||||
name:
|
||||
lib.nameValuePair "${name}Settings" (
|
||||
lib.mkOption {
|
||||
type = lib.types.nullOr qtctFormat.type;
|
||||
default = null;
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
Appearance = {
|
||||
style = "kvantum";
|
||||
icon_theme = "Papirus-Dark";
|
||||
standar_dialogs = "xdgdesktopportal";
|
||||
};
|
||||
Fonts = {
|
||||
fixed = "\"DejaVuSansM Nerd Font Mono,12\"";
|
||||
general = "\"DejaVu Sans,12\"";
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Qtct configuration. Writes settings to `${name}/${name}.conf`
|
||||
file. Lists will be translated to comma-separated strings.
|
||||
Fonts must be quoted (see example).
|
||||
'';
|
||||
}
|
||||
)
|
||||
));
|
||||
};
|
||||
|
||||
config =
|
||||
@@ -397,5 +428,18 @@ in
|
||||
]
|
||||
++ lib.optionals (platformTheme.name != null) [ "QT_QPA_PLATFORMTHEME" ]
|
||||
++ lib.optionals (cfg.style.name != null) [ "QT_STYLE_OVERRIDE" ];
|
||||
|
||||
xdg.configFile =
|
||||
lib.pipe
|
||||
[ "qt5ct" "qt6ct" ]
|
||||
[
|
||||
(lib.filter (qtct: cfg."${qtct}Settings" != null))
|
||||
(lib.flip lib.genAttrs' (
|
||||
qtct:
|
||||
lib.nameValuePair "${qtct}/${qtct}.conf" {
|
||||
source = qtctFormat.generate "${qtct}-config" cfg."${qtct}Settings";
|
||||
}
|
||||
))
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ in
|
||||
"24.11"
|
||||
"25.05"
|
||||
"25.11"
|
||||
"26.05"
|
||||
];
|
||||
description = ''
|
||||
It is occasionally necessary for Home Manager to change
|
||||
|
||||
@@ -136,7 +136,7 @@ in
|
||||
xdg.stateHome = mkOptionDefault defaultStateHome;
|
||||
|
||||
home.sessionVariables = variables;
|
||||
systemd.user.sessionVariables = mkIf pkgs.stdenv.hostPlatform.isLinux variables;
|
||||
systemd.user.sessionVariables = variables;
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ in
|
||||
home.activation.xfconfSettings = lib.hm.dag.entryAfter [ "installPackages" ] (
|
||||
let
|
||||
mkCommand = channel: property: value: ''
|
||||
run ${pkgs.xfce.xfconf}/bin/xfconf-query \
|
||||
run ${pkgs.xfconf}/bin/xfconf-query \
|
||||
${lib.escapeShellArgs (
|
||||
[
|
||||
"-c"
|
||||
|
||||
@@ -8,26 +8,28 @@ msgstr ""
|
||||
"Project-Id-Version: Home Manager Modules\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
|
||||
"POT-Creation-Date: 2025-07-22 10:59+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
"PO-Revision-Date: 2025-11-30 14:00+0000\n"
|
||||
"Last-Translator: Brian E <brianellingsgaard9@gmail.com>\n"
|
||||
"Language-Team: Faroese <https://hosted.weblate.org/projects/home-manager/"
|
||||
"modules/fo/>\n"
|
||||
"Language: fo\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.15-dev\n"
|
||||
|
||||
#: modules/files.nix:206
|
||||
msgid "Creating home file links in %s"
|
||||
msgstr ""
|
||||
msgstr "Stávni heimafílaleinkir innaní %s"
|
||||
|
||||
#: modules/files.nix:219
|
||||
msgid "Cleaning up orphan links from %s"
|
||||
msgstr ""
|
||||
msgstr "Ruddi foreldraleys leinkir frá %s"
|
||||
|
||||
#: modules/home-environment.nix:647
|
||||
msgid "Creating new profile generation"
|
||||
msgstr ""
|
||||
msgstr "Stovni nýggjan profil ættarlið"
|
||||
|
||||
#: modules/home-environment.nix:650
|
||||
msgid "No change so reusing latest profile generation"
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: Home Manager Modules\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/nix-community/home-manager/issues\n"
|
||||
"POT-Creation-Date: 2025-07-22 10:59+0200\n"
|
||||
"PO-Revision-Date: 2025-03-07 18:58+0000\n"
|
||||
"Last-Translator: 807 <s10855168@gmail.com>\n"
|
||||
"PO-Revision-Date: 2025-12-04 04:17+0000\n"
|
||||
"Last-Translator: \"Urocissa Caerulea.Tw\" <urocissa.tw@proton.me>\n"
|
||||
"Language-Team: Chinese (Traditional Han script) <https://hosted.weblate.org/"
|
||||
"projects/home-manager/modules/zh_Hant/>\n"
|
||||
"Language: zh_Hant\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Weblate 5.10.3-dev\n"
|
||||
"X-Generator: Weblate 5.15-dev\n"
|
||||
|
||||
#: modules/files.nix:206
|
||||
msgid "Creating home file links in %s"
|
||||
@@ -25,15 +25,15 @@ msgstr "正在 %s 中建立家目錄檔案連結"
|
||||
|
||||
#: modules/files.nix:219
|
||||
msgid "Cleaning up orphan links from %s"
|
||||
msgstr "正在從 %s 清理孤立連結"
|
||||
msgstr "正在清理 %s 中的孤立連結"
|
||||
|
||||
#: modules/home-environment.nix:647
|
||||
msgid "Creating new profile generation"
|
||||
msgstr "正在建立新一代的配置文件中"
|
||||
msgstr "正在建立新的世代設定檔"
|
||||
|
||||
#: modules/home-environment.nix:650
|
||||
msgid "No change so reusing latest profile generation"
|
||||
msgstr "為發生改變,請重新使用新一代的配置文件"
|
||||
msgstr "沒有變更,將重複使用最新的設定檔世代"
|
||||
|
||||
#: modules/home-environment.nix:699
|
||||
msgid ""
|
||||
@@ -50,18 +50,18 @@ msgid ""
|
||||
"\n"
|
||||
"Then try activating your Home Manager configuration again."
|
||||
msgstr ""
|
||||
"糟糕,Nix 未能安裝您的新 Home Manager 配置文件!\n"
|
||||
"糟糕,Nix 無法安裝您的新 Home Manager 設定檔!\n"
|
||||
"\n"
|
||||
"也許這裏和使用 \"%s\" 安裝的包有衝突?\n"
|
||||
"嘗試運行\n"
|
||||
"可能與使用 \"%s\" 安裝的套件衝突?\n"
|
||||
"請嘗試執行\n"
|
||||
"\n"
|
||||
" %s\n"
|
||||
"\n"
|
||||
"如果有衝突的包,你可以用\n"
|
||||
"如果有衝突的套件,您可以使用以下指令移除\n"
|
||||
"\n"
|
||||
" %s\n"
|
||||
"\n"
|
||||
"來移除。然後嘗試再次啟用您的 Home Manager 配置。"
|
||||
"然後再次嘗試啟用您的 Home Manager 設定。"
|
||||
|
||||
#: modules/home-environment.nix:735
|
||||
msgid "Activating %s"
|
||||
@@ -69,27 +69,27 @@ msgstr "正在啟用 %s"
|
||||
|
||||
#: modules/home-environment.nix:807
|
||||
msgid "%s: unknown option '%s'"
|
||||
msgstr ""
|
||||
msgstr "%s:未知選項 '%s'"
|
||||
|
||||
#: modules/lib-bash/activation-init.sh:22
|
||||
msgid "Migrating profile from %s to %s"
|
||||
msgstr "正在從 %S 配置文件轉移到 %s 中"
|
||||
msgstr "正在將設定檔從 %s 遷移至 %s"
|
||||
|
||||
#: modules/lib-bash/activation-init.sh:54
|
||||
msgid "Could not find suitable profile directory, tried %s and %s"
|
||||
msgstr "找不到合適的 profile 目錄,已經嘗試 %s 和 %s"
|
||||
msgstr "找不到合適的設定檔目錄,已嘗試 %s 和 %s"
|
||||
|
||||
#: modules/lib-bash/activation-init.sh:106
|
||||
msgid "Error: USER is set to \"%s\" but we expect \"%s\""
|
||||
msgstr "錯誤:USER 被設定為 「%s」但我們希望是 「%s」"
|
||||
msgstr "錯誤:USER 被設定為「%s」,但我們的預期為「%s」"
|
||||
|
||||
#: modules/lib-bash/activation-init.sh:115
|
||||
msgid "Error: HOME is set to \"%s\" but we expect \"%s\""
|
||||
msgstr "錯誤:HOME 被設定為 「%s」但我們預期得到 「%s」"
|
||||
msgstr "錯誤:HOME 被設定為「%s」,但我們的預期為「%s」"
|
||||
|
||||
#: modules/lib-bash/activation-init.sh:132
|
||||
msgid "Starting Home Manager activation"
|
||||
msgstr "正在啟動 Home Manager 初始化程式"
|
||||
msgstr "正在進行 Home Manager 啟用程序"
|
||||
|
||||
#: modules/lib-bash/activation-init.sh:136
|
||||
msgid "Sanity checking Nix"
|
||||
@@ -97,19 +97,19 @@ msgstr "正在進行 Nix 完整性檢查"
|
||||
|
||||
#: modules/lib-bash/activation-init.sh:149
|
||||
msgid "This is a dry run"
|
||||
msgstr "這是試運行"
|
||||
msgstr "這是模擬執行"
|
||||
|
||||
#: modules/lib-bash/activation-init.sh:153
|
||||
msgid "This is a live run"
|
||||
msgstr "這是在實際運行"
|
||||
msgstr "這是實際執行"
|
||||
|
||||
#: modules/lib-bash/activation-init.sh:159
|
||||
msgid "Using Nix version: %s"
|
||||
msgstr "正在使用的 Nix 版本: %s"
|
||||
msgstr "使用中的 Nix 版本:%s"
|
||||
|
||||
#: modules/lib-bash/activation-init.sh:162
|
||||
msgid "Activation variables:"
|
||||
msgstr "啟用的變數:"
|
||||
msgstr "啟用變數:"
|
||||
|
||||
#~ msgid "Creating profile generation %s"
|
||||
#~ msgstr "正在建立配置檔案世代 %s"
|
||||
|
||||
@@ -10,6 +10,12 @@ let
|
||||
|
||||
tomlFormat = pkgs.formats.toml { };
|
||||
|
||||
configPath =
|
||||
if config.xdg.enable then
|
||||
"${lib.removePrefix config.home.homeDirectory config.xdg.configHome}/aerospace/aerospace.toml"
|
||||
else
|
||||
".aerospace.toml";
|
||||
|
||||
# filterAttrsRecursive supporting lists, as well.
|
||||
filterListAndAttrsRecursive =
|
||||
pred: set:
|
||||
@@ -39,6 +45,19 @@ in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ damidoug ];
|
||||
|
||||
imports = [
|
||||
(lib.mkRenamedOptionModule
|
||||
[ "programs" "aerospace" "userSettings" ]
|
||||
[ "programs" "aerospace" "settings" ]
|
||||
)
|
||||
|
||||
(lib.mkRemovedOptionModule [
|
||||
"programs"
|
||||
"aerospace"
|
||||
"extraConfig"
|
||||
] "This option has been removed. Please use 'programs.aerospace.settings' instead.")
|
||||
];
|
||||
|
||||
options.programs.aerospace = {
|
||||
enable = lib.mkEnableOption "AeroSpace window manager";
|
||||
|
||||
@@ -81,24 +100,7 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra configuration to append to the aerospace.toml file.
|
||||
This allows you to add raw TOML content, including multiline strings.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
alt-enter = ''''exec-and-forget osascript -e '
|
||||
tell application "Terminal"
|
||||
do script
|
||||
activate
|
||||
end tell'
|
||||
''''
|
||||
'';
|
||||
};
|
||||
|
||||
userSettings = mkOption {
|
||||
settings = mkOption {
|
||||
inherit (tomlFormat) type;
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
@@ -115,6 +117,27 @@ in
|
||||
alt-k = "focus up";
|
||||
alt-l = "focus right";
|
||||
};
|
||||
on-window-detected = [
|
||||
{
|
||||
"if".app-id = "com.apple.finder";
|
||||
run = "move-node-to-workspace 9";
|
||||
}
|
||||
|
||||
{
|
||||
"if" = {
|
||||
app-id = "com.apple.systempreferences";
|
||||
app-name-regex-substring = "settings";
|
||||
window-title-regex-substring = "substring";
|
||||
workspace = "workspace-name";
|
||||
during-aerospace-startup = true;
|
||||
};
|
||||
check-further-callbacks = true;
|
||||
run = [
|
||||
"layout floating"
|
||||
"move-node-to-workspace S"
|
||||
];
|
||||
}
|
||||
];
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
@@ -128,32 +151,68 @@ in
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
(lib.hm.assertions.assertPlatform "programs.aerospace" pkgs lib.platforms.darwin)
|
||||
|
||||
# 1. Fail if user sets start-at-login = true BUT launchd is disabled.
|
||||
{
|
||||
assertion =
|
||||
!((lib.hasAttr "start-at-login" cfg.settings) && (cfg.settings."start-at-login" == true))
|
||||
|| (cfg.launchd.enable == true);
|
||||
message = ''
|
||||
You have set `programs.aerospace.settings."start-at-login" = true;`
|
||||
but `programs.aerospace.launchd.enable` is false.
|
||||
|
||||
This tells AeroSpace to manage its own startup, which can conflict
|
||||
with Home Manager.
|
||||
|
||||
To manage startup with Home Manager, please set
|
||||
`programs.aerospace.launchd.enable = true;`
|
||||
(You can leave `start-at-login = true` in your settings, it will be
|
||||
correctly overridden).
|
||||
'';
|
||||
}
|
||||
|
||||
# 2. Fail if user sets after-login-command (in any case).
|
||||
{
|
||||
assertion =
|
||||
!(
|
||||
(lib.hasAttr "after-login-command" cfg.settings)
|
||||
&& (lib.isList cfg.settings."after-login-command")
|
||||
&& (cfg.settings."after-login-command" != [ ])
|
||||
);
|
||||
message = ''
|
||||
You have set `programs.aerospace.settings."after-login-command"`.
|
||||
|
||||
This setting is not supported when using this Home Manager module,
|
||||
as it either conflicts with the launchd service (if enabled)
|
||||
or bypasses it (if disabled).
|
||||
|
||||
The correct way to run commands after AeroSpace starts is to use:
|
||||
1. `programs.aerospace.launchd.enable = true;`
|
||||
2. `programs.aerospace.settings."after-startup-command" = [ ... ];`
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
home = {
|
||||
packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
|
||||
file.".config/aerospace/aerospace.toml".source =
|
||||
let
|
||||
generatedConfig = tomlFormat.generate "aerospace" (
|
||||
filterNulls (
|
||||
cfg.userSettings
|
||||
// lib.optionalAttrs cfg.launchd.enable {
|
||||
# Override these to avoid launchd conflicts
|
||||
start-at-login = false;
|
||||
after-login-command = [ ];
|
||||
}
|
||||
)
|
||||
);
|
||||
extraConfig = pkgs.writeText "aerospace-extra-config" cfg.extraConfig;
|
||||
in
|
||||
pkgs.runCommandLocal "aerospace.toml"
|
||||
{
|
||||
inherit generatedConfig extraConfig;
|
||||
}
|
||||
''
|
||||
cat "$generatedConfig" "$extraConfig" > "$out"
|
||||
'';
|
||||
file.${configPath} = lib.mkIf (cfg.settings != { }) {
|
||||
source = tomlFormat.generate "aerospace" (
|
||||
filterNulls (
|
||||
cfg.settings
|
||||
// {
|
||||
# Override these to avoid launchd conflicts
|
||||
start-at-login = false;
|
||||
after-login-command = [ ];
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
onChange = lib.mkIf cfg.launchd.enable ''
|
||||
echo "AeroSpace config changed, reloading..."
|
||||
${lib.getExe cfg.package} reload-config
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.aerospace = {
|
||||
|
||||
@@ -82,7 +82,7 @@ in
|
||||
};
|
||||
|
||||
uiScale = lib.mkOption {
|
||||
type = with lib.types; nullOr (numbers.between 0.0 1.0);
|
||||
type = with lib.types; nullOr (numbers.between 1.0 2.0);
|
||||
default = null;
|
||||
example = 1.0;
|
||||
description = "User interface scale.";
|
||||
|
||||
@@ -112,7 +112,7 @@ let
|
||||
|
||||
answer_keys: tuple[tuple[int, str], ...] = (${
|
||||
lib.strings.concatMapStringsSep ", " (val: "(${toString val.ease}, '${val.key}')") cfg.answerKeys
|
||||
})
|
||||
}${if cfg.answerKeys != [ ] then "," else ""})
|
||||
for ease, key in answer_keys:
|
||||
profile_manager.set_answer_key(ease, key)
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ in
|
||||
|
||||
extraCss = mkOption {
|
||||
type = nullOr lines;
|
||||
default = "";
|
||||
default = null;
|
||||
description = ''
|
||||
Extra CSS lines to add to {file}`~/.config/anyrun/style.css`.
|
||||
'';
|
||||
|
||||
@@ -11,7 +11,6 @@ let
|
||||
tomlFormat = pkgs.formats.toml { };
|
||||
|
||||
inherit (lib) mkIf mkOption types;
|
||||
inherit (pkgs.stdenv) isLinux isDarwin;
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
@@ -221,98 +220,82 @@ in
|
||||
};
|
||||
}
|
||||
|
||||
(mkIf daemonCfg.enable (
|
||||
lib.mkMerge [
|
||||
(mkIf daemonCfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertions = [
|
||||
{
|
||||
assertion = lib.versionAtLeast cfg.package.version "18.2.0";
|
||||
message = ''
|
||||
The Atuin daemon requires at least version 18.2.0 or later.
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = isLinux || isDarwin;
|
||||
message = "The Atuin daemon can only be configured on either Linux or macOS.";
|
||||
}
|
||||
];
|
||||
|
||||
programs.atuin.settings = {
|
||||
daemon = {
|
||||
enabled = true;
|
||||
};
|
||||
};
|
||||
assertion = lib.versionAtLeast cfg.package.version "18.2.0";
|
||||
message = ''
|
||||
The Atuin daemon requires at least version 18.2.0 or later.
|
||||
'';
|
||||
}
|
||||
(mkIf isLinux {
|
||||
programs.atuin.settings = {
|
||||
daemon = {
|
||||
systemd_socket = true;
|
||||
};
|
||||
};
|
||||
{
|
||||
assertion = config.systemd.user.enable || config.launchd.enable;
|
||||
message = "The Atuin daemon can only be configured on systems with systemd or launchd.";
|
||||
}
|
||||
];
|
||||
|
||||
systemd.user.services.atuin-daemon = {
|
||||
Unit = {
|
||||
Description = "Atuin daemon";
|
||||
Requires = [ "atuin-daemon.socket" ];
|
||||
};
|
||||
Install = {
|
||||
Also = [ "atuin-daemon.socket" ];
|
||||
WantedBy = [ "default.target" ];
|
||||
};
|
||||
Service = {
|
||||
ExecStart = "${lib.getExe cfg.package} daemon";
|
||||
Environment = lib.optionals (daemonCfg.logLevel != null) [ "ATUIN_LOG=${daemonCfg.logLevel}" ];
|
||||
Restart = "on-failure";
|
||||
RestartSteps = 3;
|
||||
RestartMaxDelaySec = 6;
|
||||
};
|
||||
};
|
||||
programs.atuin.settings.daemon = {
|
||||
enabled = true;
|
||||
systemd_socket = config.systemd.user.enable;
|
||||
socket_path = lib.mkIf (!config.systemd.user.enable) (
|
||||
lib.mkDefault "${config.xdg.dataHome}/atuin/daemon.sock"
|
||||
);
|
||||
};
|
||||
|
||||
systemd.user.sockets.atuin-daemon =
|
||||
let
|
||||
socket_dir = if lib.versionAtLeast cfg.package.version "18.4.0" then "%t" else "%D/atuin";
|
||||
in
|
||||
{
|
||||
Unit = {
|
||||
Description = "Atuin daemon socket";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "sockets.target" ];
|
||||
};
|
||||
Socket = {
|
||||
ListenStream = "${socket_dir}/atuin.sock";
|
||||
SocketMode = "0600";
|
||||
RemoveOnStop = true;
|
||||
};
|
||||
};
|
||||
})
|
||||
(mkIf isDarwin {
|
||||
programs.atuin.settings = {
|
||||
daemon = {
|
||||
socket_path = lib.mkDefault "${config.xdg.dataHome}/atuin/daemon.sock";
|
||||
};
|
||||
};
|
||||
systemd.user.services.atuin-daemon = {
|
||||
Unit = {
|
||||
Description = "Atuin daemon";
|
||||
Requires = [ "atuin-daemon.socket" ];
|
||||
};
|
||||
Install = {
|
||||
Also = [ "atuin-daemon.socket" ];
|
||||
WantedBy = [ "default.target" ];
|
||||
};
|
||||
Service = {
|
||||
ExecStart = "${lib.getExe cfg.package} daemon";
|
||||
Environment = lib.optionals (daemonCfg.logLevel != null) [ "ATUIN_LOG=${daemonCfg.logLevel}" ];
|
||||
Restart = "on-failure";
|
||||
RestartSteps = 3;
|
||||
RestartMaxDelaySec = 6;
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.atuin-daemon = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${lib.getExe cfg.package}"
|
||||
"daemon"
|
||||
];
|
||||
EnvironmentVariables = lib.optionalAttrs (daemonCfg.logLevel != null) {
|
||||
ATUIN_LOG = daemonCfg.logLevel;
|
||||
};
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
};
|
||||
systemd.user.sockets.atuin-daemon =
|
||||
let
|
||||
socket_dir = if lib.versionAtLeast cfg.package.version "18.4.0" then "%t" else "%D/atuin";
|
||||
in
|
||||
{
|
||||
Unit = {
|
||||
Description = "Atuin daemon socket";
|
||||
};
|
||||
})
|
||||
]
|
||||
))
|
||||
Install = {
|
||||
WantedBy = [ "sockets.target" ];
|
||||
};
|
||||
Socket = {
|
||||
ListenStream = "${socket_dir}/atuin.sock";
|
||||
SocketMode = "0600";
|
||||
RemoveOnStop = true;
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.atuin-daemon = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${lib.getExe cfg.package}"
|
||||
"daemon"
|
||||
];
|
||||
EnvironmentVariables = lib.optionalAttrs (daemonCfg.logLevel != null) {
|
||||
ATUIN_LOG = daemonCfg.logLevel;
|
||||
};
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ let
|
||||
cfg = config.programs.bashmount;
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.AndersonTorres ];
|
||||
meta.maintainers = [ ];
|
||||
|
||||
options.programs.bashmount = {
|
||||
enable = lib.mkEnableOption "bashmount";
|
||||
|
||||
44
modules/programs/calibre.nix
Normal file
44
modules/programs/calibre.nix
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
types
|
||||
mkIf
|
||||
mkEnableOption
|
||||
mkPackageOption
|
||||
mkOption
|
||||
;
|
||||
|
||||
cfg = config.programs.calibre;
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.hm.maintainers; [ aguirre-matteo ];
|
||||
options.programs.calibre = {
|
||||
enable = mkEnableOption "calibre";
|
||||
package = mkPackageOption pkgs "calibre" { nullable = true; };
|
||||
plugins = mkOption {
|
||||
type = with types; listOf path;
|
||||
default = [ ];
|
||||
description = "List of plugins to install for calibre";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = mkIf (cfg.package != null) [ cfg.package ];
|
||||
xdg.configFile = mkIf (cfg.plugins != [ ]) (
|
||||
let
|
||||
symlinkedPlugins = pkgs.symlinkJoin {
|
||||
name = "calibre-plugins";
|
||||
paths = cfg.plugins;
|
||||
};
|
||||
in
|
||||
lib.mapAttrs' (
|
||||
k: _: lib.nameValuePair "calibre/plugins/${k}" { source = (symlinkedPlugins + "/${k}"); }
|
||||
) (builtins.readDir symlinkedPlugins)
|
||||
);
|
||||
};
|
||||
}
|
||||
43
modules/programs/cargo.nix
Normal file
43
modules/programs/cargo.nix
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkEnableOption;
|
||||
|
||||
tomlFormat = pkgs.formats.toml { };
|
||||
|
||||
cfg = config.programs.cargo;
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.friedrichaltheide ];
|
||||
|
||||
options = {
|
||||
programs = {
|
||||
cargo = {
|
||||
enable = mkEnableOption "management of cargo config";
|
||||
|
||||
settings = lib.mkOption {
|
||||
inherit (tomlFormat) type;
|
||||
default = { };
|
||||
description = ''
|
||||
Available configuration options for the .cargo/config see:
|
||||
https://doc.rust-lang.org/cargo/reference/config.html
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
home = {
|
||||
file = {
|
||||
".cargo/config.toml" = {
|
||||
source = tomlFormat.generate "config.toml" cfg.settings;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -40,7 +40,7 @@ let
|
||||
|
||||
finalPackage = mkOption {
|
||||
inherit visible;
|
||||
type = types.package;
|
||||
type = types.nullOr types.package;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
Resulting customized ${name} package
|
||||
@@ -220,15 +220,22 @@ let
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
lib.mkIf cfg.enable {
|
||||
programs.${browser}.finalPackage = lib.mkIf (cfg.package != null) (
|
||||
assertions = [
|
||||
{
|
||||
assertion = !(cfg.package == null && cfg.commandLineArgs != [ ]);
|
||||
message = "Cannot set `commandLineArgs` when `package` is null for ${browser}.";
|
||||
}
|
||||
];
|
||||
|
||||
programs.${browser}.finalPackage =
|
||||
if cfg.commandLineArgs != [ ] then
|
||||
cfg.package.override {
|
||||
commandLineArgs = lib.concatStringsSep " " cfg.commandLineArgs;
|
||||
}
|
||||
else
|
||||
cfg.package
|
||||
);
|
||||
cfg.package;
|
||||
|
||||
home.packages = lib.mkIf (cfg.finalPackage != null) [
|
||||
cfg.finalPackage
|
||||
|
||||
@@ -197,6 +197,47 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
rules = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path);
|
||||
default = { };
|
||||
description = ''
|
||||
Modular rule files for Claude Code.
|
||||
The attribute name becomes the rule filename, and the value is either:
|
||||
- Inline content as a string
|
||||
- A path to a file containing the rule content
|
||||
Rules are stored in .claude/rules/ directory.
|
||||
All markdown files in .claude/rules/ are automatically loaded as project memory.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
code-style = '''
|
||||
# Code Style Guidelines
|
||||
|
||||
- Use consistent formatting
|
||||
- Follow language conventions
|
||||
''';
|
||||
testing = '''
|
||||
# Testing Conventions
|
||||
|
||||
- Write tests for all new features
|
||||
- Maintain test coverage above 80%
|
||||
''';
|
||||
security = ./rules/security.md;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
rulesDir = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
description = ''
|
||||
Path to a directory containing rule files for Claude Code.
|
||||
Rule files from this directory will be symlinked to .claude/rules/.
|
||||
All markdown files in this directory are automatically loaded as project memory.
|
||||
'';
|
||||
example = lib.literalExpression "./rules";
|
||||
};
|
||||
|
||||
agentsDir = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
default = null;
|
||||
@@ -325,6 +366,10 @@ in
|
||||
assertion = !(cfg.memory.text != null && cfg.memory.source != null);
|
||||
message = "Cannot specify both `programs.claude-code.memory.text` and `programs.claude-code.memory.source`";
|
||||
}
|
||||
{
|
||||
assertion = !(cfg.rules != { } && cfg.rulesDir != null);
|
||||
message = "Cannot specify both `programs.claude-code.rules` and `programs.claude-code.rulesDir`";
|
||||
}
|
||||
{
|
||||
assertion = !(cfg.agents != { } && cfg.agentsDir != null);
|
||||
message = "Cannot specify both `programs.claude-code.agents` and `programs.claude-code.agentsDir`";
|
||||
@@ -348,7 +393,7 @@ in
|
||||
makeWrapperArgs = lib.flatten (
|
||||
lib.filter (x: x != [ ]) [
|
||||
(lib.optional (cfg.mcpServers != { }) [
|
||||
"--add-flags"
|
||||
"--append-flags"
|
||||
"--mcp-config ${jsonFormat.generate "claude-code-mcp-config.json" { inherit (cfg) mcpServers; }}"
|
||||
])
|
||||
]
|
||||
@@ -386,6 +431,11 @@ in
|
||||
if cfg.memory.text != null then { text = cfg.memory.text; } else { source = cfg.memory.source; }
|
||||
);
|
||||
|
||||
".claude/rules" = lib.mkIf (cfg.rulesDir != null) {
|
||||
source = cfg.rulesDir;
|
||||
recursive = true;
|
||||
};
|
||||
|
||||
".claude/agents" = lib.mkIf (cfg.agentsDir != null) {
|
||||
source = cfg.agentsDir;
|
||||
recursive = true;
|
||||
@@ -406,6 +456,12 @@ in
|
||||
recursive = true;
|
||||
};
|
||||
}
|
||||
// lib.mapAttrs' (
|
||||
name: content:
|
||||
lib.nameValuePair ".claude/rules/${name}.md" (
|
||||
if lib.isPath content then { source = content; } else { text = content; }
|
||||
)
|
||||
) cfg.rules
|
||||
// lib.mapAttrs' (
|
||||
name: content:
|
||||
lib.nameValuePair ".claude/agents/${name}.md" (
|
||||
|
||||
@@ -68,8 +68,15 @@ in
|
||||
in
|
||||
lib.mkMerge [
|
||||
(mkIf cfg.enable {
|
||||
# Auto-enable git integration if programs.git.diff-highlight.enable was set to true
|
||||
programs.diff-highlight.enableGitIntegration = lib.mkIf oldOptionEnabled (lib.mkOverride 1490 true);
|
||||
assertions = [
|
||||
{
|
||||
assertion = !cfg.enableGitIntegration || config.programs.git.package != null;
|
||||
message = ''
|
||||
programs.diff-highlight.enableGitIntegration requires programs.git.package to be set.
|
||||
Please set programs.git.package to a valid git package.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
warnings =
|
||||
lib.optional
|
||||
@@ -77,9 +84,12 @@ in
|
||||
cfg.enableGitIntegration && options.programs.diff-highlight.enableGitIntegration.highestPrio == 1490
|
||||
)
|
||||
"`programs.diff-highlight.enableGitIntegration` automatic enablement is deprecated. Please explicitly set `programs.diff-highlight.enableGitIntegration = true`.";
|
||||
|
||||
# Auto-enable git integration if programs.git.diff-highlight.enable was set to true
|
||||
programs.diff-highlight.enableGitIntegration = lib.mkIf oldOptionEnabled (lib.mkOverride 1490 true);
|
||||
})
|
||||
|
||||
(mkIf (cfg.enable && cfg.enableGitIntegration) {
|
||||
(mkIf (cfg.enable && cfg.enableGitIntegration && config.programs.git.package != null) {
|
||||
programs.git = {
|
||||
enable = lib.mkDefault true;
|
||||
iniContent =
|
||||
|
||||
@@ -75,25 +75,7 @@ in
|
||||
|
||||
enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { inherit config; };
|
||||
|
||||
enableFishIntegration =
|
||||
lib.hm.shell.mkFishIntegrationOption {
|
||||
inherit config;
|
||||
extraDescription = ''
|
||||
Note, enabling the direnv module will always activate its functionality
|
||||
for Fish since the direnv package automatically gets loaded in Fish.
|
||||
If this is not the case try adding
|
||||
|
||||
```nix
|
||||
environment.pathsToLink = [ "/share/fish" ];
|
||||
```
|
||||
|
||||
to the system configuration.
|
||||
'';
|
||||
}
|
||||
// {
|
||||
default = true;
|
||||
readOnly = true;
|
||||
};
|
||||
enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { inherit config; };
|
||||
|
||||
enableNushellIntegration = lib.hm.shell.mkNushellIntegrationOption { inherit config; };
|
||||
|
||||
|
||||
@@ -645,7 +645,7 @@ in
|
||||
# Support completion for `man` by building a cache for `apropos`.
|
||||
programs.man.generateCaches = lib.mkDefault true;
|
||||
|
||||
xdg.dataFile."fish/home-manager_generated_completions".source =
|
||||
xdg.dataFile."fish/home-manager/generated_completions".source =
|
||||
let
|
||||
# Paths later in the list will overwrite those already linked
|
||||
destructiveSymlinkJoin =
|
||||
@@ -696,7 +696,7 @@ in
|
||||
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
|
||||
set fish_complete_path $prev "${config.xdg.dataHome}/fish/home-manager/generated_completions" $post
|
||||
end
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -21,14 +21,19 @@ in
|
||||
settings = lib.mkOption {
|
||||
inherit (jsonFormat) type;
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
"theme": "Default",
|
||||
"vimMode": true,
|
||||
"preferredEditor": "nvim",
|
||||
"autoAccept": true
|
||||
}
|
||||
'';
|
||||
example = {
|
||||
ui.theme = "Default";
|
||||
general = {
|
||||
vimMode = true;
|
||||
preferredEditor = "nvim";
|
||||
previewFeatures = true;
|
||||
};
|
||||
ide.enabled = true;
|
||||
privacy.usageStatisticsEnabled = false;
|
||||
tools.autoAccept = false;
|
||||
context.loadMemoryFromIncludeDirectories = true;
|
||||
security.auth.selectedType = "oauth-personal";
|
||||
};
|
||||
description = "JSON config for gemini-cli";
|
||||
};
|
||||
|
||||
@@ -81,12 +86,12 @@ in
|
||||
};
|
||||
|
||||
defaultModel = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "gemini-2.5-pro";
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "gemini-2.5-flash";
|
||||
description = ''
|
||||
The default model to use for the CLI.
|
||||
Will be set as $GEMINI_MODEL.
|
||||
Will be set as $GEMINI_MODEL when configured.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -138,7 +143,9 @@ in
|
||||
file.".gemini/settings.json" = lib.mkIf (cfg.settings != { }) {
|
||||
source = jsonFormat.generate "gemini-cli-settings.json" cfg.settings;
|
||||
};
|
||||
sessionVariables.GEMINI_MODEL = cfg.defaultModel;
|
||||
sessionVariables = lib.mkIf (cfg.defaultModel != null) {
|
||||
GEMINI_MODEL = cfg.defaultModel;
|
||||
};
|
||||
};
|
||||
}
|
||||
{
|
||||
|
||||
@@ -224,8 +224,24 @@ in
|
||||
message = "Ghostty systemd integration cannot be enabled for non-linux platforms";
|
||||
}
|
||||
];
|
||||
|
||||
xdg.configFile."systemd/user/app-com.mitchellh.ghostty.service".source =
|
||||
"${cfg.package}/share/systemd/user/app-com.mitchellh.ghostty.service";
|
||||
|
||||
xdg.configFile."systemd/user/app-com.mitchellh.ghostty.service.d/overrides.conf".text = ''
|
||||
[Unit]
|
||||
X-SwitchMethod=keep-old
|
||||
X-Reload-Triggers=${
|
||||
let
|
||||
storePathOf = name: config.xdg.configFile.${name}.source;
|
||||
in
|
||||
toString (
|
||||
lib.optionals (cfg.settings != { }) [ (storePathOf "ghostty/config") ]
|
||||
++ lib.mapAttrsToList (name: _: storePathOf "ghostty/themes/${name}") cfg.themes
|
||||
)
|
||||
}
|
||||
'';
|
||||
|
||||
dbus.packages = [ cfg.package ];
|
||||
})
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ in
|
||||
enable = mkEnableOption "Git";
|
||||
|
||||
package = lib.mkPackageOption pkgs "git" {
|
||||
nullable = true;
|
||||
example = "pkgs.gitFull";
|
||||
extraDescription = ''
|
||||
Use {var}`pkgs.gitFull`
|
||||
@@ -328,7 +329,7 @@ in
|
||||
config = mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
home.packages = [ cfg.package ];
|
||||
home.packages = lib.optionals (cfg.package != null) [ cfg.package ];
|
||||
|
||||
assertions = [
|
||||
{
|
||||
@@ -516,7 +517,7 @@ in
|
||||
Type = "oneshot";
|
||||
ExecStart =
|
||||
let
|
||||
exe = lib.getExe cfg.package;
|
||||
exe = if cfg.package != null then lib.getExe cfg.package else "git";
|
||||
in
|
||||
''
|
||||
"${exe}" for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%i
|
||||
@@ -553,7 +554,7 @@ in
|
||||
launchd.agents =
|
||||
let
|
||||
baseArguments = [
|
||||
"${lib.getExe cfg.package}"
|
||||
"${if cfg.package != null then lib.getExe cfg.package else "git"}"
|
||||
"for-each-repo"
|
||||
"--keep-going"
|
||||
"--config=maintenance.repo"
|
||||
|
||||
@@ -16,18 +16,13 @@ let
|
||||
|
||||
cfg = config.programs.gpg;
|
||||
|
||||
mkKeyValue =
|
||||
key: value: if lib.isString value then "${key} ${value}" else lib.optionalString value key;
|
||||
|
||||
cfgText = lib.generators.toKeyValue {
|
||||
inherit mkKeyValue;
|
||||
listsAsDuplicateKeys = true;
|
||||
} cfg.settings;
|
||||
|
||||
scdaemonCfgText = lib.generators.toKeyValue {
|
||||
inherit mkKeyValue;
|
||||
listsAsDuplicateKeys = true;
|
||||
} cfg.scdaemonSettings;
|
||||
toKeyValue =
|
||||
settings:
|
||||
lib.generators.toKeyValue {
|
||||
mkKeyValue =
|
||||
key: value: if lib.isString value then "${key} ${value}" else lib.optionalString value key;
|
||||
listsAsDuplicateKeys = true;
|
||||
} settings;
|
||||
|
||||
primitiveType = types.oneOf [
|
||||
types.str
|
||||
@@ -193,6 +188,7 @@ in
|
||||
|
||||
scdaemonSettings = mkOption {
|
||||
type = types.attrsOf (types.either primitiveType (types.listOf types.str));
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
disable-ccid = true;
|
||||
@@ -207,6 +203,41 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
dirmngrSettings = mkOption {
|
||||
type = types.attrsOf (types.either primitiveType (types.listOf types.str));
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
allow-version-check = true;
|
||||
keyserver = "ldaps://ldap.example.com";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Dirmngr configuration options. Available options are described
|
||||
in
|
||||
[
|
||||
{manpage}`dirmngr(1)`
|
||||
](https://www.gnupg.org/documentation/manuals/gnupg/Dirmngr-Options.html)
|
||||
'';
|
||||
};
|
||||
|
||||
gpgsmSettings = mkOption {
|
||||
type = types.attrsOf (types.either primitiveType (types.listOf types.str));
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
with-key-data = true;
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
GPGSM configuration options. Available options are described
|
||||
in
|
||||
[
|
||||
{manpage}`gpgsm(1)`
|
||||
](https://www.gnupg.org/documentation/manuals/gnupg/GPGSM-Options.html)
|
||||
'';
|
||||
};
|
||||
|
||||
homedir = mkOption {
|
||||
type = types.path;
|
||||
example = literalExpression ''"''${config.xdg.dataHome}/gnupg"'';
|
||||
@@ -267,8 +298,7 @@ in
|
||||
cert-digest-algo = mkDefault "SHA512";
|
||||
s2k-digest-algo = mkDefault "SHA512";
|
||||
s2k-cipher-algo = mkDefault "AES256";
|
||||
charset = mkDefault "utf-8";
|
||||
fixed-list-mode = mkDefault true;
|
||||
display-charset = mkDefault "utf-8";
|
||||
no-comments = mkDefault true;
|
||||
no-emit-version = mkDefault true;
|
||||
keyid-format = mkDefault "0xlong";
|
||||
@@ -277,11 +307,6 @@ in
|
||||
with-fingerprint = mkDefault true;
|
||||
require-cross-certification = mkDefault true;
|
||||
no-symkey-cache = mkDefault true;
|
||||
use-agent = mkDefault true;
|
||||
};
|
||||
|
||||
programs.gpg.scdaemonSettings = {
|
||||
# no defaults for scdaemon
|
||||
};
|
||||
|
||||
home.packages = [ cfg.package ];
|
||||
@@ -289,9 +314,21 @@ in
|
||||
GNUPGHOME = cfg.homedir;
|
||||
};
|
||||
|
||||
home.file."${cfg.homedir}/gpg.conf".text = cfgText;
|
||||
home.file."${cfg.homedir}/gpg.conf" = mkIf (cfg.settings != { }) {
|
||||
text = toKeyValue cfg.settings;
|
||||
};
|
||||
|
||||
home.file."${cfg.homedir}/scdaemon.conf".text = scdaemonCfgText;
|
||||
home.file."${cfg.homedir}/scdaemon.conf" = mkIf (cfg.scdaemonSettings != { }) {
|
||||
text = toKeyValue cfg.scdaemonSettings;
|
||||
};
|
||||
|
||||
home.file."${cfg.homedir}/dirmngr.conf" = mkIf (cfg.dirmngrSettings != { }) {
|
||||
text = toKeyValue cfg.dirmngrSettings;
|
||||
};
|
||||
|
||||
home.file."${cfg.homedir}/gpgsm.conf" = mkIf (cfg.gpgsmSettings != { }) {
|
||||
text = toKeyValue cfg.gpgsmSettings;
|
||||
};
|
||||
|
||||
# Link keyring if keys are not mutable
|
||||
home.file."${cfg.homedir}/pubring.kbx" = mkIf (!cfg.mutableKeys && cfg.publicKeys != [ ]) {
|
||||
|
||||
@@ -9,7 +9,7 @@ let
|
||||
iniFormat = pkgs.formats.ini { };
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ AndersonTorres ];
|
||||
meta.maintainers = with lib.maintainers; [ ];
|
||||
|
||||
options.programs.havoc = {
|
||||
enable = lib.mkEnableOption "Havoc terminal";
|
||||
|
||||
@@ -49,7 +49,8 @@ in
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to configure {command}`hx` as the default
|
||||
editor using the {env}`EDITOR` environment variable.
|
||||
editor using the {env}`EDITOR` and {env}`VISUAL`
|
||||
environment variables.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -225,7 +226,10 @@ in
|
||||
else
|
||||
[ cfg.package ];
|
||||
|
||||
home.sessionVariables = mkIf cfg.defaultEditor { EDITOR = "hx"; };
|
||||
home.sessionVariables = mkIf cfg.defaultEditor {
|
||||
EDITOR = "hx";
|
||||
VISUAL = "hx";
|
||||
};
|
||||
|
||||
xdg.configFile =
|
||||
let
|
||||
|
||||
@@ -9,7 +9,7 @@ let
|
||||
jsonFormat = pkgs.formats.json { };
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.perchun ];
|
||||
meta.maintainers = [ lib.maintainers.PerchunPak ];
|
||||
|
||||
imports = [
|
||||
(lib.mkRemovedOptionModule [ "programs" "hyprpanel" "dontAssertNotificationDaemons " ] ''
|
||||
|
||||
81
modules/programs/infat.nix
Normal file
81
modules/programs/infat.nix
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.programs.infat;
|
||||
tomlFormat = pkgs.formats.toml { };
|
||||
|
||||
configDir =
|
||||
if config.xdg.enable then
|
||||
config.xdg.configHome
|
||||
else
|
||||
"${config.home.homeDirectory}/Library/Application Support";
|
||||
|
||||
configFile = "${configDir}/infat/config.toml";
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
mirkolenz
|
||||
];
|
||||
|
||||
options = {
|
||||
programs.infat = {
|
||||
enable = lib.mkEnableOption "infat";
|
||||
package = lib.mkPackageOption pkgs "infat" { nullable = true; };
|
||||
settings = lib.mkOption {
|
||||
type = tomlFormat.type;
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
extensions = {
|
||||
md = "TextEdit";
|
||||
html = "Safari";
|
||||
pdf = "Preview";
|
||||
};
|
||||
schemes = {
|
||||
mailto = "Mail";
|
||||
web = "Safari";
|
||||
};
|
||||
types = {
|
||||
plain-text = "VSCode";
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Configuration written to
|
||||
{file}`$XDG_CONFIG_HOME/infat/config.toml`.
|
||||
'';
|
||||
};
|
||||
autoActivate = lib.mkEnableOption "auto-activate infat" // {
|
||||
default = true;
|
||||
example = false;
|
||||
description = ''
|
||||
Automatically activate infat on startup.
|
||||
This is useful if you want to use infat as a
|
||||
default application handler for certain file types.
|
||||
If you don't want this, set this to false.
|
||||
This option is only effective if `settings` is set.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
(lib.hm.assertions.assertPlatform "programs.infat" pkgs lib.platforms.darwin)
|
||||
];
|
||||
home = {
|
||||
packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
file.${configFile} = lib.mkIf (cfg.settings != { }) {
|
||||
source = tomlFormat.generate "infat-settings.toml" cfg.settings;
|
||||
};
|
||||
activation = lib.mkIf (cfg.settings != { } && cfg.package != null && cfg.autoActivate) {
|
||||
infat = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||
run ${lib.getExe cfg.package} --config "${configFile}" $VERBOSE_ARG
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -705,7 +705,8 @@ in
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to configure {command}`kak` as the default
|
||||
editor using the {env}`EDITOR` environment variable.
|
||||
editor using the {env}`EDITOR` and {env}`VISUAL`
|
||||
environment variables.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -755,7 +756,10 @@ in
|
||||
programs.kakoune.finalPackage = lib.mkIf (cfg.package != null) kakouneWithPlugins;
|
||||
|
||||
home.packages = lib.mkIf (cfg.finalPackage != null) [ cfg.finalPackage ];
|
||||
home.sessionVariables = mkIf cfg.defaultEditor { EDITOR = "kak"; };
|
||||
home.sessionVariables = mkIf cfg.defaultEditor {
|
||||
EDITOR = "kak";
|
||||
VISUAL = "kak";
|
||||
};
|
||||
xdg.configFile = lib.mkMerge [
|
||||
{ "kak/kakrc".source = configFile; }
|
||||
(mkIf (cfg.colorSchemePackage != null) {
|
||||
|
||||
@@ -62,8 +62,15 @@ in
|
||||
Configuration written to
|
||||
{file}`$XDG_CONFIG_HOME/keepassxc/keepassxc.ini`.
|
||||
|
||||
See <https://github.com/keepassxreboot/keepassxc/blob/647272e9c5542297d3fcf6502e6173c96f12a9a0/src/core/Config.cpp#L49-L223>
|
||||
See <https://github.com/keepassxreboot/keepassxc/blob/develop/src/core/Config.cpp>
|
||||
for the full list of options.
|
||||
|
||||
::: {.note}
|
||||
When the settings are non-empty, the configuration file will be linked
|
||||
into the Nix store and KeePassXC will report an access error for its
|
||||
configuration file. This is expected and can not be fixed in a way that
|
||||
aligns with Home Manager's principles. See [#8257](https://github.com/nix-community/home-manager/issues/8257) for more details.
|
||||
:::
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
@@ -37,13 +37,17 @@ in
|
||||
options = lib.mkOption {
|
||||
type =
|
||||
with lib.types;
|
||||
attrsOf (oneOf [
|
||||
bool
|
||||
int
|
||||
str
|
||||
]);
|
||||
default = { };
|
||||
description = "GNU-style options to be set via {env}`$LESS`.";
|
||||
let
|
||||
scalar = oneOf [
|
||||
bool
|
||||
int
|
||||
str
|
||||
];
|
||||
attrs = attrsOf (either scalar (listOf scalar));
|
||||
in
|
||||
coercedTo attrs (lib.cli.toGNUCommandLine { }) (listOf str);
|
||||
default = [ ];
|
||||
description = "Options to be set via {env}`$LESS`.";
|
||||
example = {
|
||||
RAW-CONTROL-CHARS = true;
|
||||
quiet = true;
|
||||
@@ -58,10 +62,10 @@ in
|
||||
|
||||
xdg.configFile."lesskey" = lib.mkIf (cfg.config != "") { text = cfg.config; };
|
||||
|
||||
programs.less.config = lib.mkIf (cfg.options != { }) (
|
||||
programs.less.config = lib.mkIf (cfg.options != [ ]) (
|
||||
lib.mkBefore ''
|
||||
#env
|
||||
LESS = ${lib.cli.toGNUCommandLineShell { } cfg.options}
|
||||
LESS = ${lib.concatStringsSep " " cfg.options}
|
||||
''
|
||||
);
|
||||
};
|
||||
|
||||
@@ -24,7 +24,8 @@ let
|
||||
meliAccounts = (lib.attrsets.mapAttrs (name: value: (mkMeliAccounts name value)) enabledAccounts);
|
||||
|
||||
mkMeliAccounts = (
|
||||
name: account: {
|
||||
name: account:
|
||||
{
|
||||
root_mailbox = "${config.accounts.email.maildirBasePath}/${account.maildir.path}";
|
||||
format = "Maildir";
|
||||
identity = account.address;
|
||||
@@ -33,6 +34,14 @@ let
|
||||
send_mail = mkSmtp account;
|
||||
mailboxes = account.meli.mailboxAliases;
|
||||
}
|
||||
// lib.optionalAttrs (account.flavor == "fastmail.com") {
|
||||
server_username = account.userName;
|
||||
server_password_command = lib.concatMapStringsSep " " lib.escapeShellArg account.passwordCommand;
|
||||
format = "jmap";
|
||||
server_url = "https://api.fastmail.com/jmap/session";
|
||||
use_token = true;
|
||||
}
|
||||
// account.meli.settings
|
||||
);
|
||||
|
||||
mkSmtp = account: {
|
||||
@@ -153,6 +162,14 @@ in
|
||||
};
|
||||
description = "Folder display name";
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = types.submodule {
|
||||
freeformType = tomlFormat.type;
|
||||
};
|
||||
default = { };
|
||||
description = "Account specific meli configuration";
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
@@ -160,6 +177,15 @@ in
|
||||
};
|
||||
};
|
||||
config = mkIf config.programs.meli.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.settings ? accounts == false;
|
||||
message = ''
|
||||
programs.meli.settings.accounts override the accounts.email values.
|
||||
Use per-email accounts.email.<ACCOUNT>.meli.settings instead'';
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = [ config.programs.meli.package ];
|
||||
|
||||
# Generate meli configuration from email accounts
|
||||
|
||||
@@ -7,121 +7,46 @@
|
||||
|
||||
let
|
||||
inherit (lib)
|
||||
concatMapStringsSep
|
||||
literalExpression
|
||||
mkEnableOption
|
||||
mkIf
|
||||
mkOption
|
||||
mkRemovedOptionModule
|
||||
mkPackageOption
|
||||
optionals
|
||||
types
|
||||
;
|
||||
|
||||
cfg = config.programs.neovim;
|
||||
|
||||
fileType =
|
||||
(import ../lib/file-type.nix {
|
||||
inherit (config.home) homeDirectory;
|
||||
inherit lib pkgs;
|
||||
}).fileType;
|
||||
inherit
|
||||
(
|
||||
(import ../lib/file-type.nix {
|
||||
inherit (config.home) homeDirectory;
|
||||
inherit lib pkgs;
|
||||
})
|
||||
)
|
||||
fileType
|
||||
;
|
||||
|
||||
jsonFormat = pkgs.formats.json { };
|
||||
|
||||
pluginWithConfigType = types.submodule {
|
||||
options = {
|
||||
config = mkOption {
|
||||
type = types.nullOr types.lines;
|
||||
description = "Script to configure this plugin. The scripting language should match type.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
type = mkOption {
|
||||
type = types.either (types.enum [
|
||||
"lua"
|
||||
"viml"
|
||||
"teal"
|
||||
"fennel"
|
||||
]) types.str;
|
||||
description = "Language used in config. Configurations are aggregated per-language.";
|
||||
default = "viml";
|
||||
};
|
||||
|
||||
optional = mkEnableOption "optional" // {
|
||||
description = "Don't load by default (load with :packadd)";
|
||||
};
|
||||
|
||||
plugin = lib.mkPackageOption pkgs.vimPlugins "plugin" {
|
||||
default = null;
|
||||
example = "pkgs.vimPlugins.nvim-treesitter";
|
||||
pkgsText = "pkgs.vimPlugins";
|
||||
};
|
||||
|
||||
runtime = mkOption {
|
||||
default = { };
|
||||
# passing actual "${xdg.configHome}/nvim" as basePath was a bit tricky
|
||||
# due to how fileType.target is implemented
|
||||
type = fileType "programs.neovim.plugins._.runtime" "{var}`xdg.configHome/nvim`" "nvim";
|
||||
example = literalExpression ''
|
||||
{ "ftplugin/c.vim".text = "setlocal omnifunc=v:lua.vim.lsp.omnifunc"; }
|
||||
'';
|
||||
description = ''
|
||||
Set of files that have to be linked in nvim config folder.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
allPlugins =
|
||||
cfg.plugins
|
||||
++ lib.optional cfg.coc.enable {
|
||||
type = "viml";
|
||||
plugin = cfg.coc.package;
|
||||
config = cfg.coc.pluginConfig;
|
||||
optional = false;
|
||||
};
|
||||
|
||||
luaPackages = cfg.finalPackage.unwrapped.lua.pkgs;
|
||||
resolvedExtraLuaPackages = cfg.extraLuaPackages luaPackages;
|
||||
|
||||
extraMakeWrapperArgs = lib.optionalString (
|
||||
cfg.extraPackages != [ ]
|
||||
) ''--suffix PATH : "${lib.makeBinPath cfg.extraPackages}"'';
|
||||
extraMakeWrapperLuaCArgs =
|
||||
lib.optionalString (resolvedExtraLuaPackages != [ ])
|
||||
''--suffix LUA_CPATH ";" "${
|
||||
lib.concatMapStringsSep ";" luaPackages.getLuaCPath resolvedExtraLuaPackages
|
||||
}"'';
|
||||
extraMakeWrapperLuaArgs =
|
||||
lib.optionalString (resolvedExtraLuaPackages != [ ])
|
||||
''--suffix LUA_PATH ";" "${
|
||||
lib.concatMapStringsSep ";" luaPackages.getLuaPath resolvedExtraLuaPackages
|
||||
}"'';
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ khaneliman ];
|
||||
|
||||
imports = [
|
||||
(mkRemovedOptionModule [
|
||||
"programs"
|
||||
"neovim"
|
||||
"withPython"
|
||||
] "Python2 support has been removed from neovim.")
|
||||
(mkRemovedOptionModule [
|
||||
"programs"
|
||||
"neovim"
|
||||
"extraPythonPackages"
|
||||
] "Python2 support has been removed from neovim.")
|
||||
(mkRemovedOptionModule [ "programs" "neovim" "configure" ] ''
|
||||
programs.neovim.configure is deprecated.
|
||||
Other programs.neovim options can override its settings or ignore them.
|
||||
Please use the other options at your disposal:
|
||||
configure.packages.*.opt -> programs.neovim.plugins = [ { plugin = ...; optional = true; }]
|
||||
configure.packages.*.start -> programs.neovim.plugins = [ { plugin = ...; }]
|
||||
configure.customRC -> programs.neovim.extraConfig
|
||||
'')
|
||||
];
|
||||
options = {
|
||||
programs.neovim = {
|
||||
enable = mkEnableOption "Neovim";
|
||||
|
||||
package = mkPackageOption pkgs "neovim" { default = "neovim-unwrapped"; };
|
||||
|
||||
finalPackage = mkOption {
|
||||
type = types.package;
|
||||
readOnly = true;
|
||||
description = "Resulting customized neovim package.";
|
||||
};
|
||||
|
||||
# Aliases
|
||||
viAlias = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -146,6 +71,17 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
defaultEditor = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to configure {command}`nvim` as the default
|
||||
editor using the {env}`EDITOR` and {env}`VISUAL`
|
||||
environment variables.
|
||||
'';
|
||||
};
|
||||
|
||||
# Providers & Runtimes
|
||||
withNodeJs = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -155,11 +91,12 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
withRuby = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = true;
|
||||
withPerl = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Enable ruby provider.
|
||||
Enable perl provider. Set to `true` to
|
||||
use Perl plugins.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -172,21 +109,16 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
withRuby = mkOption {
|
||||
type = types.nullOr types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Enable ruby provider.
|
||||
'';
|
||||
};
|
||||
|
||||
extraPython3Packages = mkOption {
|
||||
# In case we get a plain list, we need to turn it into a function,
|
||||
# as expected by the function in nixpkgs.
|
||||
# The only way to do so is to call `const`, which will ignore its input.
|
||||
type =
|
||||
let
|
||||
fromType = types.listOf types.package;
|
||||
in
|
||||
types.coercedTo fromType (lib.flip lib.warn lib.const ''
|
||||
Assigning a plain list to extraPython3Packages is deprecated.
|
||||
Please assign a function taking a package set as argument, so
|
||||
extraPython3Packages = [ pkgs.python3Packages.xxx ];
|
||||
should become
|
||||
extraPython3Packages = ps: [ ps.xxx ];
|
||||
'') (types.functionTo fromType);
|
||||
type = types.functionTo (types.listOf types.package);
|
||||
default = _: [ ];
|
||||
defaultText = literalExpression "ps: [ ]";
|
||||
example = literalExpression "pyPkgs: with pyPkgs; [ python-language-server ]";
|
||||
@@ -198,21 +130,8 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
# We get the Lua package from the final package and use its
|
||||
# Lua packageset to evaluate the function that this option was set to.
|
||||
# This ensures that we always use the same Lua version as the Neovim package.
|
||||
extraLuaPackages = mkOption {
|
||||
type =
|
||||
let
|
||||
fromType = types.listOf types.package;
|
||||
in
|
||||
types.coercedTo fromType (lib.flip lib.warn lib.const ''
|
||||
Assigning a plain list to extraLuaPackages is deprecated.
|
||||
Please assign a function taking a package set as argument, so
|
||||
extraLuaPackages = [ pkgs.lua51Packages.xxx ];
|
||||
should become
|
||||
extraLuaPackages = ps: [ ps.xxx ];
|
||||
'') (types.functionTo fromType);
|
||||
type = types.functionTo (types.listOf types.package);
|
||||
default = _: [ ];
|
||||
defaultText = literalExpression "ps: [ ]";
|
||||
example = literalExpression "luaPkgs: with luaPkgs; [ luautf8 ]";
|
||||
@@ -224,8 +143,34 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
# Wrapper Configuration
|
||||
extraName = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = ''
|
||||
Extra name appended to the wrapper package name.
|
||||
'';
|
||||
};
|
||||
|
||||
autowrapRuntimeDeps = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to automatically wrap the binary with the runtime dependencies of the plugins.
|
||||
'';
|
||||
};
|
||||
|
||||
waylandSupport = mkOption {
|
||||
type = types.bool;
|
||||
default = pkgs.stdenv.isLinux;
|
||||
defaultText = literalExpression "pkgs.stdenv.isLinux";
|
||||
description = ''
|
||||
Whether to enable Wayland clipboard support.
|
||||
'';
|
||||
};
|
||||
|
||||
extraWrapperArgs = mkOption {
|
||||
type = with types; listOf str;
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
example = literalExpression ''
|
||||
[
|
||||
@@ -246,53 +191,14 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
generatedConfigViml = mkOption {
|
||||
type = types.lines;
|
||||
visible = true;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
Generated vimscript config.
|
||||
'';
|
||||
};
|
||||
|
||||
generatedConfigs = mkOption {
|
||||
type = types.attrsOf types.lines;
|
||||
visible = true;
|
||||
readOnly = true;
|
||||
example = literalExpression ''
|
||||
{
|
||||
viml = '''
|
||||
" Generated by home-manager
|
||||
map <leader> ,
|
||||
''';
|
||||
|
||||
lua = '''
|
||||
-- Generated by home-manager
|
||||
vim.opt.background = "dark"
|
||||
''';
|
||||
}'';
|
||||
description = ''
|
||||
Generated configurations with as key their language (set via type).
|
||||
'';
|
||||
};
|
||||
|
||||
package = lib.mkPackageOption pkgs "neovim" { default = "neovim-unwrapped"; };
|
||||
|
||||
finalPackage = mkOption {
|
||||
type = types.package;
|
||||
readOnly = true;
|
||||
description = "Resulting customized neovim package.";
|
||||
};
|
||||
|
||||
defaultEditor = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to configure {command}`nvim` as the default
|
||||
editor using the {env}`EDITOR` environment variable.
|
||||
'';
|
||||
extraPackages = mkOption {
|
||||
type = types.listOf types.package;
|
||||
default = [ ];
|
||||
example = literalExpression "[ pkgs.shfmt ]";
|
||||
description = "Extra packages available to nvim.";
|
||||
};
|
||||
|
||||
# Configuration & Plugins
|
||||
extraConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
@@ -307,45 +213,92 @@ in
|
||||
extraLuaConfig = mkOption {
|
||||
type = types.lines;
|
||||
default = "";
|
||||
example = ''
|
||||
vim.opt.nobackup = true
|
||||
example = lib.literalExpression ''
|
||||
let
|
||||
nvimEarlyInit = lib.mkOrder 500 "set rtp+=vim.opt.rtp:prepend('/home/user/myplugin')";
|
||||
nvimLateInit = lib.mkAfter "vim.opt.signcolumn = 'auto:1-3'";
|
||||
in
|
||||
lib.mkMerge [ nvimEarlyInit nvimLateInit ];
|
||||
'';
|
||||
description = ''
|
||||
Custom lua lines.
|
||||
Content to be added to {file}`init.lua`.
|
||||
|
||||
To specify the order, use `lib.mkOrder`, `lib.mkBefore`, `lib.mkAfter`.
|
||||
'';
|
||||
};
|
||||
|
||||
extraPackages = mkOption {
|
||||
type = with types; listOf package;
|
||||
default = [ ];
|
||||
example = literalExpression "[ pkgs.shfmt ]";
|
||||
description = "Extra packages available to nvim.";
|
||||
};
|
||||
plugins =
|
||||
let
|
||||
pluginWithConfigType = types.submodule {
|
||||
options = {
|
||||
config = mkOption {
|
||||
type = types.nullOr types.lines;
|
||||
description = "Script to configure this plugin. The scripting language should match type.";
|
||||
default = null;
|
||||
};
|
||||
|
||||
plugins = mkOption {
|
||||
type = with types; listOf (either package pluginWithConfigType);
|
||||
default = [ ];
|
||||
example = literalExpression ''
|
||||
with pkgs.vimPlugins; [
|
||||
yankring
|
||||
vim-nix
|
||||
{ plugin = vim-startify;
|
||||
config = "let g:startify_change_to_vcs_root = 0";
|
||||
}
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
List of vim plugins to install optionally associated with
|
||||
configuration to be placed in init.vim.
|
||||
type = mkOption {
|
||||
type = types.either (types.enum [
|
||||
"lua"
|
||||
"viml"
|
||||
"teal"
|
||||
"fennel"
|
||||
]) types.str;
|
||||
description = "Language used in config. Configurations are aggregated per-language.";
|
||||
default = "viml";
|
||||
};
|
||||
|
||||
This option is mutually exclusive with {var}`configure`.
|
||||
'';
|
||||
};
|
||||
optional = mkEnableOption "optional" // {
|
||||
description = "Don't load by default (load with :packadd)";
|
||||
};
|
||||
|
||||
plugin = mkPackageOption pkgs.vimPlugins "plugin" {
|
||||
default = null;
|
||||
example = "pkgs.vimPlugins.nvim-treesitter";
|
||||
pkgsText = "pkgs.vimPlugins";
|
||||
};
|
||||
|
||||
runtime = mkOption {
|
||||
default = { };
|
||||
# passing actual "${xdg.configHome}/nvim" as basePath was a bit tricky
|
||||
# due to how fileType.target is implemented
|
||||
type = fileType "programs.neovim.plugins._.runtime" "{var}`xdg.configHome/nvim`" "nvim";
|
||||
example = literalExpression ''
|
||||
{ "ftplugin/c.vim".text = "setlocal omnifunc=v:lua.vim.lsp.omnifunc"; }
|
||||
'';
|
||||
description = ''
|
||||
Set of files that have to be linked in nvim config folder.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
mkOption {
|
||||
type = types.listOf (types.either types.package pluginWithConfigType);
|
||||
default = [ ];
|
||||
example = literalExpression ''
|
||||
with pkgs.vimPlugins;
|
||||
[
|
||||
yankring
|
||||
vim-nix
|
||||
{ plugin = vim-startify;
|
||||
config = "let g:startify_change_to_vcs_root = 0";
|
||||
}
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
List of vim plugins to install optionally associated with
|
||||
configuration to be placed in init.vim.
|
||||
|
||||
This option is mutually exclusive with {var}`configure`.
|
||||
'';
|
||||
};
|
||||
|
||||
coc = {
|
||||
enable = mkEnableOption "Coc";
|
||||
|
||||
package = lib.mkPackageOption pkgs "coc-nvim" {
|
||||
package = mkPackageOption pkgs "coc-nvim" {
|
||||
default = [
|
||||
"vimPlugins"
|
||||
"coc-nvim"
|
||||
@@ -375,7 +328,7 @@ in
|
||||
filetypes = [ "haskell" "lhaskell" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Extra configuration lines to add to
|
||||
@@ -392,11 +345,52 @@ in
|
||||
description = "Script to configure CoC. Must be viml.";
|
||||
};
|
||||
};
|
||||
|
||||
# Generated / Read-Only
|
||||
generatedConfigViml = mkOption {
|
||||
type = types.lines;
|
||||
visible = true;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
Generated vimscript config.
|
||||
'';
|
||||
};
|
||||
|
||||
generatedConfigs = mkOption {
|
||||
type = types.attrsOf types.lines;
|
||||
visible = true;
|
||||
readOnly = true;
|
||||
example = literalExpression ''
|
||||
{
|
||||
viml = '''
|
||||
" Generated by home-manager
|
||||
map <leader> ,
|
||||
''';
|
||||
|
||||
lua = '''
|
||||
-- Generated by home-manager
|
||||
vim.opt.background = "dark"
|
||||
''';
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Generated configurations with as key their language (set via type).
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
config = mkIf cfg.enable (
|
||||
let
|
||||
allPlugins =
|
||||
cfg.plugins
|
||||
++ lib.optional cfg.coc.enable {
|
||||
type = "viml";
|
||||
plugin = cfg.coc.package;
|
||||
config = cfg.coc.pluginConfig;
|
||||
optional = false;
|
||||
};
|
||||
|
||||
defaultPlugin = {
|
||||
type = "viml";
|
||||
plugin = null;
|
||||
@@ -412,78 +406,100 @@ in
|
||||
|
||||
suppressNotVimlConfig = p: if p.type != "viml" then p // { config = null; } else p;
|
||||
|
||||
neovimConfig = pkgs.neovimUtils.makeNeovimConfig {
|
||||
# Lua & Python Package Resolution
|
||||
luaPackages = cfg.finalPackage.unwrapped.lua.pkgs;
|
||||
resolvedExtraLuaPackages = cfg.extraLuaPackages luaPackages;
|
||||
|
||||
# Wrapper Arguments Construction
|
||||
extraMakeWrapperArgs = optionals (cfg.extraPackages != [ ]) [
|
||||
"--suffix"
|
||||
"PATH"
|
||||
":"
|
||||
(lib.makeBinPath cfg.extraPackages)
|
||||
];
|
||||
|
||||
extraMakeWrapperLuaCArgs = optionals (resolvedExtraLuaPackages != [ ]) [
|
||||
"--suffix"
|
||||
"LUA_CPATH"
|
||||
";"
|
||||
(concatMapStringsSep ";" luaPackages.getLuaCPath resolvedExtraLuaPackages)
|
||||
];
|
||||
|
||||
extraMakeWrapperLuaArgs = optionals (resolvedExtraLuaPackages != [ ]) [
|
||||
"--suffix"
|
||||
"LUA_PATH"
|
||||
";"
|
||||
(concatMapStringsSep ";" luaPackages.getLuaPath resolvedExtraLuaPackages)
|
||||
];
|
||||
|
||||
wrappedNeovim' = pkgs.wrapNeovimUnstable cfg.package {
|
||||
withNodeJs = cfg.withNodeJs || cfg.coc.enable;
|
||||
plugins = map suppressNotVimlConfig pluginsNormalized;
|
||||
|
||||
inherit (cfg)
|
||||
extraPython3Packages
|
||||
withPython3
|
||||
withRuby
|
||||
withPerl
|
||||
viAlias
|
||||
vimAlias
|
||||
extraName
|
||||
autowrapRuntimeDeps
|
||||
waylandSupport
|
||||
;
|
||||
withNodeJs = cfg.withNodeJs || cfg.coc.enable;
|
||||
plugins = map suppressNotVimlConfig pluginsNormalized;
|
||||
customRC = cfg.extraConfig;
|
||||
neovimRcContent = cfg.extraConfig;
|
||||
wrapperArgs =
|
||||
cfg.extraWrapperArgs ++ extraMakeWrapperArgs ++ extraMakeWrapperLuaCArgs ++ extraMakeWrapperLuaArgs;
|
||||
wrapRc = false;
|
||||
};
|
||||
in
|
||||
{
|
||||
programs.neovim = {
|
||||
generatedConfigViml = cfg.extraConfig;
|
||||
|
||||
generatedConfigs =
|
||||
let
|
||||
grouped = lib.groupBy (x: x.type) pluginsNormalized;
|
||||
configsOnly = lib.foldl (acc: p: if p.config != null then acc ++ [ p.config ] else acc) [ ];
|
||||
in
|
||||
lib.mapAttrs (_name: vals: lib.concatStringsSep "\n" (configsOnly vals)) grouped;
|
||||
|
||||
finalPackage = wrappedNeovim';
|
||||
};
|
||||
|
||||
wrappedNeovim' = pkgs.wrapNeovimUnstable cfg.package (
|
||||
neovimConfig
|
||||
// {
|
||||
wrapperArgs =
|
||||
(lib.escapeShellArgs (neovimConfig.wrapperArgs ++ cfg.extraWrapperArgs))
|
||||
+ " "
|
||||
+ extraMakeWrapperArgs
|
||||
+ " "
|
||||
+ extraMakeWrapperLuaCArgs
|
||||
+ " "
|
||||
+ extraMakeWrapperLuaArgs;
|
||||
wrapRc = false;
|
||||
}
|
||||
home = {
|
||||
packages = [ cfg.finalPackage ];
|
||||
|
||||
sessionVariables = mkIf cfg.defaultEditor {
|
||||
EDITOR = "nvim";
|
||||
VISUAL = "nvim";
|
||||
};
|
||||
|
||||
shellAliases = mkIf cfg.vimdiffAlias { vimdiff = "nvim -d"; };
|
||||
};
|
||||
|
||||
programs.neovim.extraLuaConfig = lib.mkMerge [
|
||||
(lib.mkIf (wrappedNeovim'.initRc != "") (
|
||||
lib.mkBefore "vim.cmd [[source ${pkgs.writeText "nvim-init-home-manager.vim" wrappedNeovim'.initRc}]]"
|
||||
))
|
||||
(lib.mkIf (lib.hasAttr "lua" cfg.generatedConfigs) (lib.mkAfter cfg.generatedConfigs.lua))
|
||||
];
|
||||
|
||||
xdg.configFile = lib.mkMerge (
|
||||
# writes runtime
|
||||
(map (x: x.runtime) pluginsNormalized)
|
||||
++ [
|
||||
{
|
||||
"nvim/init.lua" = mkIf (cfg.extraLuaConfig != "") {
|
||||
text = cfg.extraLuaConfig;
|
||||
};
|
||||
|
||||
"nvim/coc-settings.json" = mkIf cfg.coc.enable {
|
||||
source = jsonFormat.generate "coc-settings.json" cfg.coc.settings;
|
||||
};
|
||||
}
|
||||
]
|
||||
);
|
||||
in
|
||||
mkIf cfg.enable {
|
||||
|
||||
programs.neovim.generatedConfigViml = neovimConfig.neovimRcContent;
|
||||
|
||||
programs.neovim.generatedConfigs =
|
||||
let
|
||||
grouped = lib.lists.groupBy (x: x.type) pluginsNormalized;
|
||||
configsOnly = lib.foldl (acc: p: if p.config != null then acc ++ [ p.config ] else acc) [ ];
|
||||
in
|
||||
lib.mapAttrs (name: vals: lib.concatStringsSep "\n" (configsOnly vals)) grouped;
|
||||
|
||||
home.packages = [ cfg.finalPackage ];
|
||||
|
||||
home.sessionVariables = mkIf cfg.defaultEditor { EDITOR = "nvim"; };
|
||||
|
||||
home.shellAliases = mkIf cfg.vimdiffAlias { vimdiff = "nvim -d"; };
|
||||
|
||||
xdg.configFile =
|
||||
let
|
||||
hasLuaConfig = lib.hasAttr "lua" config.programs.neovim.generatedConfigs;
|
||||
in
|
||||
lib.mkMerge (
|
||||
# writes runtime
|
||||
(map (x: x.runtime) pluginsNormalized)
|
||||
++ [
|
||||
{
|
||||
"nvim/init.lua" =
|
||||
let
|
||||
luaRcContent =
|
||||
lib.optionalString (
|
||||
wrappedNeovim'.initRc != ""
|
||||
) "vim.cmd [[source ${pkgs.writeText "nvim-init-home-manager.vim" wrappedNeovim'.initRc}]]\n"
|
||||
+ config.programs.neovim.extraLuaConfig
|
||||
+ lib.optionalString hasLuaConfig config.programs.neovim.generatedConfigs.lua;
|
||||
in
|
||||
mkIf (luaRcContent != "") { text = luaRcContent; };
|
||||
|
||||
"nvim/coc-settings.json" = mkIf cfg.coc.enable {
|
||||
source = jsonFormat.generate "coc-settings.json" cfg.coc.settings;
|
||||
};
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
programs.neovim.finalPackage = wrappedNeovim';
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ in
|
||||
lib.optional (cfg.clean.enable && config.nix.gc.automatic)
|
||||
"programs.nh.clean.enable and nix.gc.automatic (Home-Manager) are both enabled. Please use one or the other to avoid conflict.";
|
||||
|
||||
assertions = lib.optionals pkgs.stdenv.isDarwin [
|
||||
assertions = [
|
||||
(lib.hm.darwin.assertInterval "programs.nh.clean.dates" cfg.clean.dates pkgs)
|
||||
];
|
||||
|
||||
@@ -131,30 +131,25 @@ in
|
||||
];
|
||||
};
|
||||
|
||||
systemd.user = lib.mkIf (cfg.clean.enable && pkgs.stdenv.isLinux) {
|
||||
systemd.user = lib.mkIf cfg.clean.enable {
|
||||
services.nh-clean = {
|
||||
Unit.Description = "Nh clean (user)";
|
||||
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${lib.getExe cfg.package} clean user ${cfg.clean.extraArgs}";
|
||||
};
|
||||
};
|
||||
|
||||
timers.nh-clean = {
|
||||
Unit.Description = "Run nh clean";
|
||||
|
||||
Timer = {
|
||||
OnCalendar = cfg.clean.dates;
|
||||
Persistent = true;
|
||||
};
|
||||
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
launchd.agents.nh-clean = lib.mkIf (cfg.clean.enable && pkgs.stdenv.isDarwin) {
|
||||
launchd.agents.nh-clean = lib.mkIf cfg.clean.enable {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
@@ -163,9 +158,7 @@ in
|
||||
"user"
|
||||
]
|
||||
++ lib.optional (cfg.clean.extraArgs != "") cfg.clean.extraArgs;
|
||||
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval cfg.clean.dates;
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -66,10 +66,7 @@ in
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = pkgs.stdenv.hostPlatform.isLinux;
|
||||
message = "niriswitcher is only available on Linux.";
|
||||
}
|
||||
(lib.hm.assertions.assertPlatform "programs.niriswitcher" pkgs lib.platforms.linux)
|
||||
];
|
||||
|
||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
|
||||
74
modules/programs/npm.nix
Normal file
74
modules/programs/npm.nix
Normal file
@@ -0,0 +1,74 @@
|
||||
# https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/programs/npm.nix
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.programs.npm;
|
||||
|
||||
xdgConfigHome = lib.removePrefix config.home.homeDirectory config.xdg.configHome;
|
||||
configFile = if config.home.preferXdgDirectories then "${xdgConfigHome}/npm/npmrc" else ".npmrc";
|
||||
|
||||
iniFormat = pkgs.formats.ini {
|
||||
listsAsDuplicateKeys = true;
|
||||
};
|
||||
|
||||
toNpmrc =
|
||||
let
|
||||
mkLine = lib.generators.mkKeyValueDefault { } "=";
|
||||
mkLines = k: v: if lib.isList v then map (x: mkLine "${k}[]" x) v else [ (mkLine k v) ];
|
||||
in
|
||||
attrs: lib.concatLines (lib.concatLists (lib.mapAttrsToList mkLines attrs));
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ mirkolenz ];
|
||||
|
||||
options = {
|
||||
programs.npm = {
|
||||
enable = lib.mkEnableOption "{command}`npm` user config";
|
||||
|
||||
package = lib.mkPackageOption pkgs [ "nodejs" ] {
|
||||
example = "nodejs_24";
|
||||
nullable = true;
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.attrsOf iniFormat.lib.types.atom;
|
||||
description = ''
|
||||
The user-specific npm configuration.
|
||||
See <https://docs.npmjs.com/cli/using-npm/config> and
|
||||
<https://docs.npmjs.com/cli/configuring-npm/npmrc>
|
||||
for more information.
|
||||
'';
|
||||
default = {
|
||||
prefix = "\${HOME}/.npm";
|
||||
};
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
color = true;
|
||||
include = [
|
||||
"dev"
|
||||
"prod"
|
||||
];
|
||||
init-license = "MIT";
|
||||
prefix = "''${HOME}/.npm";
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
home = {
|
||||
packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
file.${configFile} = lib.mkIf (cfg.settings != { }) {
|
||||
text = toNpmrc cfg.settings;
|
||||
};
|
||||
sessionVariables = lib.mkIf (cfg.settings != { }) {
|
||||
NPM_CONFIG_USERCONFIG = "${config.home.homeDirectory}/${configFile}";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -133,7 +133,7 @@ in
|
||||
The attribute name becomes the command filename, and the value is either:
|
||||
- Inline content as a string
|
||||
- A path to a file containing the command content
|
||||
Commands are stored in {file}`$XDG_CONFIG_HOME/.config/opencode/command/` directory.
|
||||
Commands are stored in {file}`$XDG_CONFIG_HOME/opencode/command/` directory.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
@@ -162,7 +162,7 @@ in
|
||||
The attribute name becomes the agent filename, and the value is either:
|
||||
- Inline content as a string
|
||||
- A path to a file containing the agent content
|
||||
Agents are stored in {file}`$XDG_CONFIG_HOME/.config/opencode/agent/` directory.
|
||||
Agents are stored in {file}`$XDG_CONFIG_HOME/opencode/agent/` directory.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
@@ -183,6 +183,49 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
skills = lib.mkOption {
|
||||
type = lib.types.either (lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path)) lib.types.path;
|
||||
default = { };
|
||||
description = ''
|
||||
Custom agent skills for opencode.
|
||||
|
||||
This option can either be:
|
||||
- An attribute set defining skills
|
||||
- A path to a directory containing multiple skill folders
|
||||
|
||||
If an attribute set is used, the attribute name becomes the skill directory name,
|
||||
and the value is either:
|
||||
- Inline content as a string (creates `opencode/skill/<name>/SKILL.md`)
|
||||
- A path to a file (creates `opencode/skill/<name>/SKILL.md`)
|
||||
- A path to a directory (creates `opencode/skill/<name>/` with all files)
|
||||
|
||||
If a path is used, it is expected to contain one folder per skill name, each
|
||||
containing a {file}`SKILL.md`. The directory is symlinked to
|
||||
{file}`$XDG_CONFIG_HOME/opencode/skill/`.
|
||||
|
||||
See <https://opencode.ai/docs/skills/> for the documentation.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
git-release = '''
|
||||
---
|
||||
name: git-release
|
||||
description: Create consistent releases and changelogs
|
||||
---
|
||||
|
||||
## What I do
|
||||
|
||||
- Draft release notes from merged PRs
|
||||
- Propose a version bump
|
||||
- Provide a copy-pasteable `gh release create` command
|
||||
''';
|
||||
|
||||
# A skill can also be a directory containing SKILL.md and other files.
|
||||
data-analysis = ./skills/data-analysis;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
themes = mkOption {
|
||||
type = lib.types.attrsOf (lib.types.either jsonFormat.type lib.types.path);
|
||||
default = { };
|
||||
@@ -199,6 +242,13 @@ in
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = !lib.isPath cfg.skills || lib.pathIsDirectory cfg.skills;
|
||||
message = "`programs.opencode.skills` must be a directory when set to a path";
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = mkIf (cfg.package != null) [ cfg.package ];
|
||||
|
||||
xdg.configFile = {
|
||||
@@ -227,6 +277,11 @@ in
|
||||
text = cfg.rules;
|
||||
})
|
||||
);
|
||||
|
||||
"opencode/skill" = mkIf (lib.isPath cfg.skills) {
|
||||
source = cfg.skills;
|
||||
recursive = true;
|
||||
};
|
||||
}
|
||||
// lib.mapAttrs' (
|
||||
name: content:
|
||||
@@ -240,6 +295,18 @@ in
|
||||
if lib.isPath content then { source = content; } else { text = content; }
|
||||
)
|
||||
) cfg.agents
|
||||
// lib.mapAttrs' (
|
||||
name: content:
|
||||
if lib.isPath content && lib.pathIsDirectory content then
|
||||
lib.nameValuePair "opencode/skill/${name}" {
|
||||
source = content;
|
||||
recursive = true;
|
||||
}
|
||||
else
|
||||
lib.nameValuePair "opencode/skill/${name}/SKILL.md" (
|
||||
if lib.isPath content then { source = content; } else { text = content; }
|
||||
)
|
||||
) (if builtins.isAttrs cfg.skills then cfg.skills else { })
|
||||
// lib.mapAttrs' (
|
||||
name: content:
|
||||
lib.nameValuePair "opencode/themes/${name}.json" (
|
||||
|
||||
42
modules/programs/parallel.nix
Normal file
42
modules/programs/parallel.nix
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mkIf
|
||||
mkEnableOption
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
|
||||
cfg = config.programs.parallel;
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.xavwe ];
|
||||
|
||||
options.programs.parallel = {
|
||||
enable = mkEnableOption "GNU Parallel";
|
||||
|
||||
package = lib.mkPackageOption pkgs "parallel-full" { nullable = true; };
|
||||
|
||||
will-cite = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Accept GNU Parallels citation policy: <https://www.gnu.org/software/parallel/parallel_design.html#citation-notice>
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home = {
|
||||
packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
file.".parallel/will-cite" = mkIf cfg.will-cite {
|
||||
text = "generated by home manager (programs.parallel.will-cite)";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
localStorage = calendar: name: acc: {
|
||||
name = "storage";
|
||||
params = [ "${name}-local" ];
|
||||
params = [ "${if calendar then "calendar" else "contacts"}-${name}-local" ];
|
||||
children =
|
||||
(attrsToDirectives {
|
||||
inherit (acc.local) path;
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
remoteStorage = calendar: name: acc: {
|
||||
name = "storage";
|
||||
params = [ "${name}-remote" ];
|
||||
params = [ "${if calendar then "calendar" else "contacts"}-${name}-remote" ];
|
||||
children =
|
||||
(attrsToDirectives {
|
||||
inherit (acc.remote) url;
|
||||
@@ -91,8 +91,8 @@
|
||||
params = lib.singleton "${if calendar then "calendar" else "contacts"}-${name}";
|
||||
children =
|
||||
(attrsToDirectives {
|
||||
storage_a = "${name}-local";
|
||||
storage_b = "${name}-remote";
|
||||
storage_a = "${if calendar then "calendar" else "contacts"}-${name}-local";
|
||||
storage_b = "${if calendar then "calendar" else "contacts"}-${name}-remote";
|
||||
})
|
||||
++ acc.pimsync.extraPairDirectives;
|
||||
};
|
||||
|
||||
@@ -153,7 +153,7 @@ in
|
||||
default = { };
|
||||
apply = lib.mergeAttrs {
|
||||
vfs-cache-mode = "full";
|
||||
cache-dir = "%C";
|
||||
cache-dir = "%C/rclone";
|
||||
};
|
||||
description = ''
|
||||
An attribute set of option values passed to `rclone mount`. To set
|
||||
|
||||
55
modules/programs/screen.nix
Normal file
55
modules/programs/screen.nix
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
types
|
||||
mkIf
|
||||
mkEnableOption
|
||||
mkPackageOption
|
||||
mkOption
|
||||
;
|
||||
|
||||
cfg = config.programs.screen;
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.hm.maintainers; [ aguirre-matteo ];
|
||||
options.programs.screen = {
|
||||
enable = mkEnableOption "screen";
|
||||
package = mkPackageOption pkgs "screen" { nullable = true; };
|
||||
screenrc = mkOption {
|
||||
type = with types; nullOr (either path lines);
|
||||
default = null;
|
||||
example = ''
|
||||
screen -t rtorrent rtorrent
|
||||
screen -t irssi irssi
|
||||
screen -t centerim centerim
|
||||
screen -t ncmpc ncmpc -c
|
||||
screen -t bash4
|
||||
screen -t bash5
|
||||
screen -t bash6
|
||||
screen -t bash7
|
||||
screen -t bash8
|
||||
screen -t bash9
|
||||
altscreen on
|
||||
term screen-256color
|
||||
bind ',' prev
|
||||
bind '.' next
|
||||
'';
|
||||
description = ''
|
||||
Config file for GNU Screen. All the details can be found here:
|
||||
<https://www.gnu.org/software/screen/manual/screen.html>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
home.packages = mkIf (cfg.package != null) [ cfg.package ];
|
||||
home.file.".screenrc" = mkIf (cfg.screenrc != null) {
|
||||
source = if lib.isPath cfg.screenrc then cfg.screenrc else pkgs.writeText "screenrc" cfg.screenrc;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -52,7 +52,7 @@ in
|
||||
eval "$(sheldon source)"
|
||||
'';
|
||||
|
||||
programs.zsh.initExtra = mkIf cfg.enableZshIntegration ''
|
||||
programs.zsh.initContent = mkIf cfg.enableZshIntegration ''
|
||||
eval "$(sheldon source)"
|
||||
'';
|
||||
|
||||
|
||||
@@ -30,44 +30,42 @@ let
|
||||
mapAttrsToList (name: value: ''${name}="${lib.escape [ ''"'' "\\" ] (toString value)}"'') envStr
|
||||
);
|
||||
|
||||
bindOptions = {
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
default = "localhost";
|
||||
example = "example.org";
|
||||
description = "The address where to bind the port.";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.nullOr types.port;
|
||||
default = null;
|
||||
example = 8080;
|
||||
description = "Specifies port number to bind on bind address.";
|
||||
};
|
||||
};
|
||||
|
||||
dynamicForwardModule = types.submodule { options = bindOptions; };
|
||||
|
||||
forwardModule = types.submodule {
|
||||
options = {
|
||||
bind = bindOptions;
|
||||
|
||||
host = {
|
||||
mkAddressPortModule =
|
||||
{
|
||||
actionType,
|
||||
nullableAddress ? actionType == "forward",
|
||||
}:
|
||||
types.submodule {
|
||||
options = {
|
||||
address = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
type = if nullableAddress then types.nullOr types.str else types.str;
|
||||
default = if nullableAddress then null else "localhost";
|
||||
example = "example.org";
|
||||
description = "The address where to forward the traffic to.";
|
||||
description = "The address to ${actionType} to.";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.nullOr types.port;
|
||||
default = null;
|
||||
example = 80;
|
||||
description = "Specifies port number to forward the traffic to.";
|
||||
example = 8080;
|
||||
description = "Specifies port number to ${actionType} to.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dynamicForwardModule = mkAddressPortModule { actionType = "bind"; };
|
||||
|
||||
forwardModule = types.submodule {
|
||||
options = {
|
||||
bind = mkOption {
|
||||
type = mkAddressPortModule { actionType = "bind"; };
|
||||
description = "Local port binding options";
|
||||
};
|
||||
host = mkOption {
|
||||
type = mkAddressPortModule { actionType = "forward"; };
|
||||
description = "Host port binding options";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
matchBlockModule = types.submodule {
|
||||
@@ -151,14 +149,7 @@ let
|
||||
identityFile = mkOption {
|
||||
type = with types; either (listOf str) (nullOr str);
|
||||
default = [ ];
|
||||
apply =
|
||||
p:
|
||||
if p == null then
|
||||
[ ]
|
||||
else if lib.isString p then
|
||||
[ p ]
|
||||
else
|
||||
p;
|
||||
apply = p: if p == null then [ ] else lib.toList p;
|
||||
description = ''
|
||||
Specifies files from which the user identity is read.
|
||||
Identities will be tried in the given order.
|
||||
@@ -168,14 +159,7 @@ let
|
||||
identityAgent = mkOption {
|
||||
type = with types; either (listOf str) (nullOr str);
|
||||
default = [ ];
|
||||
apply =
|
||||
p:
|
||||
if p == null then
|
||||
[ ]
|
||||
else if lib.isString p then
|
||||
[ p ]
|
||||
else
|
||||
p;
|
||||
apply = p: if p == null then [ ] else lib.toList p;
|
||||
description = ''
|
||||
Specifies the location of the ssh identity agent.
|
||||
'';
|
||||
@@ -265,14 +249,7 @@ let
|
||||
certificateFile = mkOption {
|
||||
type = with types; either (listOf str) (nullOr str);
|
||||
default = [ ];
|
||||
apply =
|
||||
p:
|
||||
if p == null then
|
||||
[ ]
|
||||
else if lib.isString p then
|
||||
[ p ]
|
||||
else
|
||||
p;
|
||||
apply = p: if p == null then [ ] else lib.toList p;
|
||||
description = ''
|
||||
Specifies files from which the user certificate is read.
|
||||
'';
|
||||
@@ -404,6 +381,18 @@ let
|
||||
example = "10m";
|
||||
description = "Whether control socket should remain open in the background.";
|
||||
};
|
||||
|
||||
kexAlgorithms = mkOption {
|
||||
type = types.nullOr (types.listOf types.str);
|
||||
default = null;
|
||||
example = [
|
||||
"curve25519-sha256@libssh.org"
|
||||
"diffie-hellman-group-exchange-sha256"
|
||||
];
|
||||
description = ''
|
||||
Specifies the available KEX (Key Exchange) algorithms.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
# config.host = mkDefault dagName;
|
||||
@@ -451,7 +440,16 @@ let
|
||||
++ map (f: " LocalForward" + addressPort f.bind + addressPort f.host) cf.localForwards
|
||||
++ map (f: " RemoteForward" + addressPort f.bind + addressPort f.host) cf.remoteForwards
|
||||
++ map (f: " DynamicForward" + addressPort f) cf.dynamicForwards
|
||||
++ mapAttrsToList (n: v: " ${n} ${v}") cf.extraOptions
|
||||
++ optional (
|
||||
cf.kexAlgorithms != null
|
||||
) " KexAlgorithms ${builtins.concatStringsSep "," cf.kexAlgorithms}"
|
||||
++ [
|
||||
(lib.generators.toKeyValue {
|
||||
mkKeyValue = lib.generators.mkKeyValueDefault { } " ";
|
||||
listsAsDuplicateKeys = true;
|
||||
indent = " ";
|
||||
} cf.extraOptions)
|
||||
]
|
||||
);
|
||||
|
||||
in
|
||||
|
||||
@@ -106,13 +106,13 @@ in
|
||||
];
|
||||
|
||||
programs.bash.initExtra = lib.mkIf cfg.enableBashIntegration ''
|
||||
eval "$(${lib.getExe cfg.package} init bash)"
|
||||
source ${cfg.package}/share/television/completion.bash
|
||||
'';
|
||||
programs.zsh.initContent = lib.mkIf cfg.enableZshIntegration ''
|
||||
eval "$(${lib.getExe cfg.package} init zsh)"
|
||||
source ${cfg.package}/share/television/completion.zsh
|
||||
'';
|
||||
programs.fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration ''
|
||||
${lib.getExe cfg.package} init fish | source
|
||||
source ${cfg.package}/share/television/completion.fish
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ let
|
||||
attrValues
|
||||
concatStringsSep
|
||||
filter
|
||||
flatten
|
||||
length
|
||||
literalExpression
|
||||
mapAttrsToList
|
||||
@@ -918,7 +919,14 @@ in
|
||||
calendarAccounts = getAccountsForProfile name enabledCalendarAccountsWithId;
|
||||
contactAccounts = getAccountsForProfile name enabledContactAccountsWithId;
|
||||
|
||||
smtp = filter (a: a.smtp != null) emailAccounts;
|
||||
accountsSmtp = filter (a: a.smtp != null) emailAccounts;
|
||||
aliasesSmtp =
|
||||
let
|
||||
getAliasesWithSmtp = a: filter (al: builtins.isAttrs al && al.smtp != null) a.aliases;
|
||||
getAliasesWithId = a: map (al: al // { id = getId a al; }) (getAliasesWithSmtp a);
|
||||
in
|
||||
flatten (map getAliasesWithId emailAccounts);
|
||||
smtp = accountsSmtp ++ aliasesSmtp;
|
||||
|
||||
feedAccounts = addId (attrValues profile.feedAccounts);
|
||||
|
||||
|
||||
51
modules/programs/ty.nix
Normal file
51
modules/programs/ty.nix
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkPackageOption
|
||||
mkOption
|
||||
literalExpression
|
||||
;
|
||||
|
||||
tomlFormat = pkgs.formats.toml { };
|
||||
cfg = config.programs.ty;
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ mirkolenz ];
|
||||
|
||||
options.programs.ty = {
|
||||
enable = mkEnableOption "ty";
|
||||
|
||||
package = mkPackageOption pkgs "ty" { nullable = true; };
|
||||
|
||||
settings = mkOption {
|
||||
type = tomlFormat.type;
|
||||
default = { };
|
||||
example = literalExpression ''
|
||||
{
|
||||
rules.index-out-of-bounds = "ignore";
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Configuration written to
|
||||
{file}`$XDG_CONFIG_HOME/ty/ty.toml`.
|
||||
See <https://docs.astral.sh/ty/configuration/>
|
||||
and <https://docs.astral.sh/ty/reference/configuration/>
|
||||
for more information.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
|
||||
xdg.configFile."ty/ty.toml" = lib.mkIf (cfg.settings != { }) {
|
||||
source = tomlFormat.generate "ty-config.toml" cfg.settings;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -12,6 +12,7 @@ let
|
||||
|
||||
packageVersion = if cfg.package != null then lib.getVersion cfg.package else null;
|
||||
themeIsToml = lib.versionAtLeast packageVersion "0.15.0";
|
||||
versionPost0_17 = lib.versionAtLeast packageVersion "0.17.0";
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.leiserfg ];
|
||||
@@ -43,7 +44,12 @@ in
|
||||
useLayerShell = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "If vicinae should use the layer shell";
|
||||
description = ''
|
||||
Whether vicinae should use the layer shell.
|
||||
If you are using version 0.17 or newer, you should use
|
||||
{option}.programs.vicinae.settings.launcher_window.layer_shell.enabled = false
|
||||
instead.
|
||||
'';
|
||||
};
|
||||
|
||||
extensions = lib.mkOption {
|
||||
@@ -127,27 +133,22 @@ in
|
||||
settings = lib.mkOption {
|
||||
inherit (jsonFormat) type;
|
||||
default = { };
|
||||
description = "Settings written as JSON to `~/.config/vicinae/vicinae.json.";
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
faviconService = "twenty";
|
||||
font = {
|
||||
size = 10;
|
||||
};
|
||||
popToRootOnClose = false;
|
||||
rootSearch = {
|
||||
searchFiles = false;
|
||||
};
|
||||
favicon_service = "twenty";
|
||||
font.normal.size = 10;
|
||||
pop_to_root_on_close=false;
|
||||
search_files_in_root= false;
|
||||
theme = {
|
||||
name = "vicinae-dark";
|
||||
};
|
||||
window = {
|
||||
csd = true;
|
||||
opacity = 0.95;
|
||||
rounding = 10;
|
||||
dark.name = "vicinae-dark";
|
||||
light.name = "vicinae-light";
|
||||
};
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Settings written as JSON to {file}`~/.config/vicinae/settings.json`.
|
||||
See {command}`vicinae config default`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
@@ -158,6 +159,10 @@ in
|
||||
assertion = cfg.systemd.enable -> cfg.package != null;
|
||||
message = "{option}programs.vicinae.systemd.enable requires non null {option}programs.vicinae.package";
|
||||
}
|
||||
{
|
||||
assertion = !cfg.useLayerShell -> !versionPost0_17;
|
||||
message = ''After version 0.17, if you want to explicitly disable the use of layer shell, you need to set {option}.programs.vicinae.settings.launcher_window.layer_shell.enabled = false.'';
|
||||
}
|
||||
];
|
||||
lib.vicinae.mkExtension = (
|
||||
{
|
||||
@@ -223,10 +228,11 @@ in
|
||||
source = themeFormat.generate "vicinae-${name}-theme" theme;
|
||||
}
|
||||
) cfg.themes;
|
||||
settingsPath = if versionPost0_17 then "vicinae/settings.json" else "vicinae/vicinae.json";
|
||||
in
|
||||
{
|
||||
configFile = {
|
||||
"vicinae/vicinae.json" = lib.mkIf (cfg.settings != { }) {
|
||||
"${settingsPath}" = lib.mkIf (cfg.settings != { }) {
|
||||
source = jsonFormat.generate "vicinae-settings" cfg.settings;
|
||||
};
|
||||
}
|
||||
@@ -250,14 +256,16 @@ in
|
||||
PartOf = [ cfg.systemd.target ];
|
||||
};
|
||||
Service = {
|
||||
EnvironmentFile = pkgs.writeText "vicinae-env" ''
|
||||
USE_LAYER_SHELL=${if cfg.useLayerShell then builtins.toString 1 else builtins.toString 0}
|
||||
'';
|
||||
Type = "simple";
|
||||
ExecStart = "${lib.getExe' cfg.package "vicinae"} server";
|
||||
Restart = "always";
|
||||
RestartSec = 5;
|
||||
KillMode = "process";
|
||||
EnvironmentFile = lib.mkIf (!versionPost0_17) (
|
||||
pkgs.writeText "vicinae-env" ''
|
||||
USE_LAYER_SHELL=${if cfg.useLayerShell then builtins.toString 1 else builtins.toString 0}
|
||||
''
|
||||
);
|
||||
};
|
||||
Install = lib.mkIf cfg.systemd.autoStart {
|
||||
WantedBy = [ cfg.systemd.target ];
|
||||
|
||||
@@ -162,7 +162,8 @@ in
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to configure {command}`vim` as the default
|
||||
editor using the {env}`EDITOR` environment variable.
|
||||
editor using the {env}`EDITOR` and {env}`VISUAL`
|
||||
environment variables.
|
||||
'';
|
||||
};
|
||||
};
|
||||
@@ -213,7 +214,10 @@ in
|
||||
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
home.sessionVariables = lib.mkIf cfg.defaultEditor { EDITOR = "vim"; };
|
||||
home.sessionVariables = lib.mkIf cfg.defaultEditor {
|
||||
EDITOR = "vim";
|
||||
VISUAL = "vim";
|
||||
};
|
||||
|
||||
programs.vim = {
|
||||
package = vim;
|
||||
|
||||
@@ -23,7 +23,10 @@ let
|
||||
yamlFormat = pkgs.formats.yaml { };
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.hm.maintainers; [ aguirre-matteo ];
|
||||
meta.maintainers = [
|
||||
lib.hm.maintainers.aguirre-matteo
|
||||
lib.maintainers.arunoruto
|
||||
];
|
||||
|
||||
options.programs.vivid = {
|
||||
enable = mkEnableOption "vivid";
|
||||
@@ -34,7 +37,14 @@ in
|
||||
enableFishIntegration = mkFishIntegrationOption { inherit config; };
|
||||
|
||||
colorMode = mkOption {
|
||||
type = with types; nullOr str;
|
||||
type =
|
||||
with types;
|
||||
nullOr (
|
||||
either str (enum [
|
||||
"8-bit"
|
||||
"24-bit"
|
||||
])
|
||||
);
|
||||
default = null;
|
||||
example = "8-bit";
|
||||
description = ''
|
||||
@@ -135,7 +145,7 @@ in
|
||||
// (lib.mapAttrs' (
|
||||
name: value:
|
||||
lib.nameValuePair "vivid/themes/${name}.yml" {
|
||||
source = if lib.isAttrs value then yamlFormat.generate "${name}.yml" value else value;
|
||||
source = if lib.isAttrs value then pkgs.writeText "${name}.json" (builtins.toJSON value) else value;
|
||||
}
|
||||
) cfg.themes);
|
||||
|
||||
|
||||
@@ -9,12 +9,27 @@ let
|
||||
|
||||
cfg = config.programs.yt-dlp;
|
||||
|
||||
renderSettings = lib.mapAttrsToList (
|
||||
configAtom =
|
||||
with types;
|
||||
oneOf [
|
||||
bool
|
||||
int
|
||||
str
|
||||
];
|
||||
|
||||
renderSingleOption =
|
||||
name: value:
|
||||
if lib.isBool value then
|
||||
if value then "--${name}" else "--no-${name}"
|
||||
else
|
||||
"--${name} ${toString value}"
|
||||
"--${name} ${toString value}";
|
||||
|
||||
renderSettings = lib.mapAttrsToList (
|
||||
name: value:
|
||||
if lib.isList value then
|
||||
lib.concatStringsSep "\n" (map (renderSingleOption name) value)
|
||||
else
|
||||
renderSingleOption name value
|
||||
);
|
||||
|
||||
in
|
||||
@@ -27,13 +42,7 @@ in
|
||||
package = lib.mkPackageOption pkgs "yt-dlp" { };
|
||||
|
||||
settings = mkOption {
|
||||
type =
|
||||
with types;
|
||||
attrsOf (oneOf [
|
||||
bool
|
||||
int
|
||||
str
|
||||
]);
|
||||
type = with types; attrsOf (either configAtom (listOf configAtom));
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
@@ -42,6 +51,10 @@ in
|
||||
sub-langs = "all";
|
||||
downloader = "aria2c";
|
||||
downloader-args = "aria2c:'-c -x8 -s8 -k1M'";
|
||||
color = [
|
||||
"stdout:no_color"
|
||||
"stderr:always"
|
||||
];
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
options,
|
||||
...
|
||||
}:
|
||||
let
|
||||
@@ -100,9 +101,18 @@ in
|
||||
};
|
||||
|
||||
dotDir = mkOption {
|
||||
default = homeDir;
|
||||
defaultText = "`config.home.homeDirectory`";
|
||||
example = "`\${config.xdg.configHome}/zsh`";
|
||||
default =
|
||||
if config.xdg.enable && lib.versionAtLeast config.home.stateVersion "26.05" then
|
||||
"${config.xdg.configHome}/zsh"
|
||||
else
|
||||
homeDir;
|
||||
defaultText = lib.literalExpression ''
|
||||
if config.xdg.enable && lib.versionAtLeast config.home.stateVersion "26.05" then
|
||||
"''${config.xdg.configHome}/zsh"
|
||||
else
|
||||
config.home.homeDirectory
|
||||
'';
|
||||
example = literalExpression ''"''${config.xdg.configHome}/zsh"'';
|
||||
description = ''
|
||||
Directory where the zsh configuration and more should be located,
|
||||
relative to the users home directory. The default is the home
|
||||
@@ -391,7 +401,24 @@ in
|
||||
- config.xdg.dataHome (XDG data directory)
|
||||
- config.xdg.cacheHome (XDG cache directory)
|
||||
''
|
||||
];
|
||||
]
|
||||
++
|
||||
lib.optionals
|
||||
(
|
||||
config.xdg.enable
|
||||
&& !lib.versionAtLeast config.home.stateVersion "26.05"
|
||||
&& options.programs.zsh.dotDir.highestPrio >= 1500
|
||||
)
|
||||
[
|
||||
''
|
||||
The default value of `programs.zsh.dotDir` will change in future versions.
|
||||
You are currently using the legacy default (home directory) because `home.stateVersion` is less than "26.05".
|
||||
To silence this warning and lock in the current behavior, set:
|
||||
programs.zsh.dotDir = config.home.homeDirectory;
|
||||
To adopt the new behavior (XDG config directory), set:
|
||||
programs.zsh.dotDir = "''${config.xdg.configHome}/zsh";
|
||||
''
|
||||
];
|
||||
}
|
||||
|
||||
(mkIf (cfg.envExtra != "") {
|
||||
@@ -412,7 +439,7 @@ in
|
||||
|
||||
(mkIf (dotDirAbs != homeDir) {
|
||||
home.file."${dotDirRel}/.zshenv".text = ''
|
||||
export ZDOTDIR=${dotDirAbs}
|
||||
${config.lib.zsh.export "ZDOTDIR" dotDirAbs}
|
||||
'';
|
||||
|
||||
# When dotDir is set, only use ~/.zshenv to source ZDOTDIR/.zshenv,
|
||||
@@ -420,7 +447,7 @@ in
|
||||
# already set correctly (by e.g. spawning a zsh inside a zsh), all env
|
||||
# vars still get exported
|
||||
home.file.".zshenv".text = ''
|
||||
source ${dotDirAbs}/.zshenv
|
||||
source ${lib.escapeShellArg "${dotDirAbs}/.zshenv"}
|
||||
'';
|
||||
})
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
cfg = config.programs.zsh;
|
||||
|
||||
stripSlash = lib.removeSuffix "/";
|
||||
in
|
||||
rec {
|
||||
homeDir = config.home.homeDirectory;
|
||||
# Raw home directory, no trailing slash.
|
||||
homeDir = stripSlash config.home.homeDirectory;
|
||||
|
||||
/*
|
||||
Escape a path string for shell usage and remove trailing slashes.
|
||||
@@ -18,10 +21,11 @@ rec {
|
||||
cleanPathStr "/path/to/dir/" => "'/path/to/dir'"
|
||||
cleanPathStr "path with spaces" => "'path with spaces'"
|
||||
*/
|
||||
cleanPathStr = pathStr: lib.escapeShellArg (lib.removeSuffix "/" pathStr);
|
||||
cleanPathStr = pathStr: lib.escapeShellArg (stripSlash pathStr);
|
||||
|
||||
/*
|
||||
Convert an absolute path to a relative path by stripping the home directory prefix.
|
||||
Returns the raw path (unescaped) for use in home.file keys.
|
||||
|
||||
This function converts absolute paths within the home directory to relative paths
|
||||
by removing the home directory prefix. Paths already relative are returned as-is.
|
||||
@@ -30,19 +34,22 @@ rec {
|
||||
Type: String -> String
|
||||
|
||||
Example:
|
||||
mkRelPathStr "/home/user/config" => "'config'"
|
||||
mkRelPathStr "config" => "'config'"
|
||||
mkRelPathStr "/home/user/config" => "config"
|
||||
mkRelPathStr "config" => "config"
|
||||
mkRelPathStr "/home/user" => "."
|
||||
mkRelPathStr "/etc/config" => <error>
|
||||
*/
|
||||
mkRelPathStr =
|
||||
pathStr:
|
||||
# is already a relative path
|
||||
if (!lib.hasPrefix "/" pathStr) then
|
||||
cleanPathStr pathStr
|
||||
# is an absolute path within home dir
|
||||
else if (lib.hasPrefix homeDir pathStr) then
|
||||
cleanPathStr (lib.removePrefix "${homeDir}/" pathStr)
|
||||
# is an absolute path not in home dir
|
||||
let
|
||||
normPath = stripSlash pathStr;
|
||||
in
|
||||
if (!lib.hasPrefix "/" normPath) then
|
||||
normPath
|
||||
else if normPath == homeDir then
|
||||
"."
|
||||
else if (lib.hasPrefix "${homeDir}/" normPath) then
|
||||
lib.removePrefix "${homeDir}/" normPath
|
||||
else
|
||||
throw ''
|
||||
Attempted to convert an absolute path not within home directory to a
|
||||
@@ -54,47 +61,47 @@ rec {
|
||||
'';
|
||||
|
||||
/*
|
||||
Convert a relative path to an absolute path by prepending the home directory.
|
||||
Convert a relative path to an absolute path.
|
||||
Returns RAW path (unescaped).
|
||||
|
||||
This function ensures paths are absolute by prepending the home directory
|
||||
to relative paths. Already absolute paths are returned unchanged (after cleaning).
|
||||
This function does NOT support shell variables.
|
||||
|
||||
Type: String -> String
|
||||
|
||||
Example:
|
||||
mkAbsPathStr "config" => "'/home/user/config'"
|
||||
mkAbsPathStr "/absolute/path" => "'/absolute/path'"
|
||||
mkAbsPathStr "config" => "/home/user/config"
|
||||
mkAbsPathStr "/absolute/path" => "/absolute/path"
|
||||
*/
|
||||
mkAbsPathStr =
|
||||
pathStr: cleanPathStr ((lib.optionalString (!lib.hasPrefix "/" pathStr) "${homeDir}/") + pathStr);
|
||||
pathStr:
|
||||
let
|
||||
normPath = stripSlash pathStr;
|
||||
in
|
||||
if lib.hasPrefix "/" normPath then normPath else "${homeDir}/${normPath}";
|
||||
|
||||
/*
|
||||
Convert a path to absolute form while preserving shell variables for runtime expansion.
|
||||
Convert a path to absolute form while preserving shell variables.
|
||||
Returns RAW path (unescaped) unless vars are present (then preserves vars).
|
||||
|
||||
This function handles both literal paths and shell variable expressions.
|
||||
Shell variables (containing '$') are preserved unescaped to allow runtime expansion.
|
||||
Literal paths are made absolute and properly escaped for shell usage.
|
||||
Literal paths are made absolute.
|
||||
|
||||
Type: String -> String
|
||||
|
||||
Example:
|
||||
mkShellVarPathStr "config" => "'/home/user/config'"
|
||||
mkShellVarPathStr "config" => "/home/user/config"
|
||||
mkShellVarPathStr "$HOME/config" => "$HOME/config"
|
||||
mkShellVarPathStr "\${XDG_CONFIG_HOME:-$HOME/.config}/app" => "\${XDG_CONFIG_HOME:-$HOME/.config}/app"
|
||||
*/
|
||||
mkShellVarPathStr =
|
||||
pathStr:
|
||||
let
|
||||
cleanPath = lib.removeSuffix "/" pathStr;
|
||||
hasShellVars = lib.hasInfix "$" cleanPath;
|
||||
normPath = stripSlash pathStr;
|
||||
hasShellVars = lib.hasInfix "$" normPath;
|
||||
in
|
||||
if hasShellVars then
|
||||
# Does not escape shell variables, allowing them to be expanded at runtime
|
||||
cleanPath
|
||||
else
|
||||
# For literal paths, make them absolute if needed and escape them
|
||||
cleanPathStr ((lib.optionalString (!lib.hasPrefix "/" cleanPath) "${homeDir}/") + cleanPath);
|
||||
if hasShellVars then normPath else mkAbsPathStr normPath;
|
||||
|
||||
dotDirAbs = mkAbsPathStr cfg.dotDir;
|
||||
dotDirRel = mkRelPathStr cfg.dotDir;
|
||||
@@ -107,5 +114,5 @@ rec {
|
||||
|
||||
Type: String
|
||||
*/
|
||||
pluginsDir = dotDirAbs + (lib.optionalString (homeDir == dotDirAbs) "/.zsh") + "/plugins";
|
||||
pluginsDir = dotDirAbs + (lib.optionalString (mkRelPathStr cfg.dotDir == ".") "/.zsh") + "/plugins";
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ let
|
||||
);
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ foo-dogsquared ];
|
||||
meta.maintainers = [ ];
|
||||
|
||||
options.services.activitywatch = {
|
||||
enable = lib.mkEnableOption "ActivityWatch, an automated time tracker";
|
||||
|
||||
@@ -32,78 +32,72 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf serviceConfig.enable (
|
||||
lib.mkMerge [
|
||||
(lib.mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user = {
|
||||
services.borgmatic = {
|
||||
Unit = {
|
||||
Description = "borgmatic backup";
|
||||
# Prevent borgmatic from running unless the machine is
|
||||
# plugged into power:
|
||||
ConditionACPower = true;
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
|
||||
# Lower CPU and I/O priority:
|
||||
Nice = 19;
|
||||
IOSchedulingClass = "best-effort";
|
||||
IOSchedulingPriority = 7;
|
||||
IOWeight = 100;
|
||||
|
||||
Restart = "no";
|
||||
LogRateLimitIntervalSec = 0;
|
||||
|
||||
# Delay start to prevent backups running during boot:
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/sleep 3m";
|
||||
|
||||
ExecStart = ''
|
||||
${pkgs.systemd}/bin/systemd-inhibit \
|
||||
--who="borgmatic" \
|
||||
--what="sleep:shutdown" \
|
||||
--why="Prevent interrupting scheduled backup" \
|
||||
${programConfig.package}/bin/borgmatic \
|
||||
--stats \
|
||||
--verbosity -1 \
|
||||
--list \
|
||||
--syslog-verbosity 1
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
timers.borgmatic = {
|
||||
Unit.Description = "Run borgmatic backup";
|
||||
Timer = {
|
||||
OnCalendar = serviceConfig.frequency;
|
||||
Persistent = true;
|
||||
RandomizedDelaySec = "10m";
|
||||
};
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
};
|
||||
config = lib.mkIf serviceConfig.enable {
|
||||
systemd.user = {
|
||||
services.borgmatic = {
|
||||
Unit = {
|
||||
Description = "borgmatic backup";
|
||||
# Prevent borgmatic from running unless the machine is
|
||||
# plugged into power:
|
||||
ConditionACPower = true;
|
||||
};
|
||||
})
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
|
||||
(lib.mkIf pkgs.stdenv.isDarwin {
|
||||
assertions = [
|
||||
(lib.hm.darwin.assertInterval "services.borgmatic.frequency" serviceConfig.frequency pkgs)
|
||||
# Lower CPU and I/O priority:
|
||||
Nice = 19;
|
||||
IOSchedulingClass = "best-effort";
|
||||
IOSchedulingPriority = 7;
|
||||
IOWeight = 100;
|
||||
|
||||
Restart = "no";
|
||||
LogRateLimitIntervalSec = 0;
|
||||
|
||||
# Delay start to prevent backups running during boot:
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/sleep 3m";
|
||||
|
||||
ExecStart = ''
|
||||
${pkgs.systemd}/bin/systemd-inhibit \
|
||||
--who="borgmatic" \
|
||||
--what="sleep:shutdown" \
|
||||
--why="Prevent interrupting scheduled backup" \
|
||||
${programConfig.package}/bin/borgmatic \
|
||||
--stats \
|
||||
--verbosity -1 \
|
||||
--list \
|
||||
--syslog-verbosity 1
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
timers.borgmatic = {
|
||||
Unit.Description = "Run borgmatic backup";
|
||||
Timer = {
|
||||
OnCalendar = serviceConfig.frequency;
|
||||
Persistent = true;
|
||||
RandomizedDelaySec = "10m";
|
||||
};
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
assertions = [
|
||||
(lib.hm.darwin.assertInterval "services.borgmatic.frequency" serviceConfig.frequency pkgs)
|
||||
];
|
||||
|
||||
launchd.agents.borgmatic = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
(lib.getExe programConfig.package)
|
||||
"--stats"
|
||||
"--list"
|
||||
];
|
||||
|
||||
launchd.agents.borgmatic = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
(lib.getExe programConfig.package)
|
||||
"--stats"
|
||||
"--list"
|
||||
];
|
||||
ProcessType = "Background";
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval serviceConfig.frequency;
|
||||
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/borgmatic/launchd-stdout.log";
|
||||
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/borgmatic/launchd-stderr.log";
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
ProcessType = "Background";
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval serviceConfig.frequency;
|
||||
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/borgmatic/launchd-stdout.log";
|
||||
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/borgmatic/launchd-stderr.log";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ in
|
||||
|
||||
xdg.configFile."clipse/custom_theme.json".source = jsonFormat.generate "theme" cfg.theme;
|
||||
|
||||
systemd.user.services.clipse = lib.mkIf (pkgs.stdenv.isLinux && (cfg.package != null)) {
|
||||
systemd.user.services.clipse = lib.mkIf (cfg.package != null) {
|
||||
Unit = {
|
||||
Description = "Clipse listener";
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
|
||||
262
modules/services/colima.nix
Normal file
262
modules/services/colima.nix
Normal file
@@ -0,0 +1,262 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.colima;
|
||||
yamlFormat = pkgs.formats.yaml { };
|
||||
in
|
||||
{
|
||||
meta.maintainers = [
|
||||
lib.hm.maintainers.will-lol
|
||||
];
|
||||
|
||||
options.services.colima = {
|
||||
enable = lib.mkEnableOption "Colima, a container runtime";
|
||||
|
||||
package = lib.mkPackageOption pkgs "colima" { };
|
||||
dockerPackage = lib.mkPackageOption pkgs "docker" {
|
||||
extraDescription = "Used by colima to activate profiles. Not needed if no profile is set to isActive.";
|
||||
};
|
||||
perlPackage = lib.mkPackageOption pkgs "perl" {
|
||||
extraDescription = "Used by colima during image download for the shasum command.";
|
||||
};
|
||||
sshPackage = lib.mkPackageOption pkgs "openssh" {
|
||||
extraDescription = "Used by colima to manage the vm.";
|
||||
};
|
||||
coreutilsPackage = lib.mkPackageOption pkgs "coreutils" {
|
||||
extraDescription = "Used in various ways by colima.";
|
||||
};
|
||||
curlPackage = lib.mkPackageOption pkgs "curl" {
|
||||
extraDescription = "Used by colima to donwload images.";
|
||||
};
|
||||
bashPackage = lib.mkPackageOption pkgs "bashNonInteractive" {
|
||||
extraDescription = "Used by colima's internal scripts.";
|
||||
};
|
||||
|
||||
profiles = lib.mkOption {
|
||||
default = {
|
||||
default = {
|
||||
isActive = true;
|
||||
isService = true;
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
Profiles allow multiple colima configurations. The default profile is active by default.
|
||||
If you have used colima before, you may need to delete existing configuration using `colima delete` or use a different profile.
|
||||
|
||||
Note that removing a configured profile will not delete the corresponding Colima instance.
|
||||
You will need to manually run `colima delete <profile-name>` to remove the instance and release resources.
|
||||
'';
|
||||
example = ''
|
||||
{
|
||||
default = {
|
||||
isActive = true;
|
||||
isService = true;
|
||||
};
|
||||
rosetta = {
|
||||
isService = true;
|
||||
settings.rosetta = true;
|
||||
};
|
||||
powerful = {
|
||||
settings.cpu = 8;
|
||||
};
|
||||
};
|
||||
'';
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ name, ... }:
|
||||
{
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = name;
|
||||
readOnly = true;
|
||||
description = "The profile's name.";
|
||||
};
|
||||
|
||||
isService = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether this profile will run as a service.
|
||||
'';
|
||||
};
|
||||
|
||||
isActive = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether to set this profile as:
|
||||
- active docker context
|
||||
- active kubernetes context
|
||||
- active incus remote
|
||||
Exactly one or zero profiles should have this option set.
|
||||
'';
|
||||
};
|
||||
|
||||
logFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "${config.home.homeDirectory}/.local/state/colima-${name}.log";
|
||||
defaultText = lib.literalExpression "\${config.home.homeDirectory}/.local/state/colima-\${name}.log";
|
||||
description = "Combined stdout and stderr log file for the Colima service.";
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
inherit (yamlFormat) type;
|
||||
default = { };
|
||||
description = "Colima configuration settings, see <https://github.com/abiosoft/colima/blob/main/embedded/defaults/colima.yaml> or run `colima template`.";
|
||||
example = ''
|
||||
{
|
||||
cpu = 2;
|
||||
disk = 100;
|
||||
memory = 2;
|
||||
arch = "host";
|
||||
runtime = "docker";
|
||||
hostname = null;
|
||||
kubernetes = {
|
||||
enabled = false;
|
||||
version = "v1.33.3+k3s1";
|
||||
k3sArgs = [ "--disable=traefik" ];
|
||||
port = 0;
|
||||
};
|
||||
autoActivate = true;
|
||||
network = {
|
||||
address = false;
|
||||
mode = "shared";
|
||||
interface = "en0";
|
||||
preferredRoute = false;
|
||||
dns = [ ];
|
||||
dnsHosts = {
|
||||
"host.docker.internal" = "host.lima.internal";
|
||||
};
|
||||
hostAddresses = false;
|
||||
};
|
||||
forwardAgent = false;
|
||||
docker = { };
|
||||
vmType = "qemu";
|
||||
portForwarder = "ssh";
|
||||
rosetta = false;
|
||||
binfmt = true;
|
||||
nestedVirtualization = false;
|
||||
mountType = "sshfs";
|
||||
mountInotify = false;
|
||||
cpuType = "host";
|
||||
provision = [ ];
|
||||
sshConfig = true;
|
||||
sshPort = 0;
|
||||
mounts = [ ];
|
||||
diskImage = "";
|
||||
rootDisk = 20;
|
||||
env = { };
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = (lib.count (p: p.isActive) (lib.attrValues cfg.profiles)) <= 1;
|
||||
message = "Only one Colima profile can be active at a time.";
|
||||
}
|
||||
];
|
||||
|
||||
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
||||
|
||||
home.file = lib.mkMerge (
|
||||
lib.mapAttrsToList (profileName: profile: {
|
||||
".colima/${profileName}/colima.yaml" = {
|
||||
source = yamlFormat.generate "colima.yaml" profile.settings;
|
||||
};
|
||||
}) (lib.filterAttrs (name: profile: profile.settings != { }) cfg.profiles)
|
||||
);
|
||||
|
||||
programs.docker-cli.settings.currentContext =
|
||||
let
|
||||
activeProfile = lib.findFirst (p: p.isActive) null (lib.attrValues cfg.profiles);
|
||||
in
|
||||
lib.mkIf (activeProfile != null) (
|
||||
if activeProfile.name != "default" then "colima-${activeProfile.name}" else "colima"
|
||||
);
|
||||
|
||||
launchd.agents = lib.mapAttrs' (
|
||||
name: profile:
|
||||
lib.nameValuePair "colima-${name}" {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${lib.getExe cfg.package}"
|
||||
"start"
|
||||
name
|
||||
"-f"
|
||||
"--activate=${if profile.isActive then "true" else "false"}"
|
||||
"--save-config=false"
|
||||
];
|
||||
KeepAlive = true;
|
||||
RunAtLoad = true;
|
||||
EnvironmentVariables.PATH = lib.makeBinPath [
|
||||
cfg.package
|
||||
cfg.perlPackage
|
||||
cfg.dockerPackage
|
||||
cfg.sshPackage
|
||||
cfg.coreutilsPackage
|
||||
cfg.curlPackage
|
||||
cfg.bashPackage
|
||||
pkgs.darwin.DarwinTools
|
||||
];
|
||||
StandardOutPath = profile.logFile;
|
||||
StandardErrorPath = profile.logFile;
|
||||
};
|
||||
}
|
||||
) (lib.filterAttrs (_: p: p.isService) cfg.profiles);
|
||||
|
||||
systemd.user.services = lib.mapAttrs' (
|
||||
name: profile:
|
||||
lib.nameValuePair "colima-${name}" {
|
||||
Unit = {
|
||||
Description = "Colima container runtime (${name} profile)";
|
||||
After = [ "network-online.target" ];
|
||||
Wants = [ "network-online.target" ];
|
||||
};
|
||||
Service = {
|
||||
ExecStart = ''
|
||||
${lib.getExe cfg.package} start ${name} \
|
||||
-f \
|
||||
--activate=${if profile.isActive then "true" else "false"} \
|
||||
--save-config=false
|
||||
'';
|
||||
Restart = "always";
|
||||
RestartSec = 2;
|
||||
Environment = [
|
||||
"PATH=${
|
||||
lib.makeBinPath [
|
||||
cfg.package
|
||||
cfg.perlPackage
|
||||
cfg.dockerPackage
|
||||
cfg.sshPackage
|
||||
cfg.coreutilsPackage
|
||||
cfg.curlPackage
|
||||
cfg.bashPackage
|
||||
]
|
||||
}"
|
||||
];
|
||||
StandardOutput = "append:${profile.logFile}";
|
||||
StandardError = "append:${profile.logFile}";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "default.target" ];
|
||||
};
|
||||
}
|
||||
) (lib.filterAttrs (_: p: p.isService) cfg.profiles);
|
||||
};
|
||||
}
|
||||
@@ -117,6 +117,8 @@ in
|
||||
systemd.user.services.easyeffects = {
|
||||
Unit = {
|
||||
Description = "Easyeffects daemon";
|
||||
After = [ "graphical-session.target" ];
|
||||
PartOf = [ "graphical-session.target" ];
|
||||
};
|
||||
|
||||
Install.WantedBy = [ "graphical-session.target" ];
|
||||
|
||||
@@ -107,133 +107,129 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
defaultEditor = mkOption rec {
|
||||
defaultEditor = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = !default;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether to configure {command}`emacsclient` as the default
|
||||
editor using the {env}`EDITOR` environment variable.
|
||||
editor using the {env}`EDITOR` and {env}`VISUAL`
|
||||
environment variables.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
home.sessionVariables = mkIf cfg.defaultEditor {
|
||||
EDITOR = lib.getBin (
|
||||
pkgs.writeShellScript "editor" ''exec ${lib.getBin cfg.package}/bin/emacsclient "''${@:---create-frame}"''
|
||||
);
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
home.sessionVariables =
|
||||
let
|
||||
editorBin = lib.getBin (
|
||||
pkgs.writeShellScript "editor" ''exec ${lib.getBin cfg.package}/bin/emacsclient "''${@:---create-frame}"''
|
||||
);
|
||||
in
|
||||
mkIf cfg.defaultEditor {
|
||||
EDITOR = editorBin;
|
||||
VISUAL = editorBin;
|
||||
};
|
||||
|
||||
home.packages = optional (cfg.client.enable && pkgs.stdenv.isLinux) (lib.hiPrio clientDesktopItem);
|
||||
|
||||
systemd.user.services.emacs = {
|
||||
Unit = {
|
||||
Description = "Emacs text editor";
|
||||
Documentation = "info:emacs man:emacs(1) https://gnu.org/software/emacs/";
|
||||
|
||||
After = optional (cfg.startWithUserSession == "graphical") "graphical-session.target";
|
||||
PartOf = optional (cfg.startWithUserSession == "graphical") "graphical-session.target";
|
||||
|
||||
# Avoid killing the Emacs session, which may be full of
|
||||
# unsaved buffers.
|
||||
X-RestartIfChanged = false;
|
||||
}
|
||||
// optionalAttrs needsSocketWorkaround {
|
||||
# Emacs deletes its socket when shutting down, which systemd doesn't
|
||||
# handle, resulting in a server without a socket.
|
||||
# See https://github.com/nix-community/home-manager/issues/2018
|
||||
RefuseManualStart = true;
|
||||
};
|
||||
|
||||
(mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user.services.emacs = {
|
||||
Unit = {
|
||||
Description = "Emacs text editor";
|
||||
Documentation = "info:emacs man:emacs(1) https://gnu.org/software/emacs/";
|
||||
Service = {
|
||||
Type = "notify";
|
||||
|
||||
After = optional (cfg.startWithUserSession == "graphical") "graphical-session.target";
|
||||
PartOf = optional (cfg.startWithUserSession == "graphical") "graphical-session.target";
|
||||
# We wrap ExecStart in a login shell so Emacs starts with the user's
|
||||
# environment, most importantly $PATH and $NIX_PROFILES. It may be
|
||||
# worth investigating a more targeted approach for user services to
|
||||
# import the user environment.
|
||||
ExecStart = ''${pkgs.runtimeShell} -l -c "${emacsBinPath}/emacs --fg-daemon${
|
||||
# In case the user sets 'server-directory' or 'server-name' in
|
||||
# their Emacs config, we want to specify the socket path explicitly
|
||||
# so launching 'emacs.service' manually doesn't break emacsclient
|
||||
# when using socket activation.
|
||||
lib.optionalString cfg.socketActivation.enable "=${lib.escapeShellArg socketPath}"
|
||||
} ${lib.escapeShellArgs cfg.extraOptions}"'';
|
||||
|
||||
# Avoid killing the Emacs session, which may be full of
|
||||
# unsaved buffers.
|
||||
X-RestartIfChanged = false;
|
||||
}
|
||||
// optionalAttrs needsSocketWorkaround {
|
||||
# Emacs deletes its socket when shutting down, which systemd doesn't
|
||||
# handle, resulting in a server without a socket.
|
||||
# See https://github.com/nix-community/home-manager/issues/2018
|
||||
RefuseManualStart = true;
|
||||
};
|
||||
# Emacs will exit with status 15 after having received SIGTERM, which
|
||||
# is the default "KillSignal" value systemd uses to stop services.
|
||||
SuccessExitStatus = 15;
|
||||
|
||||
Service = {
|
||||
Type = "notify";
|
||||
Restart = "on-failure";
|
||||
}
|
||||
// optionalAttrs needsSocketWorkaround {
|
||||
# Use read-only directory permissions to prevent emacs from
|
||||
# deleting systemd's socket file before exiting.
|
||||
ExecStartPost = "${pkgs.coreutils}/bin/chmod --changes -w ${socketDir}";
|
||||
ExecStopPost = "${pkgs.coreutils}/bin/chmod --changes +w ${socketDir}";
|
||||
};
|
||||
}
|
||||
// optionalAttrs (cfg.startWithUserSession != false) {
|
||||
Install = {
|
||||
WantedBy = [
|
||||
(if cfg.startWithUserSession == true then "default.target" else "graphical-session.target")
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# We wrap ExecStart in a login shell so Emacs starts with the user's
|
||||
# environment, most importantly $PATH and $NIX_PROFILES. It may be
|
||||
# worth investigating a more targeted approach for user services to
|
||||
# import the user environment.
|
||||
ExecStart = ''${pkgs.runtimeShell} -l -c "${emacsBinPath}/emacs --fg-daemon${
|
||||
# In case the user sets 'server-directory' or 'server-name' in
|
||||
# their Emacs config, we want to specify the socket path explicitly
|
||||
# so launching 'emacs.service' manually doesn't break emacsclient
|
||||
# when using socket activation.
|
||||
lib.optionalString cfg.socketActivation.enable "=${lib.escapeShellArg socketPath}"
|
||||
} ${lib.escapeShellArgs cfg.extraOptions}"'';
|
||||
systemd.user.sockets.emacs = mkIf cfg.socketActivation.enable {
|
||||
Unit = {
|
||||
Description = "Emacs text editor";
|
||||
Documentation = "info:emacs man:emacs(1) https://gnu.org/software/emacs/";
|
||||
};
|
||||
|
||||
# Emacs will exit with status 15 after having received SIGTERM, which
|
||||
# is the default "KillSignal" value systemd uses to stop services.
|
||||
SuccessExitStatus = 15;
|
||||
Socket = {
|
||||
ListenStream = socketPath;
|
||||
FileDescriptorName = "server";
|
||||
SocketMode = "0600";
|
||||
DirectoryMode = "0700";
|
||||
# This prevents the service from immediately starting again
|
||||
# after being stopped, due to the function
|
||||
# `server-force-stop' present in `kill-emacs-hook', which
|
||||
# calls `server-running-p', which opens the socket file.
|
||||
FlushPending = true;
|
||||
};
|
||||
|
||||
Restart = "on-failure";
|
||||
}
|
||||
// optionalAttrs needsSocketWorkaround {
|
||||
# Use read-only directory permissions to prevent emacs from
|
||||
# deleting systemd's socket file before exiting.
|
||||
ExecStartPost = "${pkgs.coreutils}/bin/chmod --changes -w ${socketDir}";
|
||||
ExecStopPost = "${pkgs.coreutils}/bin/chmod --changes +w ${socketDir}";
|
||||
};
|
||||
}
|
||||
// optionalAttrs (cfg.startWithUserSession != false) {
|
||||
Install = {
|
||||
WantedBy = [
|
||||
(if cfg.startWithUserSession == true then "default.target" else "graphical-session.target")
|
||||
];
|
||||
};
|
||||
Install = {
|
||||
WantedBy = [ "sockets.target" ];
|
||||
# Adding this Requires= dependency ensures that systemd
|
||||
# manages the socket file, in the case where the service is
|
||||
# started when the socket is stopped.
|
||||
# The socket unit is implicitly ordered before the service.
|
||||
RequiredBy = [ "emacs.service" ];
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.emacs = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${cfg.package}/bin/emacs"
|
||||
"--fg-daemon"
|
||||
]
|
||||
++ cfg.extraOptions;
|
||||
RunAtLoad = true;
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
|
||||
home.packages = optional cfg.client.enable (lib.hiPrio clientDesktopItem);
|
||||
})
|
||||
|
||||
(mkIf (cfg.socketActivation.enable && pkgs.stdenv.isLinux) {
|
||||
systemd.user.sockets.emacs = {
|
||||
Unit = {
|
||||
Description = "Emacs text editor";
|
||||
Documentation = "info:emacs man:emacs(1) https://gnu.org/software/emacs/";
|
||||
};
|
||||
|
||||
Socket = {
|
||||
ListenStream = socketPath;
|
||||
FileDescriptorName = "server";
|
||||
SocketMode = "0600";
|
||||
DirectoryMode = "0700";
|
||||
# This prevents the service from immediately starting again
|
||||
# after being stopped, due to the function
|
||||
# `server-force-stop' present in `kill-emacs-hook', which
|
||||
# calls `server-running-p', which opens the socket file.
|
||||
FlushPending = true;
|
||||
};
|
||||
|
||||
Install = {
|
||||
WantedBy = [ "sockets.target" ];
|
||||
# Adding this Requires= dependency ensures that systemd
|
||||
# manages the socket file, in the case where the service is
|
||||
# started when the socket is stopped.
|
||||
# The socket unit is implicitly ordered before the service.
|
||||
RequiredBy = [ "emacs.service" ];
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf pkgs.stdenv.isDarwin {
|
||||
launchd.agents.emacs = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${cfg.package}/bin/emacs"
|
||||
"--fg-daemon"
|
||||
]
|
||||
++ cfg.extraOptions;
|
||||
RunAtLoad = true;
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,49 +15,12 @@ let
|
||||
|
||||
cfg = config.services.git-sync;
|
||||
|
||||
mkUnit = name: repo: {
|
||||
Unit.Description = "Git Sync ${name}";
|
||||
|
||||
Install.WantedBy = [ "default.target" ];
|
||||
|
||||
Service = {
|
||||
Environment = [
|
||||
"PATH=${
|
||||
lib.makeBinPath (
|
||||
with pkgs;
|
||||
[
|
||||
openssh
|
||||
git
|
||||
]
|
||||
++ repo.extraPackages
|
||||
)
|
||||
}"
|
||||
"GIT_SYNC_DIRECTORY=${lib.strings.escapeShellArg repo.path}"
|
||||
"GIT_SYNC_COMMAND=${cfg.package}/bin/git-sync"
|
||||
"GIT_SYNC_REPOSITORY=${lib.strings.escapeShellArg repo.uri}"
|
||||
"GIT_SYNC_INTERVAL=${toString repo.interval}"
|
||||
];
|
||||
ExecStart = "${cfg.package}/bin/git-sync-on-inotify";
|
||||
Restart = "on-abort";
|
||||
};
|
||||
};
|
||||
|
||||
mkAgent = name: repo: {
|
||||
enable = true;
|
||||
config = {
|
||||
StartInterval = repo.interval;
|
||||
ProcessType = "Background";
|
||||
WorkingDirectory = "${repo.path}";
|
||||
WatchPaths = [ "${repo.path}" ];
|
||||
ProgramArguments = [ "${cfg.package}/bin/git-sync" ];
|
||||
};
|
||||
};
|
||||
|
||||
mkService = if pkgs.stdenv.isLinux then mkUnit else mkAgent;
|
||||
services = lib.mapAttrs' (name: repo: {
|
||||
name = "git-sync-${name}";
|
||||
value = mkService name repo;
|
||||
}) cfg.repositories;
|
||||
services =
|
||||
mkService:
|
||||
lib.mapAttrs' (name: repo: {
|
||||
name = "git-sync-${name}";
|
||||
value = mkService name repo;
|
||||
}) cfg.repositories;
|
||||
|
||||
repositoryType = types.submodule (
|
||||
{ name, ... }:
|
||||
@@ -141,11 +104,48 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
(mkIf pkgs.stdenv.isLinux { systemd.user.services = services; })
|
||||
(mkIf pkgs.stdenv.isDarwin { launchd.agents = services; })
|
||||
]
|
||||
);
|
||||
config = mkIf cfg.enable {
|
||||
launchd.agents = services (
|
||||
name: repo: {
|
||||
enable = true;
|
||||
config = {
|
||||
StartInterval = repo.interval;
|
||||
ProcessType = "Background";
|
||||
WorkingDirectory = "${repo.path}";
|
||||
WatchPaths = [ "${repo.path}" ];
|
||||
ProgramArguments = [ "${cfg.package}/bin/git-sync" ];
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
systemd.user.services = services (
|
||||
name: repo: {
|
||||
Unit.Description = "Git Sync ${name}";
|
||||
|
||||
Install.WantedBy = [ "default.target" ];
|
||||
|
||||
Service = {
|
||||
Environment = [
|
||||
"PATH=${
|
||||
lib.makeBinPath (
|
||||
with pkgs;
|
||||
[
|
||||
openssh
|
||||
git
|
||||
]
|
||||
++ repo.extraPackages
|
||||
)
|
||||
}"
|
||||
"GIT_SYNC_DIRECTORY=${lib.strings.escapeShellArg repo.path}"
|
||||
"GIT_SYNC_COMMAND=${cfg.package}/bin/git-sync"
|
||||
"GIT_SYNC_REPOSITORY=${lib.strings.escapeShellArg repo.uri}"
|
||||
"GIT_SYNC_INTERVAL=${toString repo.interval}"
|
||||
];
|
||||
ExecStart = "${cfg.package}/bin/git-sync-on-inotify";
|
||||
Restart = "on-abort";
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -344,125 +344,115 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
# Grab the default binary name and fallback to expected value if `meta.mainProgram` not set
|
||||
services.gpg-agent.pinentry.program = lib.mkOptionDefault (
|
||||
cfg.pinentry.package.meta.mainProgram or "pinentry"
|
||||
);
|
||||
config = mkIf cfg.enable {
|
||||
# Grab the default binary name and fallback to expected value if `meta.mainProgram` not set
|
||||
services.gpg-agent.pinentry.program = lib.mkOptionDefault (
|
||||
cfg.pinentry.package.meta.mainProgram or "pinentry"
|
||||
);
|
||||
|
||||
home.file."${homedir}/gpg-agent.conf".text = lib.concatStringsSep "\n" (
|
||||
optional cfg.enableSshSupport "enable-ssh-support"
|
||||
++ optional cfg.grabKeyboardAndMouse "grab"
|
||||
++ optional (!cfg.enableScDaemon) "disable-scdaemon"
|
||||
++ optional cfg.noAllowExternalCache "no-allow-external-cache"
|
||||
++ optional (cfg.defaultCacheTtl != null) "default-cache-ttl ${toString cfg.defaultCacheTtl}"
|
||||
++ optional (
|
||||
cfg.defaultCacheTtlSsh != null
|
||||
) "default-cache-ttl-ssh ${toString cfg.defaultCacheTtlSsh}"
|
||||
++ optional (cfg.maxCacheTtl != null) "max-cache-ttl ${toString cfg.maxCacheTtl}"
|
||||
++ optional (cfg.maxCacheTtlSsh != null) "max-cache-ttl-ssh ${toString cfg.maxCacheTtlSsh}"
|
||||
++ optional (
|
||||
cfg.pinentry.package != null
|
||||
) "pinentry-program ${lib.getExe' cfg.pinentry.package cfg.pinentry.program}"
|
||||
++ [ cfg.extraConfig ]
|
||||
);
|
||||
home.file."${homedir}/gpg-agent.conf".text = lib.concatStringsSep "\n" (
|
||||
optional cfg.enableSshSupport "enable-ssh-support"
|
||||
++ optional cfg.grabKeyboardAndMouse "grab"
|
||||
++ optional (!cfg.enableScDaemon) "disable-scdaemon"
|
||||
++ optional cfg.noAllowExternalCache "no-allow-external-cache"
|
||||
++ optional (cfg.defaultCacheTtl != null) "default-cache-ttl ${toString cfg.defaultCacheTtl}"
|
||||
++ optional (
|
||||
cfg.defaultCacheTtlSsh != null
|
||||
) "default-cache-ttl-ssh ${toString cfg.defaultCacheTtlSsh}"
|
||||
++ optional (cfg.maxCacheTtl != null) "max-cache-ttl ${toString cfg.maxCacheTtl}"
|
||||
++ optional (cfg.maxCacheTtlSsh != null) "max-cache-ttl-ssh ${toString cfg.maxCacheTtlSsh}"
|
||||
++ optional (
|
||||
cfg.pinentry.package != null
|
||||
) "pinentry-program ${lib.getExe' cfg.pinentry.package cfg.pinentry.program}"
|
||||
++ [ cfg.extraConfig ]
|
||||
);
|
||||
|
||||
home.sessionVariablesExtra = optionalString cfg.enableSshSupport ''
|
||||
unset SSH_AGENT_PID
|
||||
if [ -z "$SSH_CONNECTION" -o -z "$SSH_AUTH_SOCK" ] && [ "''${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
|
||||
export SSH_AUTH_SOCK="$(${gpgPkg}/bin/gpgconf --list-dirs agent-ssh-socket)"
|
||||
fi
|
||||
'';
|
||||
home.sessionVariablesExtra = optionalString cfg.enableSshSupport ''
|
||||
unset SSH_AGENT_PID
|
||||
if [ -z "$SSH_CONNECTION" -o -z "$SSH_AUTH_SOCK" ] && [ "''${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
|
||||
export SSH_AUTH_SOCK="$(${gpgPkg}/bin/gpgconf --list-dirs agent-ssh-socket)"
|
||||
fi
|
||||
'';
|
||||
|
||||
programs = {
|
||||
bash.initExtra = mkIf cfg.enableBashIntegration gpgBashInitStr;
|
||||
zsh.initContent = mkIf cfg.enableZshIntegration gpgZshInitStr;
|
||||
fish.interactiveShellInit = mkIf cfg.enableFishIntegration gpgFishInitStr;
|
||||
nushell.extraConfig = mkIf cfg.enableNushellIntegration gpgNushellInitStr;
|
||||
programs = {
|
||||
bash.initExtra = mkIf cfg.enableBashIntegration gpgBashInitStr;
|
||||
zsh.initContent = mkIf cfg.enableZshIntegration gpgZshInitStr;
|
||||
fish.interactiveShellInit = mkIf cfg.enableFishIntegration gpgFishInitStr;
|
||||
nushell.extraConfig = mkIf cfg.enableNushellIntegration gpgNushellInitStr;
|
||||
};
|
||||
|
||||
# Trailing newlines are important
|
||||
home.file."${homedir}/sshcontrol" = mkIf (cfg.sshKeys != null) {
|
||||
text = lib.concatMapStrings (s: ''
|
||||
${s}
|
||||
'') cfg.sshKeys;
|
||||
};
|
||||
|
||||
systemd.user = {
|
||||
services.gpg-agent = {
|
||||
Unit = {
|
||||
Description = "GnuPG cryptographic agent and passphrase cache";
|
||||
Documentation = "man:gpg-agent(1)";
|
||||
Requires = "gpg-agent.socket";
|
||||
After = "gpg-agent.socket";
|
||||
# This is a socket-activated service:
|
||||
RefuseManualStart = true;
|
||||
};
|
||||
}
|
||||
|
||||
(mkIf (cfg.sshKeys != null) {
|
||||
# Trailing newlines are important
|
||||
home.file."${homedir}/sshcontrol".text = lib.concatMapStrings (s: ''
|
||||
${s}
|
||||
'') cfg.sshKeys;
|
||||
})
|
||||
Service = {
|
||||
ExecStart = "${gpgPkg}/bin/gpg-agent --supervised" + optionalString cfg.verbose " --verbose";
|
||||
ExecReload = "${gpgPkg}/bin/gpgconf --reload gpg-agent";
|
||||
Environment = [ "GNUPGHOME=${homedir}" ];
|
||||
};
|
||||
};
|
||||
|
||||
(lib.mkMerge [
|
||||
(mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user = {
|
||||
services.gpg-agent = {
|
||||
Unit = {
|
||||
Description = "GnuPG cryptographic agent and passphrase cache";
|
||||
Documentation = "man:gpg-agent(1)";
|
||||
Requires = "gpg-agent.socket";
|
||||
After = "gpg-agent.socket";
|
||||
# This is a socket-activated service:
|
||||
RefuseManualStart = true;
|
||||
};
|
||||
sockets = {
|
||||
gpg-agent = mkSocket {
|
||||
desc = "GnuPG cryptographic agent and passphrase cache";
|
||||
docs = "man:gpg-agent(1)";
|
||||
stream = "S.gpg-agent";
|
||||
fdName = "std";
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = "${gpgPkg}/bin/gpg-agent --supervised" + optionalString cfg.verbose " --verbose";
|
||||
ExecReload = "${gpgPkg}/bin/gpgconf --reload gpg-agent";
|
||||
Environment = [ "GNUPGHOME=${homedir}" ];
|
||||
};
|
||||
};
|
||||
gpg-agent-ssh = mkIf cfg.enableSshSupport (mkSocket {
|
||||
desc = "GnuPG cryptographic agent (ssh-agent emulation)";
|
||||
docs = "man:gpg-agent(1) man:ssh-add(1) man:ssh-agent(1) man:ssh(1)";
|
||||
stream = "S.gpg-agent.ssh";
|
||||
fdName = "ssh";
|
||||
});
|
||||
|
||||
sockets = {
|
||||
gpg-agent = mkSocket {
|
||||
desc = "GnuPG cryptographic agent and passphrase cache";
|
||||
docs = "man:gpg-agent(1)";
|
||||
stream = "S.gpg-agent";
|
||||
fdName = "std";
|
||||
};
|
||||
gpg-agent-extra = mkIf cfg.enableExtraSocket (mkSocket {
|
||||
desc = "GnuPG cryptographic agent and passphrase cache (restricted)";
|
||||
docs = "man:gpg-agent(1) man:ssh(1)";
|
||||
stream = "S.gpg-agent.extra";
|
||||
fdName = "extra";
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
gpg-agent-ssh = mkIf cfg.enableSshSupport (mkSocket {
|
||||
desc = "GnuPG cryptographic agent (ssh-agent emulation)";
|
||||
docs = "man:gpg-agent(1) man:ssh-add(1) man:ssh-agent(1) man:ssh(1)";
|
||||
stream = "S.gpg-agent.ssh";
|
||||
fdName = "ssh";
|
||||
});
|
||||
|
||||
gpg-agent-extra = mkIf cfg.enableExtraSocket (mkSocket {
|
||||
desc = "GnuPG cryptographic agent and passphrase cache (restricted)";
|
||||
docs = "man:gpg-agent(1) man:ssh(1)";
|
||||
stream = "S.gpg-agent.extra";
|
||||
fdName = "extra";
|
||||
});
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf pkgs.stdenv.isDarwin {
|
||||
launchd.agents.gpg-agent = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${gpgPkg}/bin/gpg-agent"
|
||||
"--supervised"
|
||||
]
|
||||
++ optional cfg.verbose "--verbose";
|
||||
EnvironmentVariables = {
|
||||
GNUPGHOME = homedir;
|
||||
};
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
RunAtLoad = cfg.enableSshSupport;
|
||||
Sockets = {
|
||||
Agent = mkAgentSock "S.gpg-agent";
|
||||
Ssh = mkIf cfg.enableSshSupport (mkAgentSock "S.gpg-agent.ssh");
|
||||
Extra = mkIf cfg.enableExtraSocket (mkAgentSock "S.gpg-agent.extra");
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
])
|
||||
]
|
||||
);
|
||||
launchd.agents.gpg-agent = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
"${gpgPkg}/bin/gpg-agent"
|
||||
"--supervised"
|
||||
]
|
||||
++ optional cfg.verbose "--verbose";
|
||||
EnvironmentVariables = {
|
||||
GNUPGHOME = homedir;
|
||||
};
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
RunAtLoad = cfg.enableSshSupport;
|
||||
Sockets = {
|
||||
Agent = mkAgentSock "S.gpg-agent";
|
||||
Ssh = mkIf cfg.enableSshSupport (mkAgentSock "S.gpg-agent.ssh");
|
||||
Extra = mkIf cfg.enableExtraSocket (mkAgentSock "S.gpg-agent.extra");
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -81,46 +81,38 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable (
|
||||
lib.mkMerge [
|
||||
(lib.mkIf pkgs.stdenv.isLinux {
|
||||
systemd.user = {
|
||||
timers.home-manager-auto-expire = {
|
||||
Unit.Description = "Home Manager expire generations timer";
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
|
||||
Timer = {
|
||||
OnCalendar = cfg.frequency;
|
||||
Unit = "home-manager-auto-expire.service";
|
||||
Persistent = true;
|
||||
};
|
||||
};
|
||||
|
||||
services.home-manager-auto-expire = {
|
||||
Unit.Description = "Home Manager expire generations";
|
||||
|
||||
Service.ExecStart = toString script;
|
||||
};
|
||||
systemd.user = {
|
||||
timers.home-manager-auto-expire = {
|
||||
Unit.Description = "Home Manager expire generations timer";
|
||||
Install.WantedBy = [ "timers.target" ];
|
||||
Timer = {
|
||||
OnCalendar = cfg.frequency;
|
||||
Unit = "home-manager-auto-expire.service";
|
||||
Persistent = true;
|
||||
};
|
||||
})
|
||||
};
|
||||
services.home-manager-auto-expire = {
|
||||
Unit.Description = "Home Manager expire generations";
|
||||
Service.ExecStart = toString script;
|
||||
};
|
||||
};
|
||||
|
||||
(lib.mkIf pkgs.stdenv.isDarwin {
|
||||
assertions = [
|
||||
(lib.hm.darwin.assertInterval "services.home-manager.autoExpire.frequency" cfg.frequency pkgs)
|
||||
];
|
||||
assertions = [
|
||||
(lib.hm.darwin.assertInterval "services.home-manager.autoExpire.frequency" cfg.frequency pkgs)
|
||||
];
|
||||
|
||||
launchd.agents.home-manager-auto-expire = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [ (toString script) ];
|
||||
ProcessType = "Background";
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval cfg.frequency;
|
||||
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/home-manager-auto-expire/launchd-stdout.log";
|
||||
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/home-manager-auto-expire/launchd-stderr.log";
|
||||
};
|
||||
};
|
||||
})
|
||||
]
|
||||
);
|
||||
launchd.agents.home-manager-auto-expire = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [ (toString script) ];
|
||||
ProcessType = "Background";
|
||||
StartCalendarInterval = lib.hm.darwin.mkCalendarInterval cfg.frequency;
|
||||
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/home-manager-auto-expire/launchd-stdout.log";
|
||||
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/home-manager-auto-expire/launchd-stderr.log";
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user