Compare commits

...

80 commits

Author SHA1 Message Date
home-manager-ci[bot]
7eca7f7081 flake.lock: Update
Some checks are pending
/ triage (push) Waiting to run
GitHub Pages / publish (ubuntu-latest) (push) Waiting to run
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/c6245e83d836d0433170a16eb185cefe0572f8b8?narHash=sha256-G/WVghka6c4bAzMhTwT2vjLccg/awmHkdKSd2JrycLc%3D' (2025-12-18)
  → 'github:NixOS/nixpkgs/a6531044f6d0bef691ea18d4d4ce44d0daa6e816?narHash=sha256-3xY8CZ4rSnQ0NqGhMKAy5vgC%2B2IVK0NoVEzDoOh4DA4%3D' (2025-12-21)
2025-12-23 23:24:11 -06:00
Austin Horstman
20728df08f release/25.11: add darwin copy apps change
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-23 16:36:16 -06:00
Austin Horstman
af3c24de76 release/25.05: add git signing format change
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-23 16:36:16 -06:00
Austin Horstman
624c7e80fb release/23.05: add swaylock stateVersion change
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-23 16:36:16 -06:00
home-manager-ci[bot]
9c790e687e maintainers: update all-maintainers.nix
Automated update of the master maintainers list combining:
- Home Manager specific maintainers from modules/lib/maintainers.nix
- Nixpkgs maintainers referenced in Home Manager modules

**Added:** 0 maintainers
**Removed:** 0 maintainers
**Total:** 282 → 282 maintainers

Generated by: lib/python/generate-all-maintainers.py
2025-12-23 13:45:25 -06:00
Austin Horstman
527ad07e66 tests/radicle: stub radicle-node
Failing build is blocking CI, test only verifies generated config.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-22 01:11:39 -06:00
home-manager-ci[bot]
57a02fd7d9 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/1306659b587dc277866c7b69eb97e5f07864d8c4?narHash=sha256-KJ2wa/BLSrTqDjbfyNx70ov/HdgNBCBBSQP3BIzKnv4%3D' (2025-12-15)
  → 'github:NixOS/nixpkgs/c6245e83d836d0433170a16eb185cefe0572f8b8?narHash=sha256-G/WVghka6c4bAzMhTwT2vjLccg/awmHkdKSd2JrycLc%3D' (2025-12-18)
2025-12-22 01:11:39 -06:00
aleksana
3fe66908e0 television: fix keybindings 2025-12-21 23:41:33 -06:00
Austin Horstman
61fcc9de76 tests/neovim: add test to catch config eval
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-20 19:55:46 -06:00
Austin Horstman
7b73a6e98f neovim: fix eval
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-20 19:51:30 -06:00
Austin Horstman
4dc3c91c50 neovim: remove deprecated type coercion for extraXPackages
3 years old, no need to keep around.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-20 17:11:31 -06:00
Austin Horstman
a7d6bba358 neovim: remove old removal options
3-4 years old, no need to keep around.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-20 17:11:31 -06:00
Austin Horstman
bdb807dc28 neovim: modernize
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-20 17:11:31 -06:00
Austin Horstman
0a583021ea tests/neovim: add wrapper args test
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-20 17:11:31 -06:00
Austin Horstman
ab01ea24b2 neovim: add missing wrapper args
Add support for extraName, autowrapRuntimeDeps, waylandSupport, and
withPerl options in the neovim module. These options are passed to the
neovim wrapper to allow for more granular configuration.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-20 17:11:31 -06:00
Austin Horstman
c764a377a0 gemini-cli: fix settings example
Supposed to represent the settigns to pass in, not the generated json.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-20 17:11:06 -06:00
Austin Horstman
28b3622b80 tests/gemini-cli: verify defaultModel behavior
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-20 17:11:06 -06:00
Austin Horstman
c848303f1e gemini-cli: don't force GEMINI_MODEL
Default to null so user's can opt in to using this variable that will
override configurations.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-20 17:11:06 -06:00
Austin Horstman
bb35f07cc9 tests/claude-code: add rules tests
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-19 13:19:35 -06:00
Austin Horstman
9bf54edf10 claude-code: add rules support
Support the `rules` directory for modular memory files.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-19 13:19:35 -06:00
Benedikt Rips
89c9508bbe ssh-agent: set $SSH_AUTH_SOCK in non-interactive shells
Since PR #8099, the module sets `$SSH_AUTH_SOCK` through shells' options
for interactive shell initialization instead of
`home.sessionVariablesExtra`. The replacement was not faithful, however,
since `home.sessionVariablesExtra` is sourced also in non-interactive
shells. With this commit, the shells' profile options (where
`home.sessionVariablesExtra` is sourced) are used to set
`$SSH_AUTH_SOCK`.

Fixes #8129.
2025-12-17 08:15:55 -06:00
home-manager-ci[bot]
22202ff0d8 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/2fbfb1d73d239d2402a8fe03963e37aab15abe8b?narHash=sha256-9VvC20PJPsleGMewwcWYKGzDIyjckEz8uWmT0vCDYK0%3D' (2025-12-11)
  → 'github:NixOS/nixpkgs/1306659b587dc277866c7b69eb97e5f07864d8c4?narHash=sha256-KJ2wa/BLSrTqDjbfyNx70ov/HdgNBCBBSQP3BIzKnv4%3D' (2025-12-15)
2025-12-17 07:57:35 -06:00
Anton Mosich
09de9577d4
pimsync: add Install.WantedBy for default.target (#8344) 2025-12-15 22:40:45 -06:00
dependabot[bot]
f575cb24f6 ci: bump korthout/backport-action from 3 to 4
Bumps [korthout/backport-action](https://github.com/korthout/backport-action) from 3 to 4.
- [Release notes](https://github.com/korthout/backport-action/releases)
- [Commits](https://github.com/korthout/backport-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: korthout/backport-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 22:38:37 -06:00
DaRacci
3a92ffa192 home-manager: expose all attributes returned by evalModules
This change brings the homeConfigurations output inline with how the
nixosConfiguration output presents its attributes.

The primary purpose is for exposing the graph attribute however there is
no downside to exposing the rest along with it to prevent needing to add
each desired attribute individually in the future if more are added.
2025-12-15 22:36:33 -06:00
home-manager-ci[bot]
6cdf765eed flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/addf7cf5f383a3101ecfba091b98d0a1263dc9b8?narHash=sha256-hM20uyap1a0M9d344I692r%2Bik4gTMyj60cQWO%2BhAYP8%3D' (2025-12-08)
  → 'github:NixOS/nixpkgs/2fbfb1d73d239d2402a8fe03963e37aab15abe8b?narHash=sha256-9VvC20PJPsleGMewwcWYKGzDIyjckEz8uWmT0vCDYK0%3D' (2025-12-11)
2025-12-15 22:13:51 -06:00
home-manager-ci[bot]
8315c1544f maintainers: update all-maintainers.nix
Automated update of the master maintainers list combining:
- Home Manager specific maintainers from modules/lib/maintainers.nix
- Nixpkgs maintainers referenced in Home Manager modules

**Added:** 0 maintainers
**Removed:** 0 maintainers
**Total:** 282 → 282 maintainers

Generated by: lib/python/generate-all-maintainers.py
2025-12-15 19:32:11 +01:00
will
58bf3ecb2d modules/services/colima: init 2025-12-13 21:17:23 -06:00
Benedikt Rips
d787ec69c3 less: list options in correct order 2025-12-13 00:08:50 -06:00
Benedikt Rips
07d79726f1 less: enable options to be specified multiple times 2025-12-13 00:08:50 -06:00
Olmo Kramer
4767a9c719 herbstluftwm: Make herbstclient alias optional
The `herbstclient` alias in the generated `autostart` made it impossible
to use bash functions.

This makes the `herbstclient` alias optional by adding an extra
`herbstclientAlias` option on the herbstluftwm configuration. The new
option defaults to `false` as to not confuse newcomers to the
herbstluftwm module, which is not a breaking change because it was only
an optimization.
2025-12-12 23:53:36 -06:00
Austin Horstman
39cb677ed9 news: add defaultEditor entry
Let users know about new variable being set.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-11 13:12:54 -06:00
Jacob Abel
0cf525a5be
option defaultEditor: Set {env}VISUAL on true (#8322)
The defaultEditor option sets {env}`EDITOR` however strictly speaking
{env}`EDITOR` is intended for editors that are fully compatible with
teletype terminals (ex: `ed` or `vi`'s `ex` mode).

The {env}`VISUAL variable is intended for modern "visual mode"
terminal editors (ex: `vi` or `emacs`).

Technically speaking editors that are assigned to {env}`EDITOR` should
be configured to operate in teletype compatible mode (see `vi -e` and
`vim -e`).

We don't do this currently because for most users this would be
unintuitive behavior when a script or program mistakenly checks
{env}`EDITOR` instead of first checking {env}`VISUAL`.

In the future it may be worthwhile to introduce an additional option to
these modules to configure {env}`EDITOR` in a strictly conforming manner
(i.e. using the teletype/`ex` mode flags or unsetting {env}`EDITOR`
entirely).

Related Issue: #8314

Signed-off-by: Jacob Abel <jacobabel@nullpo.dev>
2025-12-11 13:04:13 -06:00
Mirko Lenz
9b5ac85d79 npm: add module 2025-12-11 12:58:36 -06:00
Austin Horstman
574f6d3526 hyprpanel: perchun -> PerchunPak
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-11 12:51:49 -06:00
Austin Horstman
e52be4fb78 tldr-update: perchun -> PerchunPak
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-11 12:51:49 -06:00
home-manager-ci[bot]
dd18018d06 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/f61125a668a320878494449750330ca58b78c557?narHash=sha256-BmPWzogsG2GsXZtlT%2BMTcAWeDK5hkbGRZTeZNW42fwA%3D' (2025-12-05)
  → 'github:NixOS/nixpkgs/addf7cf5f383a3101ecfba091b98d0a1263dc9b8?narHash=sha256-hM20uyap1a0M9d344I692r%2Bik4gTMyj60cQWO%2BhAYP8%3D' (2025-12-08)
2025-12-11 12:51:49 -06:00
Nick DeGroot
7b34e428f3 chromium: fix null package 2025-12-11 14:56:50 +01:00
Kyure_A
af7c726e8b sheldon: replace initExtra with initContent 2025-12-11 14:55:22 +01:00
fidgetingbits
13cc1efd78 snixembed: add waybar incompatbility warning
If snixembed is enabled and you try to use the waybar tray the two tools
conflict with eachother and often waybar's tray will not show any icons.
This adds a warning about it, as the problem can be difficult to
diagnose.
2025-12-09 21:27:32 -06:00
June Stepp
e5b1f87841 anki: enable tests on Darwin
Anki is no longer marked as broken in nixpkgs.
2025-12-08 12:16:00 -06:00
home-manager-ci[bot]
caa47b637d maintainers: update all-maintainers.nix
Automated update of the master maintainers list combining:
- Home Manager specific maintainers from modules/lib/maintainers.nix
- Nixpkgs maintainers referenced in Home Manager modules

**Added:** 1 maintainers
**Removed:** 0 maintainers
**Total:** 281 → 282 maintainers

** Added:** xavwe

Generated by: lib/python/generate-all-maintainers.py
2025-12-08 08:04:06 -06:00
Austin Horstman
a788734077 swayidle: fix events default
Changed from list to attrset, but default never updated.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-07 23:45:14 -06:00
Mirko Lenz
6bdf2a68e1 ty: add module 2025-12-07 23:30:36 -06:00
Viktor Titov
f9d45d664e
qt: added qt{5,6}ctSettings options (#8271)
Added qtctSettings option to qt module to make it possible to configure qt(5/6)ct declaratively.
2025-12-07 23:17:30 -06:00
home-manager-ci[bot]
082822b8a6 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/2d293cbfa5a793b4c50d17c05ef9e385b90edf6c?narHash=sha256-pp3uT4hHijIC8JUK5MEqeAWmParJrgBVzHLNfJDZxg4%3D' (2025-11-30)
  → 'github:NixOS/nixpkgs/f61125a668a320878494449750330ca58b78c557?narHash=sha256-BmPWzogsG2GsXZtlT%2BMTcAWeDK5hkbGRZTeZNW42fwA%3D' (2025-12-05)
2025-12-07 23:14:56 -06:00
Austin Horstman
27a6182347 tests/diff-highlight: add null assertion test
Verify eval when setting git package to null.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-05 23:18:20 -06:00
Austin Horstman
012cfcc44a diff-highlight: add git package assertion
Git package can be made nullable now, but module is written with
expectation of its availability.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-05 23:18:20 -06:00
Hanwen Guo
36817384a6 programs/git: package nullable
Some platforms (e.g. macOS) provide their customized version of git with
exclusive features, and user might want to use that instead.
2025-12-05 23:03:42 -06:00
Aguirre Matteo
571c5eed1d news: add hyprlauncher entry 2025-12-05 22:35:12 -06:00
Aguirre Matteo
2e02e22e28 hyprlauncher: add module 2025-12-05 22:35:12 -06:00
Aguirre Matteo
ccd22c13b2 restic: change cache directory to $XDG_CACHE_HOME/restic 2025-12-05 20:04:55 -06:00
Austin Horstman
519828bf1c claude-code: refactor wrapper to use append-flags
Alternative approach suggested in
https://github.com/nix-community/home-manager/pull/8290#discussion_r2593114782

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-05 10:42:15 -06:00
David
1a99a515a1 nixos/common: guard nix.package access when nix.enable is false
When nix-darwin has `nix.enable = false` (e.g., for Determinate Nix
users), accessing `config.nix.package` throws an error:

    error: nix.package: accessed when `nix.enable` is off

This regression was introduced in commit a521eab when adding the
`home.uid` option. The code restructuring changed `inherit (config.nix)
package` to be evaluated unconditionally, whereas PR #6383 had
previously ensured this worked correctly.

The fix wraps the package assignment in `mkIf config.nix.enable` to
only access `config.nix.package` when nix management is enabled in the
host OS configuration.

Fixes: #8303
2025-12-05 10:37:47 -06:00
Austin Horstman
6bcb2395ab home-environment: style cleanup
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-04 23:34:56 -06:00
Austin Horstman
f16bfa59e3 home-environment: fix undefined access eval
`uid` isn't guaranteed to be defined, have fallback logic in place to
account for that. Even if we require it eventually, we can't show a
proper assertion/warning without being able to eval.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-04 23:34:56 -06:00
Aguirre Matteo
35545f71dd news: add screen entry 2025-12-04 22:41:15 -06:00
Aguirre Matteo
6bbc48804b screen: add module 2025-12-04 22:41:15 -06:00
Jess
a8b6296a1e tests/restic: fix timedatectl failure
Systemd
[added a check](6a12c90ca3)
which broke this test. So use `date` instead of `timedatectl`.
2025-12-04 22:39:18 -06:00
Aguirre Matteo
68f7b34179 news: add calibre entry 2025-12-04 22:38:55 -06:00
Aguirre Matteo
24cc5c080c calibre: add module 2025-12-04 22:38:55 -06:00
Aguirre Matteo
df7bac2b2b rclone: change cache directory to $XDG_CACHE_HOME/rclone 2025-12-05 00:33:32 +01:00
Austin Horstman
05a56dbf24 claude-code: fix wrapper to inject --mcp-config after subcommands
Manually wrap program to maintain options called from cli.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-12-04 12:19:32 -06:00
Urocissa Caerulea.Tw
9379fbf4f5 Translate using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (39 of 39 strings)

Translate using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (17 of 17 strings)

Co-authored-by: Urocissa Caerulea.Tw <urocissa.tw@proton.me>
Translate-URL: https://hosted.weblate.org/projects/home-manager/cli/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/home-manager/modules/zh_Hant/
Translation: Home Manager/Home Manager CLI
Translation: Home Manager/Home Manager Modules
2025-12-04 10:33:19 -06:00
Bernardo Meurer
a521eab881 home-environment: add home.uid option
Add a home.uid option similar to home.username. When set, the
activation script verifies the current UID matches the expected
value using the new checkUid function.

When using the NixOS or nix-darwin modules, home.uid is
auto-discovered from users.users.<name>.uid when that value
is set.

This is useful for constructing paths that depend on the user's
UID, such as /run/user/<uid> paths for gpg-agent sockets or
other user-specific runtime directories.
2025-12-04 17:22:25 +01:00
tsrk.
d441981b20 thunderbird: fix aliases SMTP configuration not being listed as usable
Signed-off-by: tsrk. <tsrk@tsrk.me>
2025-12-04 10:16:29 +01:00
Xaver Wenhart
fca4cba863 parallel: package nullable 2025-12-03 12:58:50 -06:00
trash-panda-v91-beta
af324afa72 cargo: fix typo in tests
testing docker-cli instead of cargo in empty-config.nix
2025-12-03 10:43:50 -06:00
Bruno BELANYI
12e7786854 programs/ssh: use 'toList' 2025-12-03 09:48:51 -06:00
Bruno BELANYI
28741978a3 programs/ssh: use 'toKeyValue' for 'extraOptions'
A first step towards refactoring the module.

Unfortunately the config is not consistent in using comma-separated
values or repeated keys for lists, since the user can always add commas
by themselves, we should default to repeated keys in the generator.
2025-12-03 09:44:29 -06:00
Andrew Jeffery
43173abcb4 pimsync: Make storage names unique
This includes the calendar/contacts prefix in the storage name as well
as the pair name to ensure that if the same name is used for contacts
and calendar then it is correctly referenced.
2025-12-03 13:46:21 +01:00
home-manager-ci[bot]
bcc7afa1d8 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/2fad6eac6077f03fe109c4d4eb171cf96791faa4?narHash=sha256-sKoIWfnijJ0%2B9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI%3D' (2025-11-27)
  → 'github:NixOS/nixpkgs/2d293cbfa5a793b4c50d17c05ef9e385b90edf6c?narHash=sha256-pp3uT4hHijIC8JUK5MEqeAWmParJrgBVzHLNfJDZxg4%3D' (2025-11-30)
2025-12-02 22:41:07 -06:00
Patrick Steinhardt
281e9398cc swayidle: improve confusing "events" configuration
With swayidle one can configure two different kinds of hooks:

  - Idle timeouts are executed after the session has been idle for a
    specific amount of time.

  - Events are executed when systemd notifies us that for example the
    user session is locked or that the device is about to suspend.

While not obvious, there is a significant difference between how these
two kinds are configured: there can be several timeouts with separate
commands to be executed, but each event can only be specified once. If
an event is specified multiple times, then the last command wins.

This can be very easy to miss in swayidle's documentation. Furthermore,
because the config is a list of `{ event = "..."; command = "..."; }`
attrset, we double down on this confusion and make it seem like having
multiple handlers for an event was actually supported.

Fix this by converting from a list of "event" submodules to an attrset
where the key is the event name and the value is the command to be
executed. This makes it impossible to specify multiple commands for a
single event by accident.

If a user _does_ want to have multiple commands executed on any event
they can for example use `pkgs.writeShellScript` and manually chain the
commands in that script.
2025-12-02 22:24:56 -06:00
Aguirre Matteo
93d907a205 news: ludusavi's default backup path changed entry 2025-12-02 21:57:23 -06:00
Aguirre Matteo
eca5f967cd ludusavi: use config.xdg.stateHome instead of $XDG_STATE_HOME 2025-12-02 21:57:23 -06:00
Aguirre Matteo
db44f38047 ludusavi: add test 2025-12-02 21:57:23 -06:00
Mirko Lenz
06f81463bb infat: add module 2025-12-02 21:39:05 -06:00
Matt Sturgeon
ab8e4b2b5a home-environment: extend release check to include pkgs
`lib` comes from the Nixpkgs used to instantiate Home Manager itself and
cannot change within the module fixpoint. However, `pkgs` is configurable
(via `nixpkgs.*` or `_module.args`) and may come from a different Nixpkgs
instance from the one providing `lib`.

Mismatches between Home Manager's release and the release of the `pkgs`
instance are more common and also more likely to cause subtle issues.

This change extends the release check to include `pkgs.lib.trivial.release`
so that such mismatches can be detected and reported.
2025-12-02 21:35:34 -06:00
Anton Mosich
c3d1e5c65a pimsync: extend test to contacts
If I had added such a test right away, I would have encountered #8258
myself. I mistakenly believed the contact and calendar modules to be the
same.
2025-12-03 04:10:48 +01:00
Anton Mosich
bf003999ed accounts.contacts: fix eval error
You would encounter an eval error when a module (such as pimsync) would
try to access an attribute of `accounts.contacts.<name>.local`, since it
would default to `null`. The same problem was encountered in the
`accounts.calendar` module, and fixed in
2c157e22dcf2c08e38a95b557ba6785e882b8bc0 which has the same solution.

Closes #8258

Reported-by: redbeardymcgee
2025-12-03 04:10:48 +01:00
138 changed files with 2643 additions and 520 deletions

View file

@ -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 }}

View file

@ -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";
};
@ -2073,7 +2078,7 @@
source = "nixpkgs";
};
shikanime = {
email = "deva.shikanime@protonmail.com";
email = "william.phetsinorath@shikanime.studio";
github = "shikanime";
githubId = 22115108;
name = "William Phetsinorath";
@ -2311,6 +2316,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";

View file

@ -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.

View file

@ -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.

View file

@ -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.

6
flake.lock generated
View file

@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1764242076,
"narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=",
"lastModified": 1766309749,
"narHash": "sha256-3xY8CZ4rSnQ0NqGhMKAy5vgC+2IVK0NoVEzDoOh4DA4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2fad6eac6077f03fe109c4d4eb171cf96791faa4",
"rev": "a6531044f6d0bef691ea18d4d4ce44d0daa6e816",
"type": "github"
},
"original": {

View file

@ -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 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/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"

View file

@ -102,8 +102,8 @@ let
};
local = mkOption {
type = types.nullOr (localModule name);
default = null;
type = localModule name;
default = { };
description = ''
Local configuration for the contacts.
'';

View file

@ -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.

View file

@ -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 ''

View file

@ -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

View 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.
'';
}

View 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.
'';
}

View 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.
'';
}

View 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 its outstanding
and a must-have. Itll allow you to do nearly everything and it takes things a
step beyond normal e-book software. Its also completely free and open source
and great for both casual users and computer experts.
'';
}

View 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.
'';
}

View 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. Its fast, simple, and provides various modules.
'';
}

View 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.
'';
}

View 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.
'';
}

View 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`.
'';
}

View 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.
'';
}

View file

@ -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";
}
))
];
};
}

View file

@ -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"

View 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)
);
};
}

View file

@ -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

View file

@ -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" (

View file

@ -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 =

View file

@ -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;
};
};
}
{

View file

@ -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"

View file

@ -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

View file

@ -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 " ] ''

View 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
'';
};
};
};
}

View file

@ -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) {

View file

@ -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}
''
);
};

View file

@ -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 = "";
@ -315,37 +221,78 @@ in
'';
};
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 +322,7 @@ in
filetypes = [ "haskell" "lhaskell" ];
};
};
};
}
'';
description = ''
Extra configuration lines to add to
@ -392,11 +339,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,11 +400,38 @@ in
suppressNotVimlConfig = p: if p.type != "viml" then p // { config = null; } else p;
# 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)
];
neovimConfig = pkgs.neovimUtils.makeNeovimConfig {
inherit (cfg)
extraPython3Packages
withPython3
withRuby
withPerl
viAlias
vimAlias
;
@ -428,54 +443,63 @@ in
wrappedNeovim' = pkgs.wrapNeovimUnstable cfg.package (
neovimConfig
// {
inherit (cfg)
extraName
autowrapRuntimeDeps
waylandSupport
withNodeJs
;
wrapperArgs =
(lib.escapeShellArgs (neovimConfig.wrapperArgs ++ cfg.extraWrapperArgs))
+ " "
+ extraMakeWrapperArgs
+ " "
+ extraMakeWrapperLuaCArgs
+ " "
+ extraMakeWrapperLuaArgs;
neovimConfig.wrapperArgs
++ cfg.extraWrapperArgs
++ extraMakeWrapperArgs
++ extraMakeWrapperLuaCArgs
++ extraMakeWrapperLuaArgs;
wrapRc = false;
}
);
in
mkIf cfg.enable {
{
programs.neovim = {
generatedConfigViml = neovimConfig.neovimRcContent;
programs.neovim.generatedConfigViml = neovimConfig.neovimRcContent;
generatedConfigs =
let
grouped = builtins.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;
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;
finalPackage = wrappedNeovim';
};
home.packages = [ cfg.finalPackage ];
home = {
packages = [ cfg.finalPackage ];
home.sessionVariables = mkIf cfg.defaultEditor { EDITOR = "nvim"; };
sessionVariables = mkIf cfg.defaultEditor {
EDITOR = "nvim";
VISUAL = "nvim";
};
home.shellAliases = mkIf cfg.vimdiffAlias { vimdiff = "nvim -d"; };
shellAliases = mkIf cfg.vimdiffAlias { vimdiff = "nvim -d"; };
};
xdg.configFile =
let
hasLuaConfig = lib.hasAttr "lua" config.programs.neovim.generatedConfigs;
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
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/init.lua" = mkIf (luaRcContent != "") { text = luaRcContent; };
"nvim/coc-settings.json" = mkIf cfg.coc.enable {
source = jsonFormat.generate "coc-settings.json" cfg.coc.settings;
@ -483,7 +507,6 @@ in
}
]
);
programs.neovim.finalPackage = wrappedNeovim';
};
}
);
}

74
modules/programs/npm.nix Normal file
View 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}";
};
};
};
}

View file

@ -20,7 +20,7 @@ in
options.programs.parallel = {
enable = mkEnableOption "GNU Parallel";
package = lib.mkPackageOption pkgs "parallel-full" { };
package = lib.mkPackageOption pkgs "parallel-full" { nullable = true; };
will-cite = mkOption {
type = types.bool;
@ -33,7 +33,7 @@ in
config = mkIf cfg.enable {
home = {
packages = [ cfg.package ];
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)";
};

View file

@ -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;
};

View file

@ -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

View 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;
};
};
}

View file

@ -52,7 +52,7 @@ in
eval "$(sheldon source)"
'';
programs.zsh.initExtra = mkIf cfg.enableZshIntegration ''
programs.zsh.initContent = mkIf cfg.enableZshIntegration ''
eval "$(sheldon source)"
'';

View file

@ -151,14 +151,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 +161,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 +251,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.
'';
@ -451,7 +430,13 @@ 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
++ [
(lib.generators.toKeyValue {
mkKeyValue = lib.generators.mkKeyValueDefault { } " ";
listsAsDuplicateKeys = true;
indent = " ";
} cf.extraOptions)
]
);
in

View file

@ -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
'';
};
}

View file

@ -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
View 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;
};
};
}

View file

@ -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;

266
modules/services/colima.nix Normal file
View file

@ -0,0 +1,266 @@
{
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.mkIf pkgs.stdenv.isDarwin (
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.mkIf pkgs.stdenv.isLinux (
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)
);
});
}

View file

@ -113,7 +113,8 @@ in
example = !default;
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.
'';
};
};
@ -121,11 +122,16 @@ in
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}"''
);
};
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;
};
}
(mkIf pkgs.stdenv.isLinux {

View file

@ -0,0 +1,86 @@
{
lib,
pkgs,
config,
...
}:
let
inherit (lib)
mkIf
mkEnableOption
mkPackageOption
mkOption
;
cfg = config.services.hyprlauncher;
in
{
meta.maintainers = with lib.hm.maintainers; [ aguirre-matteo ];
options.services.hyprlauncher = {
enable = mkEnableOption "hyprlauncher";
package = mkPackageOption pkgs "hyprlauncher" { nullable = true; };
settings = mkOption {
type =
with lib.types;
let
valueType =
nullOr (oneOf [
bool
int
float
str
path
(attrsOf valueType)
(listOf valueType)
])
// {
description = "Hyprland configuration value";
};
in
valueType;
default = { };
example = {
general.grab_focus = true;
cache.enabled = true;
ui.window_size = "400 260";
finders = {
math_prefix = "=";
desktop_icons = true;
};
};
description = ''
Configuration settings for hyprlauncher. All the available options can be found here:
<https://wiki.hypr.land/Hypr-Ecosystem/hyprlauncher/#config>
'';
};
};
config = mkIf cfg.enable {
assertions = [
(lib.hm.assertions.assertPlatform "services.hyprlauncher" pkgs lib.platforms.linux)
];
home.packages = mkIf (cfg.package != null) [ cfg.package ];
xdg.configFile."hypr/hyprlauncher.conf" = mkIf (cfg.settings != { }) {
text = lib.hm.generators.toHyprconf { attrs = cfg.settings; };
};
systemd.user.services.hyprlauncher = mkIf (cfg.package != null) {
Install.WantedBy = [ config.wayland.systemd.target ];
Unit = {
Description = "hyprlauncher";
After = [ config.wayland.systemd.target ];
PartOf = [ config.wayland.systemd.target ];
X-Restart-Triggers = lib.mkIf (cfg.settings != { }) [
"${config.xdg.configFile."hypr/hyprlauncher.conf".source}"
];
};
Service = {
ExecStart = "${lib.getExe cfg.package} -d";
Restart = "always";
RestartSec = "10";
};
};
};
}

View file

@ -49,9 +49,17 @@ in
default = {
manifest.url = "https://raw.githubusercontent.com/mtkennerly/ludusavi-manifest/master/data/manifest.yaml";
roots = [ ];
backup.path = "$XDG_STATE_HOME/backups/ludusavi";
restore.path = "$XDG_STATE_HOME/backups/ludusavi";
backup.path = "${config.xdg.stateHome}/backups/ludusavi";
restore.path = "${config.xdg.stateHome}/backups/ludusavi";
};
defaultText = ''
{
manifest.url = "https://raw.githubusercontent.com/mtkennerly/ludusavi-manifest/master/data/manifest.yaml";
roots = [ ];
backup.path = "$XDG_STATE_HOME/backups/ludusavi";
restore.path = "$XDG_STATE_HOME/backups/ludusavi";
}
'';
example = {
language = "en-US";
theme = "light";
@ -94,6 +102,24 @@ in
Service = {
Type = "oneshot";
ExecStart = "${lib.getExe cfg.package} backup --force";
ExecStartPre = "${pkgs.writeShellScript "ludusavi-migrate-backup" ''
old_base_dir="${config.home.homeDirectory}/\$XDG_STATE_HOME"
old_dir="$old_base_dir/backups/ludusavi"
new_base_dir="${config.xdg.stateHome}/backups"
new_dir="$new_base_dir/ludusavi"
if [[ -d "$old_base_dir" ]]; then
echo "Migrating old Ludusavi's backup... (See home-manager/#8234)"
if [[ ! -d "$new_base_dir" ]]; then
mkdir -p "$new_base_dir"
fi
mv "$old_dir" "$new_dir"
rmdir "$old_base_dir/backups"
rmdir "$old_base_dir"
echo "Migration completed successfully."
fi
''}";
}
// lib.optionalAttrs cfg.backupNotification {
ExecStartPost = "${lib.getExe pkgs.libnotify} 'Ludusavi' 'Backup completed' -i com.mtkennerly.ludusavi -a 'Ludusavi'";

View file

@ -43,6 +43,7 @@ in
Description = "pimsync calendar and contacts synchronization";
PartOf = [ "network-online.target" ];
};
Install.WantedBy = [ "default.target" ];
Service = {
# TODO: make use of the readiness notification
Type = "simple";

View file

@ -475,7 +475,7 @@ in
CacheDirectoryMode = "0700";
PrivateTmp = true;
Environment = mkEnvironment backup ++ [ "RESTIC_CACHE_DIR=%C" ];
Environment = mkEnvironment backup ++ [ "RESTIC_CACHE_DIR=%C/${serviceName}" ];
ExecStart =
lib.optional doBackup backupCmd
@ -591,7 +591,7 @@ in
lib.concatLines
]}
RESTIC_CACHE_DIR=$HOME/.cache/${serviceName}
RESTIC_CACHE_DIR=${config.xdg.cacheHome}/${serviceName}
PATH=${
lib.pipe environment [

View file

@ -7,6 +7,7 @@
let
cfg = config.services.snixembed;
waybarCfg = config.programs.waybar;
in
{
meta.maintainers = [ lib.maintainers.DamienCassou ];
@ -32,6 +33,10 @@ in
assertions = [
(lib.hm.assertions.assertPlatform "services.snixembed" pkgs lib.platforms.linux)
];
warnings = lib.optional waybarCfg.enable ''
snixembed and waybar should not be enabled at the same time.
You may experience inconsistent tray behavior as a result.
'';
systemd.user.services.snixembed = {
Install.WantedBy = [ "graphical-session.target" ];

View file

@ -84,13 +84,11 @@ in
'';
in
{
bash.initExtra = lib.mkIf cfg.enableBashIntegration bashIntegration;
zsh.initContent = lib.mkIf cfg.enableZshIntegration bashIntegration;
fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration fishIntegration;
nushell.extraConfig = lib.mkIf cfg.enableNushellIntegration nushellIntegration;
# $SSH_AUTH_SOCK has to be set early since other tools rely on it
bash.profileExtra = lib.mkIf cfg.enableBashIntegration (lib.mkOrder 900 bashIntegration);
fish.shellInit = lib.mkIf cfg.enableFishIntegration (lib.mkOrder 900 fishIntegration);
nushell.extraConfig = lib.mkIf cfg.enableNushellIntegration (lib.mkOrder 900 nushellIntegration);
zsh.envExtra = lib.mkIf cfg.enableZshIntegration (lib.mkOrder 900 bashIntegration);
};
}

View file

@ -42,21 +42,30 @@ in
};
};
eventModule = {
eventsModule = {
options = {
event = mkOption {
type = types.enum [
"before-sleep"
"after-resume"
"lock"
"unlock"
];
description = "Event name.";
before-sleep = mkOption {
type = types.nullOr types.str;
default = null;
description = "Command to run before suspending.";
};
command = mkOption {
type = types.str;
description = "Command to run when event occurs.";
after-resume = mkOption {
type = types.nullOr types.str;
default = null;
description = "Command to run after resuming.";
};
lock = mkOption {
type = types.nullOr types.str;
default = null;
description = "Command to run when the logind session is locked.";
};
unlock = mkOption {
type = types.nullOr types.str;
default = null;
description = "Command to run when the logind session is unlocked.";
};
};
};
@ -80,13 +89,31 @@ in
};
events = mkOption {
type = with types; listOf (submodule eventModule);
default = [ ];
type =
with types;
(coercedTo (listOf attrs)) (
events:
lib.warn
''
The syntax of services.swayidle.events has changed. While it
previously accepted a list of events, it now accepts an attrset
keyed by the event name.
''
(
lib.listToAttrs (
map (e: {
name = e.event;
value = e.command;
}) events
)
)
) (submodule eventsModule);
default = { };
example = literalExpression ''
[
{ event = "before-sleep"; command = "''${pkgs.swaylock}/bin/swaylock -fF"; }
{ event = "lock"; command = "lock"; }
]
{
"before-sleep" = "''${pkgs.swaylock}/bin/swaylock -fF";
"lock" = "lock";
}
'';
description = "Run command on occurrence of a event.";
};
@ -144,13 +171,17 @@ in
t.resumeCommand
];
mkEvent = e: [
e.event
e.command
mkEvent = event: command: [
event
command
];
nonemptyEvents = lib.filterAttrs (event: command: command != null) cfg.events;
args =
cfg.extraArgs ++ (lib.concatMap mkTimeout cfg.timeouts) ++ (lib.concatMap mkEvent cfg.events);
cfg.extraArgs
++ (lib.concatMap mkTimeout cfg.timeouts)
++ (lib.flatten (lib.mapAttrsToList mkEvent nonemptyEvents));
in
"${lib.getExe cfg.package} ${lib.escapeShellArgs args}";
};

View file

@ -8,7 +8,7 @@ let
cfg = config.services.tldr-update;
in
{
meta.maintainers = [ lib.maintainers.perchun ];
meta.maintainers = [ lib.maintainers.PerchunPak ];
options.services.tldr-update = {
enable = lib.mkEnableOption ''

View file

@ -119,6 +119,24 @@ in
{file}`$XDG_CONFIG_HOME/herbstluftwm/autostart`.
'';
};
enableAlias = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Set an alias for the {command}`herbstclient` command in the
{file}`autostart` script that only stores its arguments and executes
them all at once at the end of the {file}`autostart` script.
This reduces the amount of flickering you get while all options are
being applied and improves the performance.
On the other hand, this makes it more difficult to write bash functions
that call {command}`herbstclient`. You can work around this by calling
{command}`command herbstclient` in your functions to still get some of
the benefits of enabling this alias.
'';
};
};
config = lib.mkIf cfg.enable {
@ -131,11 +149,13 @@ in
xsession.windowManager.command = "${cfg.package}/bin/herbstluftwm --locked";
xdg.configFile."herbstluftwm/autostart".source = pkgs.writeShellScript "herbstluftwm-autostart" ''
shopt -s expand_aliases
${lib.optionalString cfg.enableAlias ''
shopt -s expand_aliases
# shellcheck disable=SC2142
alias herbstclient='set -- "$@" ";"'
set --
# shellcheck disable=SC2142
alias herbstclient='set -- "$@" ";"'
set --
''}
herbstclient emit_hook reload
@ -169,7 +189,9 @@ in
herbstclient unlock
${cfg.package}/bin/herbstclient chain ";" "$@"
${lib.optionalString cfg.enableAlias ''
${cfg.package}/bin/herbstclient chain ";" "$@"
''}
'';
};
}

View file

@ -2,7 +2,6 @@
# For OS-specific configuration, please edit nixos/default.nix or nix-darwin/default.nix instead.
{
options,
config,
lib,
pkgs,
@ -36,7 +35,7 @@ let
modules = [
(
{ name, ... }:
{ name, options, ... }:
{
imports =
import ../modules/modules.nix {
@ -48,22 +47,31 @@ let
++ cfg.sharedModules;
config = {
submoduleSupport.enable = true;
submoduleSupport.externalPackageInstall = cfg.useUserPackages;
submoduleSupport = {
enable = true;
externalPackageInstall = cfg.useUserPackages;
};
home.username = config.users.users.${name}.name;
home.homeDirectory = config.users.users.${name}.home;
home = {
username = config.users.users.${name}.name;
homeDirectory = config.users.users.${name}.home;
uid = mkIf (options.users.users.${name}.uid.isDefined or false) config.users.users.${name}.uid;
};
# Forward `nix.enable` from the OS configuration. The
# conditional is to check whether nix-darwin is new enough
# to have the `nix.enable` option; it was previously a
# `mkRemovedOptionModule` error, which we can crudely detect
# by `visible` being set to `false`.
nix.enable = mkIf (options.nix.enable.visible or true) config.nix.enable;
nix = {
# Forward `nix.enable` from the OS configuration. The
# conditional is to check whether nix-darwin is new enough
# to have the `nix.enable` option; it was previously a
# `mkRemovedOptionModule` error, which we can crudely detect
# by `visible` being set to `false`.
enable = mkIf (options.nix.enable.visible or true) config.nix.enable;
# Make activation script use same version of Nix as system as a whole.
# This avoids problems with Nix not being in PATH.
nix.package = config.nix.package;
# Make activation script use same version of Nix as system as a whole.
# This avoids problems with Nix not being in PATH.
# Only set package when nix is enabled to avoid errors when
# nix-darwin has nix.enable = false (e.g., Determinate Nix users).
package = mkIf config.nix.enable config.nix.package;
};
};
}
)
@ -160,30 +168,28 @@ in
};
};
config = (
lib.mkMerge [
# Fix potential recursion when configuring home-manager users based on values in users.users #594
(mkIf (cfg.useUserPackages && cfg.users != { }) {
users.users = (lib.mapAttrs (_username: usercfg: { packages = [ usercfg.home.path ]; }) cfg.users);
environment.pathsToLink = [ "/etc/profile.d" ];
})
(mkIf (cfg.users != { }) {
warnings = lib.flatten (
flip lib.mapAttrsToList cfg.users (
user: config: flip map config.warnings (warning: "${user} profile: ${warning}")
)
);
config = lib.mkMerge [
# Fix potential recursion when configuring home-manager users based on values in users.users #594
(mkIf (cfg.useUserPackages && cfg.users != { }) {
users.users = lib.mapAttrs (_username: usercfg: { packages = [ usercfg.home.path ]; }) cfg.users;
environment.pathsToLink = [ "/etc/profile.d" ];
})
(mkIf (cfg.users != { }) {
warnings = lib.flatten (
flip lib.mapAttrsToList cfg.users (
user: config: flip map config.warnings (warning: "${user} profile: ${warning}")
)
);
assertions = lib.flatten (
flip lib.mapAttrsToList cfg.users (
user: config:
flip map config.assertions (assertion: {
inherit (assertion) assertion;
message = "${user} profile: ${assertion.message}";
})
)
);
})
]
);
assertions = lib.flatten (
flip lib.mapAttrsToList cfg.users (
user: config:
flip map config.assertions (assertion: {
inherit (assertion) assertion;
message = "${user} profile: ${assertion.message}";
})
)
);
})
];
}

View file

@ -27,6 +27,7 @@ let
"broot"
"browserpass"
"btop"
"calibre"
"carapace"
"cava"
"claude-code"
@ -96,6 +97,7 @@ let
"lf"
"lieer"
"lsd"
"ludusavi"
"mbsync"
"meli"
"mergiraf"

View file

@ -216,7 +216,7 @@ in
def make_backup(time):
global snapshot_count
machine.succeed(f"timedatectl set-time '{time}'")
machine.succeed(f"date --set='{time}'")
systemctl_succeed_as_alice("start restic-backups-prune-me.service")
snapshot_count += 1
actual = \

View file

@ -2,4 +2,7 @@
home-session-path = ./session-path.nix;
home-session-search-variables = ./session-search-variables.nix;
home-session-variables = ./session-variables.nix;
home-nixpkgs-release-check-pkgs = ./nixpkgs-release-check-pkgs.nix;
home-uid = ./uid.nix;
home-uid-null = ./uid-null.nix;
}

View file

@ -0,0 +1,39 @@
{ lib, ... }:
let
releaseInfo = lib.importJSON ../../../release.json;
hmRelease = releaseInfo.release;
pkgsRelease = "<invalid>";
in
{
test.asserts.warnings.expected = [
''
You are using
Home Manager version: ${hmRelease}
Nixpkgs version used to evaluate Home Manager: ${hmRelease}
Nixpkgs version used for packages (`pkgs`): ${pkgsRelease}
Using mismatched versions is likely to cause errors and unexpected
behavior. It is therefore highly recommended to use a release of Home
Manager that corresponds with your chosen release of Nixpkgs.
If you insist then you can disable this warning by adding
home.enableNixpkgsReleaseCheck = false;
to your configuration.
''
];
nixpkgs.overlays = [
(final: prev: {
lib = prev.lib.extend (
final: prev: {
trivial = prev.trivial // {
release = pkgsRelease;
};
}
);
})
];
}

View file

@ -0,0 +1,7 @@
{
# home.uid defaults to null, so checkUid should not be called in the activation script
nmt.script = ''
assertFileNotRegex activate "checkUid [0-9]+"
'';
}

View file

@ -0,0 +1,7 @@
{
home.uid = 1000;
nmt.script = ''
assertFileContains activate "checkUid 1000"
'';
}

View file

@ -4,4 +4,7 @@
qt-platform-theme-gtk3 = ./qt-platform-theme-gtk3.nix;
qt-platform-theme-gnome = ./qt-platform-theme-gnome.nix;
qt-platform-theme-kde6-migration = ./qt-platform-theme-kde6-migration.nix;
qt-qt5ct-settings = ./qt-qt5ct-settings.nix;
qt-qt6ct-settings = ./qt-qt6ct-settings.nix;
qt-qtct-settings = ./qt-qtct-settings.nix;
}

View file

@ -0,0 +1,13 @@
{
qt = {
enable = true;
qt5ctSettings = {
test_section.test_option = "test";
};
};
nmt.script = ''
assertFileExists "home-files/.config/qt5ct/qt5ct.conf"
assertPathNotExists "home-files/.config/qt6ct/qt6ct.conf"
'';
}

View file

@ -0,0 +1,13 @@
{
qt = {
enable = true;
qt6ctSettings = {
test_section.test_option = "test";
};
};
nmt.script = ''
assertFileExists "home-files/.config/qt6ct/qt6ct.conf"
assertPathNotExists "home-files/.config/qt5ct/qt5ct.conf"
'';
}

View file

@ -0,0 +1,16 @@
{
qt = {
enable = true;
qt5ctSettings = {
test_section.test_option = "test";
};
qt6ctSettings = {
test_section.test_option = "test";
};
};
nmt.script = ''
assertFileExists "home-files/.config/qt5ct/qt5ct.conf"
assertFileExists "home-files/.config/qt6ct/qt6ct.conf"
'';
}

View file

@ -1,7 +1,4 @@
{ lib, pkgs, ... }:
# Anki is currently marked as broken on Darwin (2025/06/23)
lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
{
anki-minimal-config = ./minimal-config.nix;
anki-full-config = ./full-config.nix;
}

View file

@ -0,0 +1 @@
{ calibre-settings = ./settings.nix; }

View file

@ -0,0 +1,14 @@
{
programs.calibre = {
enable = true;
plugins = [
./plugins/a
./plugins/b
];
};
nmt.script = ''
assertFileExists home-files/.config/calibre/plugins/a.zip
assertFileExists home-files/.config/calibre/plugins/b.zip
'';
}

View file

@ -1,5 +1,5 @@
{
programs.docker-cli = {
programs.cargo = {
settings = {
net = {
git-fetch-with-cli = true;

View file

@ -5,6 +5,8 @@
claude-code-assertion = ./assertion.nix;
claude-code-memory-management = ./memory-management.nix;
claude-code-memory-from-source = ./memory-from-source.nix;
claude-code-rules-dir = ./rules-dir.nix;
claude-code-rules-path = ./rules-path.nix;
claude-code-agents-dir = ./agents-dir.nix;
claude-code-commands-dir = ./commands-dir.nix;
claude-code-hooks-dir = ./hooks-dir.nix;

View file

@ -1,2 +1,2 @@
#! /nix/store/00000000000000000000000000000000-bash/bin/bash -e
exec -a "$0" "/nix/store/00000000000000000000000000000000-claude-code/bin/.claude-wrapped" --mcp-config /nix/store/00000000000000000000000000000000-claude-code-mcp-config.json "$@"
exec -a "$0" "/nix/store/00000000000000000000000000000000-claude-code/bin/.claude-wrapped" "$@" --mcp-config /nix/store/00000000000000000000000000000000-claude-code-mcp-config.json

View file

@ -0,0 +1,14 @@
{
programs.claude-code = {
enable = true;
rulesDir = ./rules;
};
nmt.script = ''
assertFileExists home-files/.claude/rules/test-rule.md
assertLinkExists home-files/.claude/rules/test-rule.md
assertFileContent \
home-files/.claude/rules/test-rule.md \
${./rules/test-rule.md}
'';
}

View file

@ -0,0 +1,20 @@
{
programs.claude-code = {
enable = true;
rules = {
test-rule = ./test-rule.md;
inline-rule = ''
# Inline Rule
This is an inline rule for testing.
'';
};
};
nmt.script = ''
assertFileExists home-files/.claude/rules/test-rule.md
assertFileContent home-files/.claude/rules/test-rule.md \
${./test-rule.md}
assertFileExists home-files/.claude/rules/inline-rule.md
'';
}

View file

@ -0,0 +1,9 @@
# Test Rule from Directory
This is a test rule loaded from a directory.
Used to verify rulesDir support functionality.
## Best Practices
- Write clean code
- Test thoroughly

View file

@ -0,0 +1,9 @@
# Test Rule
This is a test rule loaded from a file path.
Used to verify path support functionality for rules.
## Guidelines
- Follow test conventions
- Maintain code quality

View file

@ -2,4 +2,5 @@
diff-highlight-basic = ./diff-highlight-basic.nix;
diff-highlight-with-git-integration = ./diff-highlight-with-git-integration.nix;
diff-highlight-migration = ./diff-highlight-migration.nix;
diff-highlight-git-package-null-assertion = ./diff-highlight-git-package-null-assertion.nix;
}

View file

@ -0,0 +1,18 @@
{
programs.diff-highlight = {
enable = true;
enableGitIntegration = true;
};
programs.git = {
enable = true;
package = null;
};
test.asserts.assertions.expected = [
''
programs.diff-highlight.enableGitIntegration requires programs.git.package to be set.
Please set programs.git.package to a valid git package.
''
];
}

View file

@ -41,5 +41,9 @@
assertFileExists home-files/.gemini/CONTEXT.md
assertFileContent home-files/.gemini/CONTEXT.md \
${./context-additional.md}
assertFileExists home-path/etc/profile.d/hm-session-vars.sh
assertFileNotRegex home-path/etc/profile.d/hm-session-vars.sh \
"GEMINI_MODEL"
'';
}

View file

@ -1,6 +1,7 @@
{
programs.gemini-cli = {
enable = true;
defaultModel = "gemini-2.5-flash";
settings = {
theme = "Default";
vimMode = true;
@ -28,5 +29,9 @@
${./changelog.toml}
assertFileContent home-files/.gemini/commands/git/fix.toml \
${./fix.toml}
assertFileExists home-path/etc/profile.d/hm-session-vars.sh
assertFileContains home-path/etc/profile.d/hm-session-vars.sh \
'export GEMINI_MODEL="gemini-2.5-flash"'
'';
}

View file

@ -0,0 +1,6 @@
{ lib, pkgs, ... }:
lib.optionalAttrs pkgs.stdenv.hostPlatform.isDarwin {
infat-example-settings = ./example-settings.nix;
infat-no-settings = ./no-settings.nix;
}

View file

@ -0,0 +1,39 @@
{ pkgs, ... }:
{
programs.infat = {
enable = true;
settings = {
extensions = {
md = "TextEdit";
};
schemes = {
web = "Safari";
};
types = {
plain-text = "VSCode";
};
};
};
test.stubs.infat = { };
nmt.script =
let
expectedConfigPath = "home-files/.config/infat/config.toml";
expectedConfigContent = pkgs.writeText "infat.config.expected" ''
[extensions]
md = "TextEdit"
[schemes]
web = "Safari"
[types]
plain-text = "VSCode"
'';
in
''
assertFileExists "${expectedConfigPath}"
assertFileContent "${expectedConfigPath}" "${expectedConfigContent}"
'';
}

View file

@ -0,0 +1,13 @@
{
programs.infat.enable = true;
test.stubs.infat = { };
nmt.script =
let
expectedConfigPath = "home-files/.config/infat/config.toml";
in
''
assertPathNotExists "${expectedConfigPath}"
'';
}

View file

@ -0,0 +1,30 @@
{ lib, ... }:
{
programs.less = {
enable = true;
options = lib.mkMerge [
{
quiet = true;
use-color = true;
}
(lib.mkAfter {
color = [
"HkK" # header: gray
"Mkb" # marks: blue
];
})
(lib.mkOrder 2000 {
prompt = "s%f";
})
];
};
nmt.script = ''
assertFileExists home-files/.config/lesskey
assertFileContent home-files/.config/lesskey ${builtins.toFile "lesskey.expected" ''
#env
LESS = --quiet --use-color --color HkK --color Mkb --prompt s%f
''}
'';
}

View file

@ -12,7 +12,10 @@ in
options = {
RAW-CONTROL-CHARS = true;
quiet = true;
wheel-lines = 3;
wheel-lines = [
3
1
];
};
};
@ -20,7 +23,7 @@ in
assertFileExists home-files/.config/lesskey
assertFileContent home-files/.config/lesskey ${builtins.toFile "less.expected" ''
#env
LESS = --RAW-CONTROL-CHARS --quiet --wheel-lines 3
LESS = --RAW-CONTROL-CHARS --quiet --wheel-lines 3 --wheel-lines 1
${config}''}
'';

View file

@ -4,7 +4,10 @@
options = {
RAW-CONTROL-CHARS = true;
quiet = true;
wheel-lines = 3;
wheel-lines = [
3
1
];
};
};
@ -12,7 +15,7 @@
assertFileExists home-files/.config/lesskey
assertFileContent home-files/.config/lesskey ${builtins.toFile "lesskey.expected" ''
#env
LESS = --RAW-CONTROL-CHARS --quiet --wheel-lines 3
LESS = --RAW-CONTROL-CHARS --quiet --wheel-lines 3 --wheel-lines 1
''}
'';
}

View file

@ -1,4 +1,5 @@
{
less-correct-option-order = ./correct-option-order.nix;
less-custom-config = ./custom-config.nix;
less-custom-options = ./custom-options.nix;
less-custom-options-and-config = ./custom-options-and-config.nix;

View file

@ -2,6 +2,7 @@
neovim-plugin-config = ./plugin-config.nix;
neovim-coc-config = ./coc-config.nix;
neovim-runtime = ./runtime.nix;
neovim-wrapper-args = ./wrapper-args.nix;
# waiting for a nixpkgs patch
neovim-no-init = ./no-init.nix;

View file

@ -34,15 +34,25 @@ lib.mkIf config.test.enableBig {
_module.args.pkgs = lib.mkForce realPkgs;
nmt.script = ''
vimout=$(mktemp)
echo "redir >> /dev/stdout | echo g:hmExtraConfig | echo g:hmPlugins | redir END" \
| ${pkgs.neovim}/bin/nvim -es -u "$TESTED/home-files/.config/nvim/init.lua" \
> "$vimout" || true
assertFileContains "$vimout" "HM_EXTRA_CONFIG"
assertFileContains "$vimout" "HM_PLUGINS_CONFIG"
nmt.script =
let
# Force evaluation of generatedConfigs.
luaConfig = config.programs.neovim.generatedConfigs.lua;
vimlConfig = config.programs.neovim.generatedConfigs.viml;
in
''
vimout=$(mktemp)
echo "redir >> /dev/stdout | echo g:hmExtraConfig | echo g:hmPlugins | redir END" \
| ${pkgs.neovim}/bin/nvim -es -u "$TESTED/home-files/.config/nvim/init.lua" \
> "$vimout" || true
assertFileContains "$vimout" "HM_EXTRA_CONFIG"
assertFileContains "$vimout" "HM_PLUGINS_CONFIG"
initLua="$TESTED/home-files/.config/nvim/init.lua"
assertFileContent $(normalizeStorePaths "$initLua") ${./plugin-config.expected}
'';
initLua="$TESTED/home-files/.config/nvim/init.lua"
assertFileContent $(normalizeStorePaths "$initLua") ${./plugin-config.expected}
# Verify generatedConfigs evaluated properly (issue #8371)
echo "Lua config length: ${toString (builtins.stringLength luaConfig)}"
echo "Viml config length: ${toString (builtins.stringLength vimlConfig)}"
'';
}

View file

@ -0,0 +1,83 @@
{
lib,
pkgs,
...
}:
let
inherit (pkgs.stdenv.hostPlatform) isLinux;
dummyDep = pkgs.runCommand "dummy-dep" { } ''
mkdir -p $out/bin
echo "echo dummy" > $out/bin/dummy-dep-bin
chmod +x $out/bin/dummy-dep-bin
'';
dummyPlugin = pkgs.vimUtils.buildVimPlugin {
pname = "dummy-plugin";
version = "1.0";
src = pkgs.writeTextDir "plugin/dummy.vim" "\" dummy";
runtimeDeps = [ dummyDep ];
};
in
{
imports = [ ./stubs.nix ];
tests.stubs.wl-clipboard = { };
programs.neovim = {
enable = true;
extraName = "-my-suffix";
withPerl = true;
withPython3 = true;
withRuby = true;
withNodeJs = true;
autowrapRuntimeDeps = true;
waylandSupport = isLinux;
plugins = [ dummyPlugin ];
};
nmt.script = ''
nvimBin="home-path/bin/nvim"
assertBinaryContains() {
local file="$TESTED/$1"
if [[ $1 == /* ]]; then file="$1"; fi
if ! grep -a -qF -- "$2" "$file"; then
fail "Expected binary file '$1' to contain '$2' but it did not."
fi
}
# Ensure the main binary exists
assertFileExists "$nvimBin"
# 1. extraName: Check if the suffix is in the rplugin manifest path within the wrapper
assertBinaryContains "$nvimBin" "-my-suffix/rplugin.vim"
# 2. withPerl: Check if nvim-perl binary exists and host prog is set
assertFileExists "home-path/bin/nvim-perl"
assertBinaryContains "$nvimBin" "perl_host_prog="
# 3. withPython3: Check if nvim-python3 binary exists and host prog is set
assertFileExists "home-path/bin/nvim-python3"
assertBinaryContains "$nvimBin" "python3_host_prog="
# 4. withRuby: Check if nvim-ruby binary exists, GEM_HOME and host prog are set
assertFileExists "home-path/bin/nvim-ruby"
assertBinaryContains "$nvimBin" "GEM_HOME="
assertBinaryContains "$nvimBin" "ruby_host_prog="
# 5. withNodeJs: Check if nvim-node binary exists and host prog is set
assertFileExists "home-path/bin/nvim-node"
assertBinaryContains "$nvimBin" "node_host_prog="
# 6. waylandSupport: Check for wl-clipboard path in wrapper's PATH modification
# We check for the store path of wl-clipboard in the current pkgs
${lib.optionalString isLinux ''
assertBinaryContains "$nvimBin" "wl-clipboard-"
''}
# 7. autowrapRuntimeDeps: Check for dummyDep path in wrapper's PATH modification
assertBinaryContains "$nvimBin" "${dummyDep}/bin"
'';
}

View file

@ -0,0 +1,4 @@
{
npm-example-settings = ./example-settings.nix;
npm-no-settings = ./no-settings.nix;
}

View file

@ -0,0 +1,36 @@
{ pkgs, ... }:
{
programs.npm = {
enable = true;
settings = {
color = true;
include = [
"dev"
"prod"
];
init-license = "MIT";
prefix = "\${HOME}/.npm";
};
};
test.stubs.nodejs = { };
nmt.script =
let
configPath = "home-files/.npmrc";
expectedConfig = pkgs.writeText "npmrc-expected" ''
color=true
include[]=dev
include[]=prod
init-license=MIT
prefix=''${HOME}/.npm
'';
in
''
assertFileExists "${configPath}"
assertFileContent "${configPath}" "${expectedConfig}"
assertFileContains home-path/etc/profile.d/hm-session-vars.sh \
'export NPM_CONFIG_USERCONFIG="/home/hm-user/.npmrc"'
'';
}

View file

@ -0,0 +1,17 @@
{ ... }:
{
programs.npm = {
enable = true;
settings = { };
};
test.stubs.nodejs = { };
nmt.script = ''
assertPathNotExists home-files/.npmrc
assertFileExists home-path/etc/profile.d/hm-session-vars.sh
assertFileNotRegex home-path/etc/profile.d/hm-session-vars.sh \
"export NPM_CONFIG_USERCONFIG="
'';
}

View file

@ -1,6 +1,6 @@
{
accounts.calendar = {
accounts.caldav = {
accounts.mine = {
pimsync.enable = true;
remote = {
passwordCommand = [
@ -22,6 +22,22 @@
basePath = ".local/state/calendar";
};
accounts.contact = {
accounts.mine = {
pimsync.enable = true;
remote = {
passwordCommand = [
"pass"
"carddav"
];
type = "carddav";
url = "https://carddav.example.com";
userName = "bob";
};
};
basePath = ".local/state/contact";
};
programs.pimsync = {
enable = true;
settings = [

View file

@ -1,14 +1,18 @@
storage caldav-local {
fileext .ics
path /home/hm-user/.local/state/calendar/caldav
type vdir/icalendar
}
storage http-local {
storage calendar-http-local {
fileext .ics
path /home/hm-user/.local/state/calendar/http
type vdir/icalendar
}
storage caldav-remote {
storage calendar-mine-local {
fileext .ics
path /home/hm-user/.local/state/calendar/mine
type vdir/icalendar
}
storage calendar-http-remote {
type webcal
url https://example.com/calendar
}
storage calendar-mine-remote {
type caldav
url https://caldav.example.com
username alice
@ -16,16 +20,29 @@ storage caldav-remote {
cmd pass caldav
}
}
storage http-remote {
type webcal
url https://example.com/calendar
}
pair calendar-caldav {
storage_a caldav-local
storage_b caldav-remote
}
pair calendar-http {
storage_a http-local
storage_b http-remote
storage_a calendar-http-local
storage_b calendar-http-remote
}
pair calendar-mine {
storage_a calendar-mine-local
storage_b calendar-mine-remote
}
storage contacts-mine-local {
fileext .vcf
path /home/hm-user/.local/state/contact/mine
type vdir/vcard
}
storage contacts-mine-remote {
type carddav
url https://carddav.example.com
username bob
password {
cmd pass carddav
}
}
pair contacts-mine {
storage_a contacts-mine-local
storage_b contacts-mine-remote
}
status_path /test/dir

View file

@ -1,9 +1,19 @@
{ config, pkgs, ... }:
{
config = {
programs.radicle.enable = true;
test.stubs.radicle-node = {
buildScript = ''
mkdir -p "$out/bin"
cat > "$out/bin/rad" << 'EOF'
#!/bin/sh
# Stub rad command that does nothing
exit 0
EOF
chmod +x "$out/bin/rad"
'';
};
nmt.script = ''
assertFileContent \
home-files/.radicle/config.json \

Some files were not shown because too many files have changed in this diff Show more