Compare commits

...

83 commits

Author SHA1 Message Date
Gaetan Lepage
436b27742c mistral-vibe: add module
Some checks are pending
/ triage (push) Waiting to run
GitHub Pages / publish (ubuntu-latest) (push) Waiting to run
2026-02-20 22:25:11 -06:00
André Kugland
a913ae61bf firefox: add handlers.json configuration
Adds support for configuring Firefox's handlers.json file to
manage MIME type and URL scheme handlers declaratively (at
`programs.firefox.profiles.<profile>.handlers`). Handlers control
how Firefox opens files and protocols (e.g., PDF viewers,
`mailto:` handlers).
2026-02-20 16:08:03 -06:00
rsahwe
c9507a9aa5 rizin: use xdg.enable and home.preferXdgDirectories
rizin reads configuration from both $HOME/.rizinrc and
from $XDG_CONFIG_HOME/rizin/rizinrc and the module
now uses the relevant options for choosing between them.
2026-02-20 16:06:11 -06:00
rsahwe
168fbe8891 rizin: add module
This adds a basic module for rizin which supports creating a basic
rizinrc for configuration.
2026-02-20 16:06:11 -06:00
rsahwe
1dcebb44c6 maintainers: add rsahwe 2026-02-20 16:06:11 -06:00
Jasper Chan
8b6212ebd6 nnn: add cd on quit option 2026-02-20 16:05:11 -06:00
Austin Horstman
91be7cce76 claude-code: fix skills implementation
Claude skills are only found when using `SKILL.md` entrypoints.
Attribute names should be used for the directory structure, not the
filename.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-19 14:00:06 -06:00
Léana 江
167e0b6837 zsh: set nix-zsh-completions as lowPrio to avoid subpath conflict 2026-02-19 17:37:09 +01:00
Ayush Pramanik
a0a01d8811 sioyek: add startupCommands option 2026-02-19 13:44:24 +01:00
Vinicius Deolindo
2dedeb55b2 man: make package nullable and default to null on darwin 2026-02-18 21:19:39 -06:00
Austin Horstman
f19a99503c ci: update buildbot test config
After https://github.com/nix-community/home-manager/pull/8464 we need to
update this to not try another flake.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-18 21:19:06 -06:00
teto
0f156f177d doc: updated instructions with tests being moved around
no need to set flake now
2026-02-18 21:13:38 -06:00
teto
8e0f4cdeee tests: merge both flakes
we used to have a flake in tests/flake.nix on top of the top-level one.
This results in 2 lockfiles for the same purpose and is not practical.
Instead this moves tests to legacyPackages:

- so they dont appear in "nix flake show" as it can be inconvenient
- legacyPackages supported nested attribute sets of derivations which
  could let us regroup tests under a same set and build that instead.
  For instance, one could `nix build .#tests.neovim` and build all of
  neovim packages. One could still pick a single `nix build
  .#tests.neovim.plugin-config`

dont expose tests into devShells to limit

fix python test runner to find the tests where appropriate
2026-02-18 21:13:38 -06:00
Léana 江
f1ebddedab tmux: fix double press prefix passthrough 2026-02-18 20:55:51 -06:00
MrTipson
b3ccd4bb26 fish: source event handling functions on shell init
Functions that contain event handler switches should be sourced during init, otherwise they become active only after being called manually.
2026-02-18 14:49:42 +01:00
carschandler
77c47a4542 carapace: ignoreCase option for case-insensitive completion
Add option for case-insensitive matching in carapace completions.
2026-02-18 11:50:04 +01:00
Thiago Kenji Okada
4ebb171bc5 nnn: remove thiagokokada from maintainers 2026-02-18 11:40:48 +01:00
Thiago Kenji Okada
30f54c7014 qt: remove thiagokokada from maintainers 2026-02-18 11:40:48 +01:00
Thiago Kenji Okada
671ba1f70e mpv: remove thiagokokada from maintainers 2026-02-18 11:40:48 +01:00
Thiago Kenji Okada
f71fa310cf hexchat: remove thiagokokada from maintainers 2026-02-18 11:40:48 +01:00
Thiago Kenji Okada
bfc89f1936 nixpkgs-disabled: remove thiagokokada from maintainers 2026-02-18 11:40:48 +01:00
Thiago Kenji Okada
b0d7d25a46 i3status-rust: remove thiagokokada from maintainers 2026-02-18 11:40:48 +01:00
teto
b0b01ab65b Revert "feat: introduce nix-shell"
This reverts commit bb45c036593f4da6a9490fd7593f60a76c444ad2.
2026-02-18 11:24:01 +01:00
home-manager-ci[bot]
5f1d42a97b 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:** 282 → 283 maintainers

** Added:** malikwirin

Generated by: lib/python/generate-all-maintainers.py
2026-02-16 13:17:35 -06:00
teto
c7d7ba954a mpv: fix include example/improve doc
I just learnt about "~~/config.inc" syntax from https://mpv.io/manual/stable/#paths
which is quite nice.
2026-02-16 13:17:21 -06:00
Austin Horstman
ae8003d8b6 mkFirefoxModule: remove visible option
Just default everything to show options to remove confusion / chance of
disabling documentation. We already set visible = true so it wasn't even
being used really.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-15 14:42:12 -06:00
Austin Horstman
1e53254671 news: inform about yazi alias change
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-14 23:14:41 -06:00
phucleeuwu
ee49ee29a1 yazi: change the default shellWrapperName yy y
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-14 23:14:41 -06:00
Bruno Bigras
ff5e5d882c tirith: fix case sensitive example
`LOW`, `MEDIUM`, `HIGH` and `CRITICAL` are case sensitive
2026-02-14 15:02:25 -06:00
mikaeladev
05e6dc0f6e qt: fix typo in qtct example 2026-02-14 03:52:59 +01:00
Ryan Hendrickson
26dfad95d9 nix: add assumeXdg option
The use-xdg-base-directories Nix setting can be set globally in
/etc/nix/nix.conf, in which case Home Manager doesn't know about it.
Users could fix that by also setting it, redundantly, in `nix.settings`,
but then Nix issues a lot of spurious warnings about
use-xdg-base-directories being a restricted setting that untrusted users
can't pass on to the daemon.

As an alternative, users can now set `nix.assumeXdg`, which makes Home
Manager assume that use-xdg-base-directories is in effect without adding
it to the user's nix.conf file.
2026-02-13 15:28:13 -06:00
Matthias Beyer
b3258dece8 programs.radicle: Document how "rad auth" must be used with this
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
2026-02-13 14:34:42 -06:00
Peter Kling
e9b706bef7 syncthing: activate logging for macOS agents 2026-02-13 14:05:36 -06:00
Peter Kling
cadfe449aa syncthing: more reliable syncthing launchd agent
Starts the syncthing-init launchd agent (responsible for updating the configuration) as a oneshot agent instead of via WatchPaths (the latter is too unreliable).

Ideally, the syncthing-init agent should be started after the syncthing agent started the Syncthing server, since syncthing-init updates the configuration using API calls to the Syncthing server. The Linux systemd service versions handle this via the Requires and After attribute. Launchd under macOS is missing a reliable way to order agents. Theoretically, one can achieve similar things via, e.g., WatchPaths (used before this commit). But this is known to be very unreliable (see also my comment in issue #6542). Thus, we just start syncthing-init and rely on the wrapped curl bash function (see curlShellFunction in nix file) to wait for the Syncthing server to be up and running.
2026-02-13 14:05:36 -06:00
Austin Horstman
bc5652b227 tests/types: add suboptions doc test
Verify we are able to extract suboptions properly with our custom lib
extension.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-13 13:41:08 -06:00
Austin Horstman
29d617ecc8 docs: improve submodule options rendering
Certain types don't offer `getSubOptions` upstream in nixpkgs, at the
moment. We can do some overriding and manually calling it for now to
fetch the options for docs.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-13 13:41:08 -06:00
Austin Horstman
4c4771cb01 rofi: add missing option description
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-13 13:41:08 -06:00
Austin Horstman
3017414609 launchd: add missing option description
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-13 13:41:08 -06:00
Austin Horstman
54ab8bc155 maintainers: remove offline
Removed upstream https://github.com/NixOS/nixpkgs/pull/483520

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-13 13:26:06 -06:00
home-manager-ci[bot]
975606b2a5 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/d6c71932130818840fc8fe9509cf50be8c64634f?narHash=sha256-ub1gpAONMFsT/GU2hV6ZWJjur8rJ6kKxdm9IlCT0j84%3D' (2026-02-08)
  → 'github:NixOS/nixpkgs/ec7c70d12ce2fc37cb92aff673dcdca89d187bae?narHash=sha256-9xejG0KoqsoKEGp2kVbXRlEYtFFcDTHjidiuX8hGO44%3D' (2026-02-11)
2026-02-13 13:26:06 -06:00
Malik
5e90b62996 tirith: add module
Adds Home Manager module for Tirith, a shell security monitor.

The module supports:
- Shell integration for Bash, Fish, and Zsh
- Allowlist configuration for bypassing Tirith analysis
- Policy configuration for customizing security behavior
2026-02-13 09:08:51 -06:00
Yus314
de4cfffc98 kitty: add autoThemeFiles option
Add support for kitty's automatic theme switching based on OS
color scheme. This creates the required auto theme config files:
- light-theme.auto.conf
- dark-theme.auto.conf
- no-preference-theme.auto.conf

Closes: nix-community/home-manager#6869
2026-02-13 10:32:36 +01:00
Austin Horstman
a6c93262f3 pay-respects: minor style cleanup
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-12 23:45:12 -06:00
Austin Horstman
f24a755980 news: add pay-respects rules addition
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-12 23:45:12 -06:00
Austin Horstman
2fe1e0ea38 tests/pay-respects: add rules test
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-12 23:45:12 -06:00
Austin Horstman
133585ddfa pay-respects: add rules support
Allow creating rules files now following docs from
https://github.com/iffse/pay-respects/blob/main/rules.md

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-12 23:45:12 -06:00
nescias
9bdb693810 notmuch: add programs.notmuch.package option
Allow users to specify which notmuch package should be used.
2026-02-12 16:42:39 -06:00
nescias
258db1d39b git: respect programs.msmtp.package
Since the user may override `programs.msmtp.package` using
`pkgs.msmtp` as the sendmail binary might result in the wrong package
being used.
2026-02-12 16:42:39 -06:00
Austin Horstman
2cc195b478 docs: update flake module example
Just include some more detail in example

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-12 15:13:04 -06:00
Austin Horstman
6a1f7101d2 news: add flameshot darwin entry
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-12 11:04:03 -06:00
Austin Horstman
ede6d1d95e tests/flameshot: add darwin tests
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-12 11:04:03 -06:00
Austin Horstman
2363f5a377 flameshot: add darwin support
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-12 11:04:03 -06:00
teto
0825a0922a feat: introduce nix-shell
flakes are not stable yet, community is divided but maintaining both
flake and a set of dependencies in our scripts is hard.
So provide a nix-shell that fetches the nixpkgs recorded in the
flake.lock to keep a single source of truth
2026-02-12 16:27:35 +01:00
home-manager-ci[bot]
0acbd11806 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/00c21e4c93d963c50d4c0c89bfa84ed6e0694df2?narHash=sha256-AYqlWrX09%2BHvGs8zM6ebZ1pwUqjkfpnv8mewYwAo%2BiM%3D' (2026-02-04)
  → 'github:NixOS/nixpkgs/d6c71932130818840fc8fe9509cf50be8c64634f?narHash=sha256-ub1gpAONMFsT/GU2hV6ZWJjur8rJ6kKxdm9IlCT0j84%3D' (2026-02-08)
2026-02-11 08:04:04 -06:00
Adam Poit
b3f43db171 colima: fix KeepAlive to prevent process accumulation on macOS
Change KeepAlive from boolean true to SuccessfulExit dictionary in the LaunchAgent configuration.
When colima fails to start (e.g., disk already attached), the boolean true setting causes
launchd to immediately restart it, spawning orphaned limactl usernet processes with each
restart.

Using SuccessfulExit = true ensures the service only restarts on clean exits (exit code 0),
preventing the aggressive restart loop that accumulates orphaned processes.
2026-02-10 21:19:55 -06:00
home-manager-ci[bot]
6c4fdbe1ad 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:** 282 → 283 maintainers

** Added:** mikaeladev

Generated by: lib/python/generate-all-maintainers.py
2026-02-09 10:28:40 -06:00
Austin Horstman
13a1beb7c9 news: add codex mcp integration
Just letting users know module has the integration enabled now.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-09 07:14:50 -06:00
Austin Horstman
6c8def1df8 codex: add enableMcpIntegration option
Work with the shared mcp module for integration and transformation.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-09 07:14:50 -06:00
Austin Horstman
b1f916ba05 news: don't specify nixpkgs revision
Not necessary for using nix-shell and causes extra maintenance.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-08 15:31:12 -06:00
home-manager-ci[bot]
a0da0f24fd flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/e6eae2ee2110f3d31110d5c222cd395303343b08?narHash=sha256-KHFT9UWOF2yRPlAnSXQJh6uVcgNcWlFqqiAZ7OVlHNc%3D' (2026-02-03)
  → 'github:NixOS/nixpkgs/00c21e4c93d963c50d4c0c89bfa84ed6e0694df2?narHash=sha256-AYqlWrX09%2BHvGs8zM6ebZ1pwUqjkfpnv8mewYwAo%2BiM%3D' (2026-02-04)
2026-02-08 15:21:52 -06:00
Francesco Noacco
afaa85cf32 vivid: add nushell integration 2026-02-08 15:20:51 -06:00
Aguirre Matteo
42c607ecb4 news: add lazyworktree entry 2026-02-08 15:14:18 -06:00
Aguirre Matteo
f5d50fd8cb lazyworktree: add module 2026-02-08 15:14:18 -06:00
Austin Horstman
cbd8a72e5f treewide: remove xorg package set
Xorg package set removed, now aliases.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-07 13:10:27 -06:00
Francesco Noacco
6cee082157 zed-editor: don't generate empty keymap files
default value for user keymaps is an empty list, but the check was
made against an empty set, generating the file when no value
was given
2026-02-07 09:07:14 -06:00
Austin Horstman
471e6a065f prismlauncher: merge only when configured
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-05 13:11:00 -06:00
Austin Horstman
f915881ba7 prismlauncher: code style and lint cleanup
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-05 13:11:00 -06:00
K900
332027bc0a treewide: use pkgs.lndir instead of pkgs.xorg.lndir
Follow the change in nixpkgs.
2026-02-05 10:59:19 -06:00
Anton
bbccee8713 halloy: fix URL in description 2026-02-05 07:58:26 -06:00
mikaeladev
04e5203db6 prismlauncher: add module 2026-02-04 21:47:21 -06:00
mikaeladev
6f64dee491 maintainers: add mikaeladev 2026-02-04 21:47:21 -06:00
Léana 江
cfb3b544f9 programs.git: test git integration options assertion 2026-02-04 21:43:38 -06:00
Léana 江
715e6d7f89 programs.git: fix assertion message inconsistency 2026-02-04 21:43:38 -06:00
Austin Horstman
6c79e409a5 news: add xdg-user-dirs changes entry
Inform users about the various changes to xdg-user-dirs.

Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2026-02-04 21:16:02 -06:00
Greg Pfeil
c8f9edda94 xdg.userDirs: add notes for stateVersion changes 2026-02-04 21:16:02 -06:00
Greg Pfeil
9b62076484 xdg.userDirs: change the syntax for extraConfig
E.g., use `MISC` instead of `XDG_MISC_DIR`, the same way `xdg-user-dirs-update`
works.

This is conditionalized on 26.05, so in future `XDG_MISC_DIR` will be disallowed.
2026-02-04 21:16:02 -06:00
Greg Pfeil
db9044b119 xdg.userDirs: add a setSessionVariables option
It defaults to `true` to maintain the current behavior.

This is conditionalized on 26.05, so in future `setSessionVariables` will
default to `false`.
2026-02-04 21:16:02 -06:00
Greg Pfeil
83cc9d32e3 xdg.userDirs: add a nullable package option 2026-02-04 21:16:02 -06:00
Greg Pfeil
7c47cafa90 xdg.userDirs: don’t require Linux
Everything here works on Darwin, etc.
2026-02-04 21:16:02 -06:00
home-manager-ci[bot]
689e4a3423 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/88d3861acdd3d2f0e361767018218e51810df8a1?narHash=sha256-MJ27Cy2NtBEV5tsK%2BYraYr2g851f3Fl1LpNHDzDX15c%3D' (2026-01-21)
  → 'github:NixOS/nixpkgs/e6eae2ee2110f3d31110d5c222cd395303343b08?narHash=sha256-KHFT9UWOF2yRPlAnSXQJh6uVcgNcWlFqqiAZ7OVlHNc%3D' (2026-02-03)
2026-02-04 20:53:11 -06:00
Johan Larsson
4fda26500b tomat: modify After, PartOf, Environment in service
This allows the tomat service to properly execute hooks, which is a
feature that requires a modifying the PATH and ensuring that the service
is started after the graphical session.
2026-02-03 18:17:40 -06:00
home-manager-ci[bot]
83e4f9b4d2 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:** magicquark

Generated by: lib/python/generate-all-maintainers.py
2026-02-03 18:16:16 -06:00
Dennis Schridde
36349274d7 home-manager: Prevent pipe failure when reading news
On my system (Fedora 43 with Nix 2.31.3) `home-manager news` exits
from `SIGPIPE` and never writes `~/.local/share/home-manager/news-read-ids`,
resulting in news items to never be marked read.  This is caused by
piping `(import ./news.nix).news.all` through `jq` and `less` failing
with an error as soon as `less` exits, which triggers `set -o pipefail`
to exit the shell running `home-manager` itself.

Avoiding the pipe into `$PAGER` avoids the problem.

Closes: https://github.com/nix-community/home-manager/issues/8690
References: https://github.com/jqlang/jq/issues/1017
References: https://www.greenend.org.uk/rjk/tech/shellmistakes.html#pipeerrors
2026-02-03 18:14:58 -06:00
145 changed files with 2709 additions and 427 deletions

View file

@ -50,7 +50,7 @@
source = "nixpkgs";
};
ALameLlama = {
email = "NicholasACiechanowski@gmail.com";
email = "nicholas@ciech.anow.ski";
github = "ALameLlama";
githubId = 55490546;
name = "Nicholas Ciechanowski";
@ -1538,6 +1538,12 @@
name = "Lukas Nagel";
source = "home-manager";
};
magicquark = {
github = "magicquark";
githubId = 198001825;
name = "magicquark";
source = "nixpkgs";
};
mainrs = {
email = "5113257+mainrs@users.noreply.github.com";
github = "mainrs";
@ -1545,6 +1551,18 @@
name = "mainrs";
source = "home-manager";
};
malikwirin = {
email = "abdelmalik.najhi@stud.hs-kempten.de";
github = "malikwirin";
githubId = 117918464;
keys = [
{
fingerprint = "B5ED 595C 8C7E 133C 6B68 63C8 CFEF 1E35 0351 F72D";
}
];
name = "Malik";
source = "nixpkgs";
};
malte-v = {
email = "nixpkgs@mal.tc";
github = "malte-v";
@ -1634,6 +1652,13 @@
name = "Shahar \"Dawn\" Or";
source = "nixpkgs";
};
mikaeladev = {
email = "mikaeladev@users.noreply.github.com";
github = "mikaeladev";
githubId = 100416544;
name = "mikaeladev";
source = "home-manager";
};
mikilio = {
email = "official.mikilio+dev@gmail.com";
github = "mikilio";
@ -1814,13 +1839,6 @@
name = "Judson Lester";
source = "nixpkgs";
};
offlinehacker = {
email = "jaka@x-truder.net";
github = "offlinehacker";
githubId = 585547;
name = "Jaka Hudoklin";
source = "nixpkgs";
};
olmokramer = {
email = "olmokramer@users.noreply.github.com";
github = "olmokramer";

View file

@ -1,3 +1 @@
attribute = "buildbot"
flake_dir = "./tests"
lock_file = "./flake.lock"

View file

@ -69,6 +69,57 @@ let
hmPath = toString ./..;
# Keep submodule option docs visible when wrapped in `either` (and therefore
# in `nullOr (either ...)`), which upstream currently omits.
docsLib = lib.extend (
_self: super:
let
mergeEitherSubOptions =
prefix: leftType: rightType:
let
getSubOptionsOrEmpty =
optionType:
let
subOptions = optionType.getSubOptions prefix;
in
if builtins.isAttrs subOptions then subOptions else { };
mkOptionDecl = options: {
_file = "<docs/default.nix>";
pos = null;
inherit options;
};
optionSets = lib.filter (options: options != { }) [
(getSubOptionsOrEmpty leftType)
(getSubOptionsOrEmpty rightType)
];
mergedOptions = lib.foldl' (
acc: options:
if acc == { } then
options
else
(super.mergeOptionDecls prefix [
(mkOptionDecl acc)
(mkOptionDecl options)
]).options
) { } optionSets;
in
mergedOptions;
in
{
types = super.types // {
either =
leftType: rightType:
(super.types.either leftType rightType)
// {
getSubOptions = prefix: mergeEitherSubOptions prefix leftType rightType;
};
};
}
);
buildOptionsDocs =
args@{
modules,
@ -103,7 +154,7 @@ let
};
options =
(lib.evalModules {
(docsLib.evalModules {
modules = modules ++ [ poisonModule ];
class = "homeManager";
}).options;
@ -141,7 +192,8 @@ let
hmOptionsDocs = buildOptionsDocs {
modules =
import ../modules/modules.nix {
inherit lib pkgs;
lib = docsLib;
inherit pkgs;
check = false;
}
++ [ scrubbedPkgsModule ];
@ -246,4 +298,7 @@ in
in
builtins.toJSON result.config.meta.maintainers
);
# Unstable, for tests.
_internal = { inherit docsLib; };
}

View file

@ -217,13 +217,13 @@ and may cause failures. To run against the Nixpkgs from the `flake.lock` file,
use instead e.g.
``` shell
$ nix build --reference-lock-file flake.lock --option allow-import-from-derivation false ./tests#test-all
$ nix build --option allow-import-from-derivation false .#test-all
```
or
``` shell
$ nix build --reference-lock-file flake.lock --option allow-import-from-derivation false ./tests#test-alacritty-empty-settings
$ nix build --option allow-import-from-derivation false .#test-alacritty-empty-settings
```
Some tests may be marked with `enableLegacyIfd`, those may be run by run with e.g.

View file

@ -1,10 +1,9 @@
# flake-parts module {#sec-flakes-flake-parts-module}
When using [flake-parts](https://flake.parts)
you may wish to import Home Manager's flake module,
`flakeModules.home-manager`.
When using [flake-parts](https://flake.parts) you may wish to import Home
Manager's flake module, `flakeModules.home-manager`.
``` nix
```nix
{
description = "flake-parts configuration";
@ -15,15 +14,41 @@ you may wish to import Home Manager's flake module,
flake-parts.url = "github:hercules-ci/flake-parts";
};
outputs = inputs@{ flake-parts, ... }:
outputs = inputs@{
flake-parts,
home-manager,
nixpkgs,
...
}:
flake-parts.lib.mkFlake { inherit inputs; } {
imports = [
# Import home-manager's flake module
inputs.home-manager.flakeModules.home-manager
];
flake = {
# Define `homeModules`, `homeConfigurations`,
# `nixosConfigurations`, etc here
# Reusable Home Manager module.
homeModules.bash= { pkgs, ... }: {
programs.bash = {
enable = true;
shellAliases = {
ll = "ls -l";
};
};
home.packages = [ pkgs.hello ];
};
# Concrete Home Manager configuration.
homeConfigurations.alice = home-manager.lib.homeManagerConfiguration {
pkgs = import nixpkgs { system = "x86_64-linux"; };
modules = [
inputs.self.homeModules.bash
{
home.username = "alice";
home.homeDirectory = "/home/alice";
home.stateVersion = "25.11";
}
];
};
};
# See flake.parts for more features, such as `perSystem`
};

View file

@ -23,3 +23,22 @@ changes are only active if the `home.stateVersion` option is set to
- The [](#opt-programs.zsh.dotDir) option now defaults to the XDG
configuration directory (usually `~/.config/zsh`) when
[](#opt-xdg.enable) is true.
- The [](#opt-programs.yazi.shellWrapperName) option now defaults to
`y` instead of `yy`. For users with older `home.stateVersion` values,
the legacy default `yy` is retained.
- The [](#opt-xdg.userDirs.setSessionVariables) option now defaults to `false`
instead of `true`.
- The [](#opt-xdg.userDirs.extraConfig) option no longer accepts keys of the
form `XDG_<name>_DIR`, they should be now be just the name. For example, if
you had the key `XDG_DESKTOP_DIR` before, you should now use the key
`DESKTOP`. Home Manager 26.05 introduced a warning when the `XDG_<name>_DIR`
form is used.
- The [](#opt-programs.man.package) option now defaults to `null` on
Darwin because the GNU `man` from nixpkgs ships `apropos`/`man -k`
and `whatis`/`man -f` binaries that don't work on Darwin. Nix-installed
manual pages still work with macOS's built-in `man` via
[](#opt-home.extraOutputsToInstall).

6
flake.lock generated
View file

@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1769018530,
"narHash": "sha256-MJ27Cy2NtBEV5tsK+YraYr2g851f3Fl1LpNHDzDX15c=",
"lastModified": 1770841267,
"narHash": "sha256-9xejG0KoqsoKEGp2kVbXRlEYtFFcDTHjidiuX8hGO44=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "88d3861acdd3d2f0e361767018218e51810df8a1",
"rev": "ec7c70d12ce2fc37cb92aff673dcdca89d187bae",
"type": "github"
},
"original": {

136
flake.nix
View file

@ -48,6 +48,113 @@
forAllPkgs =
f:
nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed (system: f nixpkgs.legacyPackages.${system});
forCI = nixpkgs.lib.genAttrs [
"aarch64-darwin"
"x86_64-linux"
];
testChunks =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
# Create chunked test packages for better CI parallelization
tests = import ./tests {
inherit pkgs;
# Disable big tests since this is only used for CI
enableBig = false;
};
allTests = lib.attrNames tests.build;
# Remove 'all' from the test list as it's a meta-package
filteredTests = lib.filter (name: name != "all") allTests;
# NOTE: Just a starting value, we can tweak this to find a good value.
targetTestsPerChunk = 50;
numChunks = lib.max 1 (
builtins.ceil ((builtins.length filteredTests) / (targetTestsPerChunk * 1.0))
);
chunkSize = builtins.ceil ((builtins.length filteredTests) / (numChunks * 1.0));
makeChunk =
chunkNum: testList:
let
start = (chunkNum - 1) * chunkSize;
end = lib.min (start + chunkSize) (builtins.length testList);
chunkTests = lib.sublist start (end - start) testList;
chunkAttrs = lib.genAttrs chunkTests (name: tests.build.${name});
in
pkgs.symlinkJoin {
name = "test-chunk-${toString chunkNum}";
paths = lib.attrValues chunkAttrs;
passthru.tests = chunkTests;
};
in
lib.listToAttrs (
lib.genList (
i: lib.nameValuePair "test-chunk-${toString (i + 1)}" (makeChunk (i + 1) filteredTests)
) numChunks
);
integrationTests =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
in
lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux (
let
tests = import ./tests/integration { inherit pkgs lib; };
renameTestPkg = n: v: lib.nameValuePair "integration-${n}" v;
in
lib.mapAttrs' renameTestPkg (lib.removeAttrs tests [ "all" ])
);
buildTests =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
tests = import ./tests { inherit pkgs; };
renameTestPkg = n: nixpkgs.lib.nameValuePair "test-${n}";
in
nixpkgs.lib.mapAttrs' renameTestPkg tests.build;
buildTestsNoBig =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
tests = import ./tests {
inherit pkgs;
enableBig = false;
};
in
{
test-all-enableBig-false-enableLegacyIfd-false = tests.build.all;
};
buildTestsNoBigIfd =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
tests = import ./tests {
inherit pkgs;
enableBig = false;
enableLegacyIfd = true;
};
in
{
test-all-enableBig-false-enableLegacyIfd-true = tests.build.all;
};
integrationTestPackages =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
tests = import ./tests/integration { inherit pkgs lib; };
renameTestPkg = n: lib.nameValuePair "integration-test-${n}";
in
lib.mapAttrs' renameTestPkg tests;
in
{
formatter = forAllPkgs (
@ -63,6 +170,22 @@
}
);
# TODO: increase buildbot testing scope
buildbot = forCI (
system:
let
allIntegrationTests = integrationTests system;
workingIntegrationTests = nixpkgs.lib.filterAttrs (
name: _:
nixpkgs.lib.elem name [
"integration-nixos-basics"
"integration-nixos-legacy-profile-management"
]
) allIntegrationTests;
in
(testChunks system) // workingIntegrationTests
);
packages = forAllPkgs (
pkgs:
let
@ -90,6 +213,19 @@
docs-manpages = docs.manPages;
}
);
legacyPackages = forAllPkgs (
pkgs:
let
system = pkgs.stdenv.hostPlatform.system;
in
(buildTests system)
// (integrationTestPackages system)
// (buildTestsNoBig system)
// (buildTestsNoBigIfd system)
// (testChunks system)
// (integrationTests system)
);
}
);
}

View file

@ -998,9 +998,11 @@ function doShowNews() {
return 1
esac
local formattedNewsFile="$WORK_DIR/news.txt"
nix-instantiate --quiet --eval --json --expr "(import ${newsNixFile}).news.$newsAttr" \
| jq -r . \
| ${PAGER:-less}
> "$formattedNewsFile"
${PAGER:-less} "$formattedNewsFile"
local allIds
allIds="$(nix-instantiate --quiet --eval --expr "(import ${newsNixFile}).meta.ids")"

View file

@ -224,7 +224,7 @@ in
(mkIf cfg.x11.enable {
xsession.profileExtra = ''
${pkgs.xorg.xsetroot}/bin/xsetroot -xcf ${cursorPath} ${toString cfg.size}
${lib.getExe pkgs.xsetroot} -xcf ${cursorPath} ${toString cfg.size}
'';
xresources.properties = {

View file

@ -291,7 +291,7 @@ in
home-files =
pkgs.runCommandLocal "home-manager-files"
{
nativeBuildInputs = [ pkgs.xorg.lndir ];
nativeBuildInputs = [ pkgs.lndir ];
}
(
''

View file

@ -618,7 +618,7 @@ in
home.profileDirectory =
if config.submoduleSupport.enable && config.submoduleSupport.externalPackageInstall then
"/etc/profiles/per-user/${cfg.username}"
else if config.nix.enable && (config.nix.settings.use-xdg-base-directories or false) then
else if config.nix.useXdg then
"${config.xdg.stateHome}/nix/profile"
else
cfg.homeDirectory + "/.nix-profile";

View file

@ -259,6 +259,10 @@ in
AfterInitialDemand = mkOption {
type = types.nullOr types.bool;
default = null;
description = ''
Whether to defer evaluating other `KeepAlive` conditions until
the job has been started at least once by demand.
'';
};
};

View file

@ -368,6 +368,12 @@
github = "mifom";
githubId = 23462908;
};
mikaeladev = {
name = "mikaeladev";
email = "mikaeladev@users.noreply.github.com";
github = "mikaeladev";
githubId = 100416544;
};
mikilio = {
name = "mikilio";
email = "official.mikilio+dev@gmail.com";
@ -488,6 +494,12 @@
github = "Rosuavio";
githubId = 7164552;
};
rsahwe = {
name = "rsahwe";
email = "rsahwe@gmx.net";
github = "rsahwe";
githubId = 201613730;
};
rszamszur = {
name = "Radosław Szamszur";
email = "radoslawszamszur@gmail.com";

View file

@ -0,0 +1,18 @@
{ config, ... }:
{
time = "2025-12-10T07:15:59+00:00";
condition = config.programs.firefox.enable;
message = ''
The Firefox module now provides a
'programs.firefox.profiles.<name>.handlers' option.
It allows declarative configuration of MIME type and URL scheme handlers
through Firefox's handlers.json file, controlling how Firefox opens files
and protocols (e.g., PDF viewers, mailto handlers).
Configure handlers with:
programs.firefox.profiles.<name>.handlers.mimeTypes
programs.firefox.profiles.<name>.handlers.schemes
'';
}

View file

@ -0,0 +1,10 @@
{
time = "2026-01-27T20:02:41+00:00";
condition = true;
message = ''
A new module is available: 'programs.prismlauncher'.
An open-source Minecraft launcher that can manage multiple instances,
accounts, and mods. Focused on user freedom and free redistributability.
'';
}

View file

@ -0,0 +1,19 @@
{ config, ... }:
{
time = "2026-02-05T03:02:20+00:00";
condition = config.xdg.userDirs.enable;
message = ''
The `xdg.userDirs` module now supports non-Linux platforms.
The `xdg.userDirs.package` option is now available. Set it to `null`
to prevent Home Manager from installing `xdg-user-dirs`.
The `xdg.userDirs.extraConfig` option no longer recommends keys of the
form `XDG_<name>_DIR`; use just `<name>` instead (e.g. `DESKTOP`).
The old form is deprecated and will emit a warning.
The `xdg.userDirs.setSessionVariables` option was added to control
whether XDG user directory environment variables like `XDG_DESKTOP_DIR` are
set. It now defaults to `false` for `home.stateVersion` 26.05 and later.
'';
}

View file

@ -0,0 +1,10 @@
{
time = "2026-02-08T13:59:14+00:00";
condition = true;
message = ''
A new module is available: `programs.lazyworktree`
LazyWorktree is a TUI for Git worktrees. It provides a keyboard-driven
workflow for creating, inspecting, and navigating worktrees within a repository.
'';
}

View file

@ -0,0 +1,13 @@
{ config, ... }:
{
time = "2026-02-08T21:04:50+00:00";
condition = config.programs.codex.enable;
message = ''
The `programs.codex` module now supports MCP integration via
`programs.codex.enableMcpIntegration`.
When enabled, shared servers from `programs.mcp.servers` are merged
into `programs.codex.settings.mcp_servers`, with settings-based values
taking precedence.
'';
}

View file

@ -0,0 +1,8 @@
{
time = "2026-02-12T05:16:46+00:00";
condition = true;
message = ''
The `services.flameshot` module now supports Darwin by generating a
launchd agent in addition to the existing Linux systemd service.
'';
}

View file

@ -0,0 +1,16 @@
{ config, ... }:
{
time = "2026-02-12T19:22:50+00:00";
condition = config.programs.pay-respects.enable;
message = ''
The option `programs.pay-respects.rules` was added.
It generates runtime rule files at
{file}`$XDG_CONFIG_HOME/pay-respects/rules/<name>.toml`, where each
attribute name under `rules` becomes a filename (for example, `rules.cargo`
writes `cargo.toml`).
For the full runtime-rules format and command matching requirements, see
<https://github.com/iffse/pay-respects/blob/main/rules.md>.
'';
}

View file

@ -0,0 +1,11 @@
{
time = "2026-02-13T11:21:10+00:00";
condition = true;
message = ''
A new module is available: 'programs.tirith'.
Tirith is a shell security monitor that helps protect against
malicious commands by analyzing shell inputs before execution.
'';
}

View file

@ -0,0 +1,9 @@
{ config, ... }:
{
time = "2026-02-13T20:17:15+00:00";
condition = config.programs.yazi.enable;
message = "
The option `programs.yazi.shellWrapperName` default has changed from `yy` to `y`
to align with the recommendation from upstream.
";
}

View file

@ -0,0 +1,10 @@
{
time = "2026-02-17T14:42:25+00:00";
condition = true;
message = ''
A new module is available: 'programs.mistral-vibe'.
mistral-vibe is Mistral's open-source CLI coding assistant.
'';
}

View file

@ -0,0 +1,12 @@
{
time = "2026-02-18T17:20:43+00:00";
condition = true;
message = ''
A new module is available: 'programs.rizin'.
Rizin is a free and open-source reverse engineering framework
that delivers a comprehensive binary analysis experience.
It focuses on usability, stability, and functional features,
striving to create a welcoming environment for developers and users.
'';
}

View file

@ -1,5 +1,5 @@
#!/usr/bin/env nix-shell
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/72ac591e737060deab2b86d6952babd1f896d7c5.tar.gz -i bash -p coreutils
#! nix-shell -i bash -p coreutils
DATE="$(date --iso-8601=second --universal)"
YEAR="$(date --date="$DATE" +"%Y")"
@ -15,7 +15,7 @@ cd "$DIRNAME" || {
exit 1
}
cat - << EOF > "$YEAR/$MONTH/$FILENAME_BASE.nix"
cat - <<EOF >"$YEAR/$MONTH/$FILENAME_BASE.nix"
{
time = "$DATE";
condition = true;

View file

@ -1,6 +1,7 @@
{
config,
lib,
osConfig,
pkgs,
...
}:
@ -21,6 +22,7 @@ let
isList
isString
literalExpression
literalMD
mapAttrsToList
mkDefault
mkEnableOption
@ -41,7 +43,7 @@ let
nixPath = concatStringsSep ":" cfg.nixPath;
useXdg = config.nix.enable && (config.nix.settings.use-xdg-base-directories or false);
inherit (config.nix) useXdg;
defexprDir =
if useXdg then
"${config.xdg.stateHome}/nix/defexpr"
@ -296,6 +298,30 @@ in
'';
};
assumeXdg = mkOption {
type = types.bool;
default = false;
description = ''
Whether Home Manager should assume that Nix is configured to use XDG
base directories. Note that this doesn't change the behavior of Nix. To
do that, set nix.settings.use-xdg-base-directories instead. This option
is intended for settings in which use-xdg-base-directories is set
globally or nix.conf is unmanaged by Home Manager.
'';
};
useXdg = mkOption {
type = types.bool;
visible = false;
readOnly = true;
defaultText = literalMD ''
In descending priority:
* `true` if `nix.assumeXdg` is `true`
* `nix.settings.use-xdg-base-directories` if it is set and `nix.enable` is `true`
* `osConfig.nix.settings.use-xdg-base-directories` if it is set and `osConfig.nix.enable` is `true`
'';
};
extraOptions = mkOption {
type = types.lines;
default = "";
@ -326,39 +352,69 @@ in
};
};
config = mkIf cfg.enable (mkMerge [
(mkIf (cfg.nixPath != [ ] && !cfg.keepOldNixPath) {
home.sessionVariables.NIX_PATH = "${nixPath}";
})
config = mkMerge [
{
nix.useXdg =
let
# Helper that checks if use-xdg-base-directories is in effect for the
# given Nix configuration, falling back to a given default value if
# it is undefined or the configuration is not enabled.
checkNixXdg = def: cfg: if cfg.enable then cfg.settings.use-xdg-base-directories or def else def;
(mkIf (cfg.nixPath != [ ] && cfg.keepOldNixPath) {
home.sessionVariables.NIX_PATH = "${nixPath}\${NIX_PATH:+:$NIX_PATH}";
})
# Whether the OS configuration indicates that XDG directories should
# be used.
osUseXdg = checkNixXdg false osConfig.nix or { enable = false; };
(lib.mkIf (cfg.channels != { }) {
nix.nixPath = [ channelPath ];
home.file."${channelPath}".source = channelsDrv;
})
# Whether the user configuration indicates that XDG directories
# should be used, falling back to the OS configuration if not
# specified.
hmUseXdg = checkNixXdg osUseXdg cfg;
in
cfg.assumeXdg || hmUseXdg;
(mkIf (cfg.registry != { }) {
xdg.configFile."nix/registry.json".source = jsonFormat.generate "registry.json" {
version = cfg.registryVersion;
flakes = mapAttrsToList (n: v: { inherit (v) from to exact; }) cfg.registry;
};
})
(mkIf (cfg.settings != { } || cfg.extraOptions != "") {
assertions = [
{
assertion = cfg.package != null;
assertion = !(cfg.assumeXdg && cfg.enable && cfg.settings ? use-xdg-base-directories);
message = ''
A corresponding Nix package must be specified via `nix.package` for generating
nix.conf.
`nix.assumeXdg` should not be set if `nix.settings.use-xdg-base-directories` is.
'';
}
];
}
(mkIf cfg.enable (mkMerge [
(mkIf (cfg.nixPath != [ ] && !cfg.keepOldNixPath) {
home.sessionVariables.NIX_PATH = "${nixPath}";
})
xdg.configFile."nix/nix.conf".source = nixConf;
})
]);
(mkIf (cfg.nixPath != [ ] && cfg.keepOldNixPath) {
home.sessionVariables.NIX_PATH = "${nixPath}\${NIX_PATH:+:$NIX_PATH}";
})
(lib.mkIf (cfg.channels != { }) {
nix.nixPath = [ channelPath ];
home.file."${channelPath}".source = channelsDrv;
})
(mkIf (cfg.registry != { }) {
xdg.configFile."nix/registry.json".source = jsonFormat.generate "registry.json" {
version = cfg.registryVersion;
flakes = mapAttrsToList (n: v: { inherit (v) from to exact; }) cfg.registry;
};
})
(mkIf (cfg.settings != { } || cfg.extraOptions != "") {
assertions = [
{
assertion = cfg.package != null;
message = ''
A corresponding Nix package must be specified via `nix.package` for generating
nix.conf.
'';
}
];
xdg.configFile."nix/nix.conf".source = nixConf;
})
]))
];
}

View file

@ -59,7 +59,7 @@ let
in
{
meta.maintainers = with lib.maintainers; [ thiagokokada ];
meta.maintainers = [ ];
options.nixpkgs = {
config = lib.mkOption {

View file

@ -92,7 +92,6 @@ in
{
meta.maintainers = with lib.maintainers; [
rycee
thiagokokada
];
imports = [
@ -302,7 +301,7 @@ in
Appearance = {
style = "kvantum";
icon_theme = "Papirus-Dark";
standar_dialogs = "xdgdesktopportal";
standard_dialogs = "xdgdesktopportal";
};
Fonts = {
fixed = "\"DejaVuSansM Nerd Font Mono,12\"";

View file

@ -36,6 +36,8 @@ in
'';
};
package = lib.mkPackageOption pkgs "xdg-user-dirs" { nullable = true; };
# Well-known directory list from
# https://gitlab.freedesktop.org/xdg/xdg-user-dirs/blob/master/man/user-dirs.dirs.xml
@ -101,45 +103,88 @@ in
defaultText = literalExpression "{ }";
example = literalExpression ''
{
XDG_MISC_DIR = "''${config.home.homeDirectory}/Misc";
MISC = "''${config.home.homeDirectory}/Misc";
}
'';
description = "Other user directories.";
apply =
if lib.versionOlder config.home.stateVersion "26.05" then
lib.mapAttrs' (
k:
let
matches = lib.match "XDG_(.*)_DIR" k;
in
lib.nameValuePair (
if matches == null then
k
else
let
name = lib.elemAt matches 0;
in
lib.warn "using keys like ${k} for xdg.userDirs.extraConfig is deprecated in favor of keys like ${name}" name
)
)
else
lib.id;
description = ''
Other user directories.
The key MISC corresponds to the user-dirs entry XDG_MISC_DIR.
'';
};
createDirectories = lib.mkEnableOption "automatic creation of the XDG user directories";
setSessionVariables = mkOption {
type = with types; bool;
default = lib.versionOlder config.home.stateVersion "26.05";
defaultText = literalExpression ''
lib.versionOlder config.home.stateVersion "26.05"
'';
description = ''
Whether to set the XDG user dir environment variables, like
`XDG_DESKTOP_DIR`.
::: {.note}
The recommended way to get these values is via the `xdg-user-dir`
command or by processing `$XDG_CONFIG_HOME/user-dirs.dirs` directly in
your application.
:::
This defaults to `true` for state version < 26.05 and `false` otherwise.
'';
};
};
config =
let
directories =
(lib.filterAttrs (n: v: !isNull v) {
XDG_DESKTOP_DIR = cfg.desktop;
XDG_DOCUMENTS_DIR = cfg.documents;
XDG_DOWNLOAD_DIR = cfg.download;
XDG_MUSIC_DIR = cfg.music;
XDG_PICTURES_DIR = cfg.pictures;
XDG_PUBLICSHARE_DIR = cfg.publicShare;
XDG_TEMPLATES_DIR = cfg.templates;
XDG_VIDEOS_DIR = cfg.videos;
DESKTOP = cfg.desktop;
DOCUMENTS = cfg.documents;
DOWNLOAD = cfg.download;
MUSIC = cfg.music;
PICTURES = cfg.pictures;
PUBLICSHARE = cfg.publicShare;
TEMPLATES = cfg.templates;
VIDEOS = cfg.videos;
})
// cfg.extraConfig;
bindings = lib.mapAttrs' (k: lib.nameValuePair "XDG_${k}_DIR") directories;
in
lib.mkIf cfg.enable {
assertions = [
(lib.hm.assertions.assertPlatform "xdg.userDirs" pkgs lib.platforms.linux)
];
xdg.configFile."user-dirs.dirs".text =
let
# For some reason, these need to be wrapped with quotes to be valid.
wrapped = lib.mapAttrs (_: value: ''"${value}"'') directories;
wrapped = lib.mapAttrs (_: value: ''"${value}"'') bindings;
in
lib.generators.toKeyValue { } wrapped;
xdg.configFile."user-dirs.conf".text = "enabled=False";
home.sessionVariables = directories;
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
home.sessionVariables = lib.mkIf cfg.setSessionVariables bindings;
home.activation.createXdgUserDirectories = lib.mkIf cfg.createDirectories (
let

View file

@ -371,7 +371,7 @@ in
exit 1
esac
echo "Xft.dpi: $DPI" | ''${pkgs.xorg.xrdb}/bin/xrdb -merge
echo "Xft.dpi: $DPI" | ''${lib.getExe pkgs.xrdb} -merge
'''
};
}

View file

@ -27,9 +27,32 @@ in
enableNushellIntegration = lib.hm.shell.mkNushellIntegrationOption { inherit config; };
enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; };
ignoreCase = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable case-insensitive matching for carapace completions.
When enabled, the carapace binary is wrapped with {env}`CARAPACE_MATCH`
set to `1`.
'';
};
};
config = lib.mkIf cfg.enable {
programs.carapace.package = lib.mkIf cfg.ignoreCase (
pkgs.symlinkJoin {
name = "carapace-wrapped";
paths = [ pkgs.carapace ];
nativeBuildInputs = [ pkgs.makeWrapper ];
postBuild = ''
wrapProgram $out/bin/carapace \
--set CARAPACE_MATCH 1
'';
meta.mainProgram = "carapace";
}
);
home.packages = [ cfg.package ];
programs = {

View file

@ -298,14 +298,14 @@ in
default = { };
description = ''
Custom skills for Claude Code.
The attribute name becomes the skill filename or directory name, and the value is either:
- Inline content as a string (creates .claude/skills/<name>.md)
- A path to a file (creates .claude/skills/<name>.md)
The attribute name becomes the skill directory name, and the value is either:
- Inline content as a string (creates .claude/skills/<name>/SKILL.md)
- A path to a file (creates .claude/skills/<name>/SKILL.md)
- A path to a directory (creates .claude/skills/<name>/ with all files)
'';
example = lib.literalExpression ''
{
xlsx = ./skills/xlsx.md;
xlsx = ./skills/xlsx/SKILL.md;
data-analysis = ./skills/data-analysis;
pdf-processing = '''
---
@ -334,8 +334,9 @@ in
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Path to a directory containing skill files for Claude Code.
Skill files from this directory will be symlinked to .claude/skills/.
Path to a directory containing skill directories for Claude Code.
Each skill directory should contain a SKILL.md entrypoint file.
Skill directories from this path will be symlinked to .claude/skills/.
'';
example = lib.literalExpression "./skills";
};
@ -516,7 +517,7 @@ in
recursive = true;
}
else
lib.nameValuePair ".claude/skills/${name}.md" (
lib.nameValuePair ".claude/skills/${name}/SKILL.md" (
if lib.isPath content then { source = content; } else { text = content; }
)
) cfg.skills;

View file

@ -26,6 +26,20 @@ in
package = lib.mkPackageOption pkgs "codex" { nullable = true; };
enableMcpIntegration = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to integrate the MCP server config from
{option}`programs.mcp.servers` into
{option}`programs.codex.settings.mcp_servers`.
Note: Settings defined in {option}`programs.mcp.servers` are merged
with {option}`programs.codex.settings.mcp_servers`, with settings-based
values taking precedence.
'';
};
settings = lib.mkOption {
# NOTE: `yaml` type supports null, using `nullOr` for backwards compatibility period
type = lib.types.nullOr tomlFormat.type;
@ -48,6 +62,15 @@ in
envKey = "OLLAMA_API_KEY";
};
};
mcp_servers = {
context7 = {
command = "npx";
args = [
"-y"
"@upstash/context7-mcp"
];
};
};
}
'';
};
@ -111,10 +134,36 @@ in
config =
let
useXdgDirectories = (config.home.preferXdgDirectories && isTomlConfig);
useXdgDirectories = config.home.preferXdgDirectories && isTomlConfig;
xdgConfigHome = lib.removePrefix config.home.homeDirectory config.xdg.configHome;
configDir = if useXdgDirectories then "${xdgConfigHome}/codex" else ".codex";
configFileName = if isTomlConfig then "config.toml" else "config.yaml";
transformedMcpServers = lib.optionalAttrs (cfg.enableMcpIntegration && config.programs.mcp.enable) (
lib.mapAttrs (
_name: server:
# NOTE: Convert shared programs.mcp fields to Codex config keys:
# - removeAttrs drops keys that Codex does not use directly
# - "disabled" becomes inverse "enabled"
# - "headers" is renamed to "http_headers"
# See: https://developers.openai.com/codex/mcp#other-configuration-options
(lib.removeAttrs server [
"disabled"
"headers"
])
// (lib.optionalAttrs (server ? headers && !(server ? http_headers)) {
http_headers = server.headers;
})
// {
enabled = !(server.disabled or false);
}
) config.programs.mcp.servers
);
settingMcpServers = lib.attrByPath [ "mcp_servers" ] { } cfg.settings;
mergedMcpServers = transformedMcpServers // settingMcpServers;
mergedSettings =
cfg.settings // lib.optionalAttrs (mergedMcpServers != { }) { mcp_servers = mergedMcpServers; };
in
mkIf cfg.enable {
assertions = [
@ -126,9 +175,10 @@ in
home = {
packages = mkIf (cfg.package != null) [ cfg.package ];
file = {
"${configDir}/${configFileName}" = lib.mkIf (cfg.settings != { }) {
source = settingsFormat.generate "codex-config" cfg.settings;
"${configDir}/${configFileName}" = lib.mkIf (mergedSettings != { }) {
source = settingsFormat.generate "codex-config" mergedSettings;
};
"${configDir}/AGENTS.md" = lib.mkIf (cfg.custom-instructions != "") {
text = cfg.custom-instructions;
@ -150,6 +200,7 @@ in
if lib.isPath content then { source = content; } else { text = content; }
)
) (if builtins.isAttrs cfg.skills then cfg.skills else { }));
sessionVariables = mkIf useXdgDirectories {
CODEX_HOME = "${config.xdg.configHome}/codex";
};

View file

@ -26,7 +26,6 @@ in
name = "Firefox";
wrappedPackageName = "firefox";
unwrappedPackageName = "firefox-unwrapped";
visible = true;
platforms.linux = {
configPath = ".mozilla/firefox";

View file

@ -5,7 +5,6 @@
wrappedPackageName ? null,
unwrappedPackageName ? null,
platforms,
visible ? false,
enableBookmarks ? true,
}:
{
@ -209,12 +208,10 @@ in
example = true;
description = ''
Whether to enable ${appName}.${optionalString (description != null) " ${description}"}
${optionalString (!visible) "See `${moduleName}` for more configuration options."}
'';
};
package = mkOption {
inherit visible;
type = with types; nullOr package;
default = pkgs.${defaultPackageName};
defaultText = literalExpression "pkgs.${packageName}";
@ -317,7 +314,6 @@ in
};
nativeMessagingHosts = mkOption {
inherit visible;
type = types.listOf types.package;
default = [ ];
description = ''
@ -327,14 +323,12 @@ in
};
finalPackage = mkOption {
inherit visible;
type = with types; nullOr package;
readOnly = true;
description = "Resulting ${appName} package.";
};
policies = lib.optionalAttrs (wrappedPackageName != null) (mkOption {
inherit visible;
type = types.attrsOf jsonFormat.type;
default = { };
description = "[See list of policies](https://mozilla.github.io/policy-templates/).";
@ -360,7 +354,6 @@ in
};
profiles = mkOption {
inherit visible;
type = types.attrsOf (
types.submodule (
{ config, name, ... }:
@ -555,6 +548,25 @@ in
description = "Declarative search engine configuration.";
};
handlers = mkOption {
type = types.submodule (
args:
import ./profiles/handlers.nix {
inherit (args) config;
inherit lib pkgs appName;
package = cfg.finalPackage;
modulePath = modulePath ++ [
"profiles"
name
"handlers"
];
profilePath = config.path;
}
);
default = { };
description = "Declarative handlers configuration for MIME types and URL schemes.";
};
containersForce = mkOption {
type = types.bool;
default = false;
@ -913,7 +925,6 @@ in
};
enableGnomeExtensions = mkOption {
inherit visible;
type = types.bool;
default = false;
description = ''
@ -1056,6 +1067,11 @@ in
source = profile.search.file;
};
"${cfg.profilesPath}/${profile.path}/handlers.json" = mkIf (profile.handlers.enable) {
source = profile.handlers.configFile;
force = profile.handlers.force;
};
"${cfg.profilesPath}/${profile.path}/extensions" = mkIf (profile.extensions.packages != [ ]) {
source =
let

View file

@ -0,0 +1,209 @@
{
config,
lib,
pkgs,
appName,
...
}:
let
jsonFormat = pkgs.formats.json { };
# Process configuration, remove null values and empty handlers arrays.
genCfg =
cfg:
lib.mapAttrs (
_: item:
(removeAttrs item [ "handlers" ])
// (lib.optionalAttrs (item.handlers != [ ]) {
handlers = map (handler: lib.filterAttrsRecursive (_: v: v != null) handler) item.handlers;
})
) cfg;
# Common options shared between mimeTypes and schemes
commonHandlerOptions = {
action = lib.mkOption {
type = lib.types.enum [
0
1
2
3
4
];
default = 1;
description = ''
The action to take for this MIME type / URL scheme. Possible values:
- 0: Save file
- 1: Always ask
- 2: Use helper app
- 3: Open in ${appName}
- 4: Use system default
'';
};
ask = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
If true, the user is asked what they want to do with the file.
If false, the action is taken without user intervention.
'';
};
handlers = lib.mkOption {
type = lib.types.listOf (
lib.types.submodule {
options = {
name = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Display name of the handler.
'';
};
path = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Path to the executable to be used.
Only one of 'path' or 'uriTemplate' should be set.
'';
};
uriTemplate = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
URI for the application handler.
Only one of 'path' or 'uriTemplate' should be set.
'';
};
};
}
);
default = [ ];
description = ''
An array of handlers with the first one being the default.
If you don't want to have a default handler, use an empty object for the first handler.
Only valid when action is set to 2 (Use helper app).
'';
};
};
in
{
imports = [ (pkgs.path + "/nixos/modules/misc/meta.nix") ];
meta.maintainers = with lib.maintainers; [ kugland ];
options = {
enable = lib.mkOption {
type = lib.types.bool;
default = config.schemes != { } || config.mimeTypes != { };
internal = true;
};
force = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to force replace the existing handlers configuration.
'';
};
mimeTypes = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
options = commonHandlerOptions // {
extensions = lib.mkOption {
type = lib.types.listOf (lib.types.strMatching "^[^\\.].+$");
default = [ ];
example = [
"jpg"
"jpeg"
];
description = ''
List of file extensions associated with this MIME type.
'';
};
};
}
);
default = { };
example = lib.literalExpression ''
{
"application/pdf" = {
action = 2;
ask = false;
handlers = [
{
name = "Okular";
path = "''${pkgs.okular}/bin/okular";
}
];
extensions = [ "pdf" ];
};
}
'';
description = ''
Attribute set mapping MIME types to their handler configurations.
For a configuration example, see [this file on Firefoxs source code](https://github.com/mozilla-firefox/firefox/blob/c3797cdebac1316dd7168e995e3468c5a597e8d1/uriloader/exthandler/tests/unit/handlers.json).
'';
};
schemes = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
options = commonHandlerOptions;
}
);
default = { };
example = lib.literalExpression ''
{
mailto = {
action = 2;
ask = false;
handlers = [
{
name = "Gmail";
uriTemplate = "https://mail.google.com/mail/?extsrc=mailto&url=%s";
}
];
};
}
'';
description = ''
Attribute set mapping URL schemes to their handler configurations.
For a configuration example, see [this file on Firefoxs source code](https://github.com/mozilla-firefox/firefox/blob/c3797cdebac1316dd7168e995e3468c5a597e8d1/uriloader/exthandler/tests/unit/handlers.json).
'';
};
finalSettings = lib.mkOption {
type = jsonFormat.type;
internal = true;
readOnly = true;
default = {
defaultHandlersVersion = { };
isDownloadsImprovementsAlreadyMigrated = false;
mimeTypes = genCfg config.mimeTypes;
schemes = genCfg config.schemes;
};
description = ''
Resulting handlers.json settings.
'';
};
configFile = lib.mkOption {
type = lib.types.path;
internal = true;
readOnly = true;
default = jsonFormat.generate "handlers.json" config.finalSettings;
description = ''
JSON representation of the handlers configuration.
'';
};
};
}

View file

@ -397,6 +397,20 @@ let
echo "end"
echo "setup_hm_session_vars") > $out/${sessionVarsFile}
'';
sourceHandlersStr =
let
handlerAttrs = [
"onJobExit"
"onProcessExit"
"onVariable"
"onSignal"
"onEvent"
];
isHandler = name: def: isAttrs def && builtins.any (attr: builtins.hasAttr attr def) handlerAttrs;
handlerFunctions = lib.filterAttrs isHandler cfg.functions;
sourceFunction = name: def: "source ${config.xdg.configHome}/fish/functions/${name}.fish";
in
builtins.concatStringsSep "\n" (lib.mapAttrsToList sourceFunction handlerFunctions);
in
{
@ -726,6 +740,9 @@ in
source ${cfg.sessionVariablesPackage}/${sessionVarsFile}
# Source handler functions
${sourceHandlersStr}
${cfg.shellInit}
status is-login; and begin

View file

@ -18,7 +18,6 @@ in
name = "Floorp";
wrappedPackageName = "floorp-bin";
unwrappedPackageName = "floorp-bin-unwrapped";
visible = true;
platforms.linux = {
configPath = ".floorp";

View file

@ -332,21 +332,43 @@ in
home.packages = lib.optionals (cfg.package != null) [ cfg.package ];
assertions = [
{
assertion =
let
enabled = [
(config.programs.delta.enable && config.programs.delta.enableGitIntegration)
(config.programs.diff-highlight.enable && config.programs.diff-highlight.enableGitIntegration)
(config.programs.diff-so-fancy.enable && config.programs.diff-so-fancy.enableGitIntegration)
(config.programs.difftastic.enable && config.programs.difftastic.git.enable)
(config.programs.patdiff.enable && config.programs.patdiff.enableGitIntegration)
(config.programs.riff.enable && config.programs.riff.enableGitIntegration)
];
in
lib.count lib.id enabled <= 1;
message = "Only one of 'programs.git.delta.enable' or 'programs.git.difftastic.enable' or 'programs.git.diff-so-fancy.enable' or 'programs.git.diff-highlight' or 'programs.git.patdiff' can be set to true at the same time.";
}
(
let
configOf =
{
name,
gitIntegrationOption ? [ "enableGitIntegration" ],
}:
{
name = "programs.${name}.${lib.concatStringsSep "." gitIntegrationOption}";
value =
config.programs.${name}.enable && lib.getAttrFromPath gitIntegrationOption config.programs.${name};
};
enabled = builtins.filter (x: x.value) (
map configOf [
{ name = "delta"; }
{ name = "diff-highlight"; }
{ name = "diff-so-fancy"; }
{
name = "difftastic";
gitIntegrationOption = [
"git"
"enable"
];
}
{ name = "patdiff"; }
{ name = "riff"; }
]
);
in
{
assertion = lib.length enabled <= 1;
message = ''
Only one of the following options can be enabled at a time.
- ${lib.concatStringsSep "\n - " (map (x: "`${x.name}'") enabled)}
'';
}
)
];
xdg.configFile = {
@ -380,7 +402,7 @@ in
lib.nameValuePair "sendemail.${name}" (
if account.msmtp.enable then
{
sendmailCmd = "${pkgs.msmtp}/bin/msmtp";
sendmailCmd = lib.getExe config.programs.msmtp.package;
envelopeSender = "auto";
from = "${realName} <${address}>";
}

View file

@ -36,7 +36,7 @@ in
};
description = ''
Configuration settings for halloy. All available options can be
found here: <https://halloy.chat/configuration/index.html>. Note that
found here: <https://halloy.chat/configuration.html>. Note that
halloy requires at least one `server` to be configured, see example.
'';
};

View file

@ -239,7 +239,7 @@ let
in
{
meta.maintainers = with lib.maintainers; [ thiagokokada ];
meta.maintainers = [ ];
options.programs.hexchat = {
enable = lib.mkEnableOption "HexChat, a graphical IRC client";

View file

@ -14,7 +14,6 @@ let
in
{
meta.maintainers = with lib.maintainers; [
thiagokokada
workflow
];

View file

@ -168,10 +168,52 @@ in
in `kitty-themes`, without the `.conf` suffix. See
<https://github.com/kovidgoyal/kitty-themes/tree/master/themes> for a
list of themes.
Note that if any automatic themes are configured via
`programs.kitty.autoThemeFiles`, Kitty will prefer them based on the
OS color scheme and they will override other color and background image
settings.
'';
example = "SpaceGray_Eighties";
};
autoThemeFiles = mkOption {
type = types.nullOr (
types.submodule {
options = {
light = mkOption {
type = types.str;
description = "Theme name for light color scheme.";
};
dark = mkOption {
type = types.str;
description = "Theme name for dark color scheme.";
};
noPreference = mkOption {
type = types.str;
description = "Theme name for no-preference color scheme.";
};
};
}
);
default = null;
description = ''
Configure Kitty automatic color themes. This creates
{file}`$XDG_CONFIG_HOME/kitty/light-theme.auto.conf`,
{file}`$XDG_CONFIG_HOME/kitty/dark-theme.auto.conf`, and
{file}`$XDG_CONFIG_HOME/kitty/no-preference-theme.auto.conf`.
Kitty applies these based on the OS color scheme, and they override
other color and background image settings.
'';
example = literalExpression ''
{
light = "GitHub";
dark = "TokyoNight";
noPreference = "OneDark";
}
'';
};
font = mkOption {
type = types.nullOr lib.hm.types.fontType;
default = null;
@ -358,15 +400,35 @@ in
'';
};
home.activation.checkKittyTheme = mkIf (cfg.themeFile != null) (
xdg.configFile."kitty/light-theme.auto.conf" = mkIf (cfg.autoThemeFiles != null) {
text = "include ${pkgs.kitty-themes}/share/kitty-themes/themes/${cfg.autoThemeFiles.light}.conf\n";
};
xdg.configFile."kitty/dark-theme.auto.conf" = mkIf (cfg.autoThemeFiles != null) {
text = "include ${pkgs.kitty-themes}/share/kitty-themes/themes/${cfg.autoThemeFiles.dark}.conf\n";
};
xdg.configFile."kitty/no-preference-theme.auto.conf" = mkIf (cfg.autoThemeFiles != null) {
text = "include ${pkgs.kitty-themes}/share/kitty-themes/themes/${cfg.autoThemeFiles.noPreference}.conf\n";
};
home.activation.checkKittyTheme = mkIf (cfg.themeFile != null || cfg.autoThemeFiles != null) (
let
themePath = "${pkgs.kitty-themes}/share/kitty-themes/themes/${cfg.themeFile}.conf";
themePath = name: "${pkgs.kitty-themes}/share/kitty-themes/themes/${name}.conf";
checkThemeFile = name: ''
if [[ ! -f "${themePath name}" ]]; then
errorEcho "kitty-themes does not contain the theme file ${themePath name}!"
exit 1
fi
'';
in
lib.hm.dag.entryBefore [ "writeBoundary" ] ''
if [[ ! -f "${themePath}" ]]; then
errorEcho "kitty-themes does not contain the theme file ${themePath}!"
exit 1
fi
${lib.optionalString (cfg.themeFile != null) (checkThemeFile cfg.themeFile)}
${lib.optionalString (cfg.autoThemeFiles != null) ''
${checkThemeFile cfg.autoThemeFiles.light}
${checkThemeFile cfg.autoThemeFiles.dark}
${checkThemeFile cfg.autoThemeFiles.noPreference}
''}
''
);

View file

@ -0,0 +1,48 @@
{
lib,
pkgs,
config,
...
}:
let
inherit (lib)
mkIf
mkEnableOption
mkPackageOption
mkOption
;
cfg = config.programs.lazyworktree;
yamlFormat = pkgs.formats.yaml { };
in
{
meta.maintainers = with lib.hm.maintainers; [ aguirre-matteo ];
options.programs.lazyworktree = {
enable = mkEnableOption "lazyworktree";
package = mkPackageOption pkgs "lazyworktree" { nullable = true; };
settings = mkOption {
inherit (yamlFormat) type;
default = { };
example = {
worktree_dir = "~/.local/share/worktrees";
sort_mode = "switched";
auto_fetch_prs = false;
auto_refresh = true;
refresh_interval = 10;
icon_set = "nerd-font-v3";
search_auto_select = false;
fuzzy_finder_input = false;
};
description = ''
Configuration settings for lazyworktree. All the available options can be found here:
<https://github.com/chmouel/lazyworktree?tab=readme-ov-file#global-configuration-yaml>
'';
};
};
config = mkIf cfg.enable {
home.packages = mkIf (cfg.package != null) [ cfg.package ];
xdg.configFile."lazyworktree/config.yaml" = mkIf (cfg.settings != { }) {
source = yamlFormat.generate "lazyworktree.yaml" cfg.settings;
};
};
}

View file

@ -34,7 +34,6 @@ in
description = "LibreWolf is a privacy enhanced Firefox fork.";
wrappedPackageName = "librewolf";
unwrappedPackageName = "librewolf-unwrapped";
visible = true;
platforms.linux = {
configPath = ".librewolf";

View file

@ -21,7 +21,18 @@ in
'';
};
package = lib.mkPackageOption pkgs "man" { };
package = mkOption {
type = with types; nullOr package;
default =
if pkgs.stdenv.isDarwin && lib.versionAtLeast config.home.stateVersion "26.05" then
null
else
pkgs.man;
defaultText = lib.literalExpression ''
if pkgs.stdenv.isDarwin && lib.versionAtLeast config.home.stateVersion "26.05" then null else pkgs.man
'';
description = "The {command}`man` package to use.";
};
extraConfig = mkOption {
type = types.lines;
@ -51,11 +62,15 @@ in
};
config = lib.mkIf cfg.enable {
home.packages = [ cfg.package ];
warnings = lib.optional (
cfg.generateCaches && cfg.package == null
) "programs.man.generateCaches has no effect when programs.man.package is null";
home.packages = lib.optional (cfg.package != null) cfg.package;
home.extraOutputsToInstall = [ "man" ];
# This is mostly copy/pasted/adapted from NixOS' documentation.nix.
home.file = lib.mkIf cfg.generateCaches {
home.file = lib.mkIf (cfg.generateCaches && cfg.package != null) {
".manpath".text =
let
# Generate a directory containing installed packages' manpages.

View file

@ -0,0 +1,64 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.mistral-vibe;
settingsFormat = pkgs.formats.toml { };
in
{
meta.maintainers = [ lib.maintainers.GaetanLepage ];
options.programs.mistral-vibe = {
enable = lib.mkEnableOption "Mistral Vibe, Mistral's open-source CLI coding assistant";
package = lib.mkPackageOption pkgs "mistral-vibe" { nullable = true; };
settings = lib.mkOption {
type = settingsFormat.type;
example = lib.literalExpression ''
{
active_model = "devstral-latest";
vim_keybindings = false;
tool_paths = [];
providers = [
{
name = "mistral";
backend = "mistral";
api_base = "https://api.mistral.ai/v1";
api_key_env_var = "MISTRAL_API_KEY";
api_style = "openai";
}
];
models = [
{
name = "devstral-latest";
provider = "mistral";
alias = "devstral-latest";
temperature = 0.1;
input_price = 0.4;
output_price = 2.0;
}
];
}
'';
description = ''
Mistral Vibe configuration.
For available settings see <https://github.com/mistralai/mistral-vibe>.
'';
};
};
config = lib.mkIf cfg.enable {
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
home.file.".vibe/config.toml".source = settingsFormat.generate "config.toml" cfg.settings;
};
}

View file

@ -67,7 +67,6 @@ let
in
{
meta.maintainers = with lib.maintainers; [
thiagokokada
chuangzhu
];
@ -139,11 +138,14 @@ in
default = [ ];
example = literalExpression ''
[
"~/path/to/config.inc";
"~/path/to/conditional.inc";
"~/path/to/config.inc"
"~~/conditional.inc"
]
'';
description = "List of configuration files to include at the end of mpv.conf.";
description = ''
List of configuration files to include at the end of mpv.conf.
Mpv accepts several useful [prefixes](https://mpv.io/manual/stable/#paths).
'';
};
profiles = mkOption {

View file

@ -49,7 +49,7 @@ let
};
in
{
meta.maintainers = with lib.maintainers; [ thiagokokada ];
meta.maintainers = [ ];
options = {
programs.nnn = {
@ -100,6 +100,14 @@ in
'';
default = { };
};
enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { inherit config; };
enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { inherit config; };
enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; };
quitcd = lib.mkEnableOption "cd on quit";
};
};
@ -116,10 +124,25 @@ in
--prefix NNN_PLUG : "${renderSettings cfg.plugins.mappings}"
'';
});
quitcd = {
bash_sh_zsh = "source ${nnnPackage}/share/quitcd/quitcd.bash_sh_zsh";
fish = "source ${nnnPackage}/share/quitcd/quitcd.fish";
};
in
lib.mkIf cfg.enable {
programs.nnn.finalPackage = nnnPackage;
home.packages = [ nnnPackage ];
xdg.configFile."nnn/plugins" = lib.mkIf (cfg.plugins.src != null) { source = cfg.plugins.src; };
programs.bash.initExtra = lib.mkIf (cfg.enableBashIntegration && cfg.quitcd) (
lib.mkAfter quitcd.bash_sh_zsh
);
programs.fish.interactiveShellInit = lib.mkIf (cfg.enableFishIntegration && cfg.quitcd) (
lib.mkAfter quitcd.fish
);
programs.zsh.initContent = lib.mkIf (cfg.enableZshIntegration && cfg.quitcd) (
lib.mkAfter quitcd.bash_sh_zsh
);
};
}

View file

@ -72,6 +72,8 @@ in
programs.notmuch = {
enable = lib.mkEnableOption "Notmuch mail indexer";
package = lib.mkPackageOption pkgs "notmuch" { };
new = mkOption {
type = types.submodule {
options = {
@ -197,7 +199,7 @@ in
}
];
home.packages = [ pkgs.notmuch ];
home.packages = [ cfg.package ];
home.sessionVariables = {
NOTMUCH_CONFIG = "${config.xdg.configHome}/notmuch/default/config";
@ -208,7 +210,7 @@ in
let
hook = name: cmds: {
"notmuch/default/hooks/${name}".source = pkgs.writeShellScript name ''
export PATH="${pkgs.notmuch}/bin''${PATH:+:}$PATH"
export PATH="${cfg.package}/bin''${PATH:+:}$PATH"
export NOTMUCH_CONFIG="${config.xdg.configHome}/notmuch/default/config"
export NMBGIT="${config.xdg.dataHome}/notmuch/nmbug"

View file

@ -6,8 +6,8 @@
}:
let
cfg = config.programs.pay-respects;
payRespectsCmd = lib.getExe cfg.package;
cfgOptions = lib.concatStringsSep " " cfg.options;
tomlFormat = pkgs.formats.toml { };
in
{
meta.maintainers = [ lib.maintainers.ALameLlama ];
@ -29,6 +29,49 @@ in
'';
};
rules = lib.mkOption {
type = lib.types.attrsOf tomlFormat.type;
default = { };
example = lib.literalExpression ''
{
cargo = {
command = "cargo";
match_err = [
{
pattern = [ "run `cargo init` to initialize a new rust project" ];
suggest = [ "cargo init" ];
}
];
};
_PR_GENERAL = {
match_err = [
{
pattern = [ "permission denied" ];
suggest = [
"#[executable(sudo), !cmd_contains(sudo)]\nsudo {{command}}"
];
}
];
};
}
'';
description = ''
Runtime rule files written to
{file}`$XDG_CONFIG_HOME/pay-respects/rules/<name>.toml`.
Attribute names map to filenames. For example, setting `rules.cargo = { ... };`
creates {file}`$XDG_CONFIG_HOME/pay-respects/rules/cargo.toml`.
The filename must match the command name, except for `_PR_GENERAL`.
See <https://github.com/iffse/pay-respects/blob/main/rules.md>
for runtime rule syntax and behavior.
Note that these rules are only applied when the runtime-rules module is
available to `pay-respects`.
'';
};
enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { inherit config; };
enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { inherit config; };
@ -41,26 +84,38 @@ in
config = lib.mkIf cfg.enable {
home.packages = [ cfg.package ];
programs = {
bash.initExtra = lib.mkIf cfg.enableBashIntegration ''
eval "$(${payRespectsCmd} bash ${cfgOptions})"
'';
xdg.configFile = lib.mapAttrs' (
name: rule:
lib.nameValuePair "pay-respects/rules/${name}.toml" {
source = tomlFormat.generate "pay-respects-rule-${name}.toml" rule;
}
) cfg.rules;
zsh.initContent = lib.mkIf cfg.enableZshIntegration ''
eval "$(${payRespectsCmd} zsh ${cfgOptions})"
'';
programs =
let
payRespectsCmd = lib.getExe cfg.package;
cfgOptions = lib.concatStringsSep " " cfg.options;
in
{
bash.initExtra = lib.mkIf cfg.enableBashIntegration ''
eval "$(${payRespectsCmd} bash ${cfgOptions})"
'';
fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration ''
${payRespectsCmd} fish ${cfgOptions} | source
'';
zsh.initContent = lib.mkIf cfg.enableZshIntegration ''
eval "$(${payRespectsCmd} zsh ${cfgOptions})"
'';
nushell.extraConfig = lib.mkIf cfg.enableNushellIntegration ''
source ${
pkgs.runCommand "pay-respects-nushell-config.nu" { } ''
${payRespectsCmd} nushell ${cfgOptions} >> "$out"
''
}
'';
};
fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration ''
${payRespectsCmd} fish ${cfgOptions} | source
'';
nushell.extraConfig = lib.mkIf cfg.enableNushellIntegration ''
source ${
pkgs.runCommand "pay-respects-nushell-config.nu" { } ''
${payRespectsCmd} nushell ${cfgOptions} >> "$out"
''
}
'';
};
};
}

View file

@ -0,0 +1,112 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (pkgs.stdenv.hostPlatform) isDarwin;
inherit (lib)
escapeShellArg
listToAttrs
literalExpression
mkIf
mkOption
types
;
cfg = config.programs.prismlauncher;
iniFormat = pkgs.formats.ini { };
in
{
meta.maintainers = with lib.hm.maintainers; [
mikaeladev
];
options.programs.prismlauncher = {
enable = lib.mkEnableOption "Prism Launcher";
package = lib.mkPackageOption pkgs "prismlauncher" { nullable = true; };
extraPackages = mkOption {
type = types.listOf types.package;
default = [ ];
description = ''
Additional theme packages to install to the user environment.
Themes can be sourced from <https://github.com/PrismLauncher/Themes> and should
install to `$out/share/PrismLauncher/{themes,iconthemes,catpacks}`.
'';
};
icons = mkOption {
type = types.listOf types.path;
default = [ ];
example = literalExpression "[ ./java.png ]";
description = ''
List of paths to instance icons.
These will be linked in {file}`$XDG_DATA_HOME/PrismLauncher/icons` on Linux and
{file}`~/Library/Application Support/PrismLauncher/icons` on macOS.
'';
};
settings = mkOption {
type = types.attrsOf iniFormat.lib.types.atom;
default = { };
example = {
ShowConsole = true;
ConsoleMaxLines = 100000;
};
description = ''
Configuration written to {file}`prismlauncher.cfg`.
'';
};
};
config =
let
dataDir =
if (isDarwin && !config.xdg.enable) then
"Library/Application Support/PrismLauncher"
else
"${config.xdg.dataHome}/PrismLauncher";
impureConfigMerger = filePath: staticSettingsFile: emptySettingsFile: ''
mkdir -p $(dirname '${escapeShellArg filePath}')
if [ ! -e '${escapeShellArg filePath}' ]; then
cat '${escapeShellArg emptySettingsFile}' > '${escapeShellArg filePath}'
fi
${lib.getExe pkgs.crudini} --merge --ini-options=nospace \
'${escapeShellArg filePath}' < '${escapeShellArg staticSettingsFile}'
'';
in
mkIf cfg.enable {
home = {
packages = lib.mkMerge ([ (mkIf (cfg.package != null) [ cfg.package ]) ] ++ cfg.extraPackages);
activation = lib.mkIf (cfg.settings != { }) {
prismlauncherConfigActivation = lib.hm.dag.entryAfter [ "linkGeneration" ] (
impureConfigMerger "${dataDir}/prismlauncher.cfg" (iniFormat.generate "prismlauncher-static.cfg" {
General = cfg.settings;
}) (iniFormat.generate "prismlauncher-empty.cfg" { General = { }; })
);
};
file = mkIf (cfg.icons != [ ]) (
listToAttrs (
map (source: {
name = "${dataDir}/icons/${baseNameOf source}";
value = { inherit source; };
}) cfg.icons
)
);
};
};
}

View file

@ -136,7 +136,13 @@ in
node = {
alias = mkOption {
type = str;
description = "Human readable alias for your node.";
description = ''
Human readable alias for your node.
When running 'rad auth' for the first time, you need to use the exact same alias,
otherwise 'rad auth' will fail because it cannot write the configuration
file in your home directory (which is generated by nix).
'';
default = config.home.username;
defaultText = lib.literalExpression "config.home.username";
};

View file

@ -0,0 +1,52 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.rizin;
in
{
meta.maintainers = [
lib.hm.maintainers.rsahwe
];
options = {
programs.rizin = {
enable = lib.mkEnableOption "Rizin";
package = lib.mkPackageOption pkgs "rizin" { nullable = true; };
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
example = ''
e asm.bytes=true
e asm.bytes.space=true
'';
description = ''
Run configuration written to {file}`rizinrc`.
See <https://book.rizin.re/src/configuration/initial_scripts.html>
for more information.
'';
};
};
};
config =
let
configFile =
if config.xdg.enable && config.home.preferXdgDirectories then
"${config.xdg.configHome}/rizin/rizinrc"
else
".rizinrc";
in
lib.mkIf cfg.enable {
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
home.file.${configFile} = lib.mkIf (cfg.extraConfig != "") {
text = cfg.extraConfig;
};
};
}

View file

@ -275,8 +275,14 @@ in
listOf (
either str (submodule {
options = {
name = mkOption { type = str; };
path = mkOption { type = str; };
name = mkOption {
type = str;
description = "Name used to reference the custom mode in the mode list.";
};
path = mkOption {
type = str;
description = "Executable path for the custom rofi script mode.";
};
};
})
);

View file

@ -18,7 +18,6 @@ let
mkKeyValue = key: value: "${key} ${value}";
listsAsDuplicateKeys = true;
};
in
{
meta.maintainers = [ lib.maintainers.podocarp ];
@ -58,24 +57,58 @@ in
{file}`$XDG_CONFIG_HOME/sioyek/prefs_user.config`.
See <https://github.com/ahrm/sioyek/blob/main/pdf_viewer/prefs.config>.
'';
type = types.attrsOf types.str;
default = { };
example = literalExpression ''
{
"background_color" = "1.0 1.0 1.0";
"text_highlight_color" = "1.0 0.0 0.0";
startup_commands = [
"toggle_visual_scroll"
"toggle_dark_mode"
];
}
'';
};
type = types.submodule {
freeformType = types.attrsOf types.str;
options.startup_commands = mkOption {
description = ''
Commands to be run upon startup. Will be written to {file}`$XDG_CONFIG_HOME/sioyek/prefs_user.config`.
See <https://github.com/ahrm/sioyek/blob/a4ce95fd968804fbf6ff3befcbe0d9b972bd754c/pdf_viewer/prefs.config#L116>.
'';
type = types.either types.str (types.listOf types.str);
apply =
x:
lib.warnIf (lib.isString x)
"`programs.sioyek.config.startup_commands` should now be a list of strings instead of a string."
x;
default = [ ];
example = [
"toggle_visual_scroll"
"toggle_dark_mode"
];
};
};
};
};
};
config = mkIf cfg.enable (
let
prefsCfg =
cfg.config
//
lib.optionalAttrs (cfg.config.startup_commands != [ ] && !lib.isString cfg.config.startup_commands)
{
startup_commands = lib.concatStringsSep ";" cfg.config.startup_commands;
};
in
lib.mkMerge [
{ home.packages = [ cfg.package ]; }
(mkIf (cfg.config != { }) {
xdg.configFile."sioyek/prefs_user.config".text = renderConfig cfg.config;
{
home.packages = [ cfg.package ];
}
(mkIf (prefsCfg != { }) {
xdg.configFile."sioyek/prefs_user.config".text = renderConfig prefsCfg;
})
(mkIf (cfg.bindings != { }) {
xdg.configFile."sioyek/keys_user.config".text = renderConfig cfg.bindings;

View file

@ -0,0 +1,84 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.tirith;
yamlFormat = pkgs.formats.yaml { };
in
{
meta.maintainers = with lib.maintainers; [ malik ];
options.programs.tirith = {
enable = lib.mkEnableOption "Tirith, a shell security monitor";
package = lib.mkPackageOption pkgs "tirith" { };
allowlist = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
apply = builtins.filter (s: s != "");
example = [
"localhost"
];
description = ''
List of allowed domains that bypass Tirith analysis.
Written to `$XDG_CONFIG_HOME/tirith/allowlist`.
'';
};
policy = lib.mkOption {
type = yamlFormat.type;
default = { };
example = lib.literalExpression ''
{
version = 1;
fail_mode = "open";
allow_bypass = true;
severity_overrides = {
docker_untrusted_registry = "CRITICAL";
};
}
'';
description = ''
Tirith policy configuration.
Written to `$XDG_CONFIG_HOME/tirith/policy.yaml`.
See <https://github.com/sheeki03/tirith/blob/main/docs/cookbook.md>
for policy examples.
'';
};
enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { inherit config; };
enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { inherit config; };
enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; };
};
config = lib.mkIf cfg.enable {
home.packages = [ cfg.package ];
xdg.configFile = {
"tirith/allowlist" = lib.mkIf (cfg.allowlist != [ ]) {
text = (lib.concatStringsSep "\n" cfg.allowlist) + "\n";
};
"tirith/policy.yaml" = lib.mkIf (cfg.policy != { }) {
source = yamlFormat.generate "tirith-policy.yaml" cfg.policy;
};
};
programs.bash.initExtra = lib.mkIf cfg.enableBashIntegration ''
eval "$(${lib.getExe cfg.package} init --shell bash)"
'';
programs.fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration ''
${lib.getExe cfg.package} init --shell fish | source
'';
programs.zsh.initExtra = lib.mkIf cfg.enableZshIntegration ''
eval "$(${lib.getExe cfg.package} init --shell zsh)"
'';
};
}

View file

@ -92,7 +92,7 @@ let
# rebind main key: ${prefix}
unbind ${defaultPrefix}
set -g prefix ${prefix}
bind -n -N "Send the prefix key through to the application" \
bind -N "Send the prefix key through to the application" \
${prefix} send-prefix
''
}

View file

@ -17,8 +17,11 @@ let
mkBashIntegrationOption
mkZshIntegrationOption
mkFishIntegrationOption
mkNushellIntegrationOption
;
inherit (lib.hm.nushell) mkNushellInline;
cfg = config.programs.vivid;
yamlFormat = pkgs.formats.yaml { };
in
@ -35,6 +38,7 @@ in
enableBashIntegration = mkBashIntegrationOption { inherit config; };
enableZshIntegration = mkZshIntegrationOption { inherit config; };
enableFishIntegration = mkFishIntegrationOption { inherit config; };
enableNushellIntegration = mkNushellIntegrationOption { inherit config; };
colorMode = mkOption {
type =
@ -160,5 +164,9 @@ in
programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration ''
set -gx LS_COLORS "$(${vividCommand})"
'';
programs.nushell.environmentVariables = mkIf cfg.enableNushellIntegration {
LS_COLORS = mkNushellInline vividCommand;
};
};
}

View file

@ -48,8 +48,23 @@ in
shellWrapperName = lib.mkOption {
type = types.str;
default = "yy";
example = "y";
default =
if lib.versionAtLeast config.home.stateVersion "26.05" then
"y"
else
lib.warn ''
The default value of `programs.yazi.shellWrapperName` has changed from `yy` to `y`.
You are currently using the legacy default (`yy`) because `home.stateVersion` is less than "26.05".
To silence this warning and keep legacy behavior, set:
programs.yazi.shellWrapperName = "yy";
To adopt the new default behavior, set:
programs.yazi.shellWrapperName = "y";
'' "yy";
defaultText = literalExpression ''
"y" for state version 26.05
"yy" for state version < 26.05
'';
example = "yy";
description = ''
Name of the shell wrapper to be called.
'';

View file

@ -304,7 +304,7 @@ in
(mkIf (!cfg.mutableUserSettings && mergedSettings != { }) {
"zed/settings.json".source = jsonFormat.generate "zed-user-settings" mergedSettings;
})
(mkIf (!cfg.mutableUserKeymaps && cfg.userKeymaps != { }) {
(mkIf (!cfg.mutableUserKeymaps && cfg.userKeymaps != [ ]) {
"zed/keymap.json".source = jsonFormat.generate "zed-user-keymaps" cfg.userKeymaps;
})
(mkIf (!cfg.mutableUserTasks && cfg.userTasks != [ ]) {

View file

@ -478,7 +478,10 @@ in
}
{
home.packages = [ cfg.package ] ++ lib.optional cfg.enableCompletion pkgs.nix-zsh-completions;
home.packages = [
cfg.package
]
++ lib.optional cfg.enableCompletion (lib.lowPrio pkgs.nix-zsh-completions);
# NOTE: Always include "main" highlighter with normal priority.
# Option default priority will cause `main` to get dropped by customization.

View file

@ -202,7 +202,9 @@ in
"--activate=${if profile.isActive then "true" else "false"}"
"--save-config=false"
];
KeepAlive = true;
KeepAlive = {
SuccessfulExit = true;
};
RunAtLoad = true;
EnvironmentVariables.PATH = lib.makeBinPath [
cfg.package

View file

@ -39,10 +39,6 @@ in
};
config = lib.mkIf cfg.enable {
assertions = [
(lib.hm.assertions.assertPlatform "services.flameshot" pkgs lib.platforms.linux)
];
home.packages = [ cfg.package ];
xdg.configFile = lib.mkIf (cfg.settings != { }) {
@ -67,7 +63,7 @@ in
Service = {
Environment = [ "PATH=${config.home.profileDirectory}/bin" ];
ExecStart = "${cfg.package}/bin/flameshot";
ExecStart = lib.getExe cfg.package;
Restart = "on-abort";
# Sandboxing.
@ -80,5 +76,18 @@ in
SystemCallFilter = "@system-service";
};
};
launchd.agents.flameshot = {
enable = true;
config = {
ProgramArguments = [ (lib.getExe cfg.package) ];
KeepAlive = {
Crashed = true;
SuccessfulExit = false;
};
ProcessType = "Interactive";
RunAtLoad = true;
};
};
};
}

View file

@ -100,11 +100,11 @@ in
default = with pkgs; [
xdotool
coreutils
xorg.xprop
xprop
];
defaultText = literalExpression "pkgs.xdotool pkgs.coreutils pkgs.xorg.xprop";
defaultText = literalExpression "pkgs.xdotool pkgs.coreutils pkgs.xprop";
example = literalExpression ''
with pkgs; [ xdotool coreutils xorg.xprop ];
with pkgs; [ xdotool coreutils xprop ];
'';
description = ''
Extra packages needs to bring to the scope of fusuma service.

View file

@ -45,7 +45,7 @@ in
primary = true;
atomic = true;
execute_after = [
"''${pkgs.xorg.xrandr}/bin/xrandr --dpi 96"
"''${lib.getExe pkgs.xrandr} --dpi 96"
"''${pkgs.xmonad-with-packages}/bin/xmonad --restart";
];
}
@ -56,7 +56,7 @@ in
primary = true;
atomic = true;
execute_after = [
"''${pkgs.xorg.xrandr}/bin/xrandr --dpi 120"
"''${lib.getExe pkgs.xrandr} --dpi 120"
"''${pkgs.xmonad-with-packages}/bin/xmonad --restart";
];
}
@ -92,7 +92,7 @@ in
ExecStart = "${lib.getExe cfg.package} watch -v";
Restart = "always";
RestartSec = "2s";
Environment = [ "PATH=${pkgs.xorg.xrandr}/bin:${pkgs.bash}/bin" ];
Environment = [ "PATH=${pkgs.xrandr}/bin:${pkgs.bash}/bin" ];
};
Install = {

View file

@ -161,7 +161,7 @@ in
};
}
(mkIf (!cfg.xautolock.enable) {
systemd.user.services.xss-lock.Service.ExecStartPre = "${pkgs.xorg.xset}/bin/xset s ${
systemd.user.services.xss-lock.Service.ExecStartPre = "${lib.getExe pkgs.xset} s ${
toString (cfg.inactiveInterval * 60)
} ${toString cfg.xss-lock.screensaverCycle}";
})

View file

@ -825,40 +825,37 @@ in
};
};
launchd.agents =
let
# agent `syncthing` uses `${syncthing_dir}/${watch_file}` to notify agent `syncthing-init`
watch_file = ".launchd_update_config";
in
{
syncthing = {
enable = true;
config = {
ProgramArguments = [
"${pkgs.writers.writeBash "syncthing-wrapper" ''
${copyKeys} # simulate systemd's `syncthing-init.Service.ExecStartPre`
touch "${syncthing_dir}/${watch_file}" # notify syncthing-init agent
exec ${lib.escapeShellArgs syncthingArgs}
''}"
];
KeepAlive = {
Crashed = true;
SuccessfulExit = false;
};
ProcessType = "Background";
};
};
syncthing-init = {
enable = cleanedConfig != { };
config = {
ProgramArguments = [ "${updateConfig}" ];
WatchPaths = [
"${config.home.homeDirectory}/Library/Application Support/Syncthing/${watch_file}"
];
launchd.agents = {
syncthing = {
enable = true;
config = {
ProgramArguments = [
"${pkgs.writers.writeBash "syncthing-wrapper" ''
${copyKeys} # simulate systemd's `syncthing-init.Service.ExecStartPre`
exec ${lib.escapeShellArgs syncthingArgs}
''}"
];
KeepAlive = {
Crashed = true;
SuccessfulExit = false;
};
ProcessType = "Background";
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/Syncthing/syncthing-stdout.log";
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/Syncthing/syncthing-stderr.log";
};
};
syncthing-init = {
enable = cleanedConfig != { };
config = {
ProgramArguments = [ "${updateConfig}" ];
ProcessType = "Background";
RunAtLoad = true;
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/Syncthing/syncthing-init-stdout.log";
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/Syncthing/syncthing-init-stderr.log";
};
};
};
})
(lib.mkIf cfg.tray.enable {

View file

@ -57,17 +57,19 @@ in
systemd.user.services.tomat = {
Unit = {
Description = "Tomat Pomodoro server";
After = [ "graphical.target" ];
After = [ "graphical-session.target" ];
PartOf = [ "graphical-session.target" ];
};
Service = {
ExecStart = "${lib.getExe cfg.package} daemon run";
Restart = "always";
RestartSec = 5;
Environment = [ "PATH=${config.home.profileDirectory}/bin" ];
};
Install = {
WantedBy = [ "default.target" ];
WantedBy = [ "graphical-session.target" ];
};
};
};

View file

@ -113,7 +113,7 @@ let
in
{
meta.maintainers = [ lib.maintainers.offline ];
meta.maintainers = [ ];
options = {
services.xsuspender = {

View file

@ -112,7 +112,7 @@ in
in
{
NIX_PATH =
if config.nix.enable && (config.nix.settings.use-xdg-base-directories or false) then
if config.nix.useXdg then
"${config.xdg.stateHome}/nix/defexpr/channels\${NIX_PATH:+:}$NIX_PATH"
else
"$HOME/.nix-defexpr/channels\${NIX_PATH:+:}$NIX_PATH";

View file

@ -31,7 +31,7 @@ let
in
"${n}: ${formatValue v}";
xrdbMerge = "${pkgs.xorg.xrdb}/bin/xrdb -merge ${cfg.path}";
xrdbMerge = "${lib.getExe pkgs.xrdb} -merge ${cfg.path}";
in
{

View file

@ -150,7 +150,7 @@ in
++ [ "-option ''" ]
++ map (v: "-option '${v}'") options;
in
"${pkgs.xorg.setxkbmap}/bin/setxkbmap ${toString args}";
"${lib.getExe pkgs.setxkbmap} ${toString args}";
};
};

View file

@ -50,6 +50,7 @@ let
"eza"
"fastfetch"
"feh"
"flameshot"
"fzf"
"gallery-dl"
"getconf"
@ -103,6 +104,7 @@ let
"mergiraf"
"micro"
"mise"
"mistral-vibe"
"mpv"
"msmtp"
"mu"

View file

@ -64,9 +64,8 @@ let
# Needed by pretty much all tests that have anything to do with fish.
babelfish
fish
lndir
;
xorg = super.xorg.overrideScope (self: super: { inherit (pkgs.xorg) lndir; });
};
outer =

View file

@ -1,169 +0,0 @@
# This is an internal Nix Flake intended for use when running tests.
#
# You can build all tests or specific tests by running
#
# nix build --reference-lock-file flake.lock ./tests#test-all
# nix build --reference-lock-file flake.lock ./tests#test-alacritty-empty-settings
#
# in the Home Manager project root directory.
#
# Similarly for integration tests
#
# nix build --reference-lock-file flake.lock ./tests#integration-test-all
# nix build --reference-lock-file flake.lock ./tests#integration-test-standalone-standard-basics
{
description = "Tests of Home Manager for Nix";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs =
{ nixpkgs, ... }:
let
forAllSystems = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed;
forCI = nixpkgs.lib.genAttrs [
"aarch64-darwin"
"x86_64-linux"
];
testChunks =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
# Create chunked test packages for better CI parallelization
tests = import ./. {
inherit pkgs;
# Disable big tests since this is only used for CI
enableBig = false;
};
allTests = lib.attrNames tests.build;
# Remove 'all' from the test list as it's a meta-package
filteredTests = lib.filter (name: name != "all") allTests;
# NOTE: Just a starting value, we can tweak this to find a good value.
targetTestsPerChunk = 50;
numChunks = lib.max 1 (
builtins.ceil ((builtins.length filteredTests) / (targetTestsPerChunk * 1.0))
);
chunkSize = builtins.ceil ((builtins.length filteredTests) / (numChunks * 1.0));
makeChunk =
chunkNum: testList:
let
start = (chunkNum - 1) * chunkSize;
end = lib.min (start + chunkSize) (builtins.length testList);
chunkTests = lib.sublist start (end - start) testList;
chunkAttrs = lib.genAttrs chunkTests (name: tests.build.${name});
in
pkgs.symlinkJoin {
name = "test-chunk-${toString chunkNum}";
paths = lib.attrValues chunkAttrs;
passthru.tests = chunkTests;
};
in
lib.listToAttrs (
lib.genList (
i: lib.nameValuePair "test-chunk-${toString (i + 1)}" (makeChunk (i + 1) filteredTests)
) numChunks
);
integrationTests =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
in
lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux (
let
tests = import ./integration { inherit pkgs lib; };
renameTestPkg = n: v: lib.nameValuePair "integration-${n}" v;
in
lib.mapAttrs' renameTestPkg (lib.removeAttrs tests [ "all" ])
);
# Test group definitions
buildTests =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
tests = import ./. { inherit pkgs; };
renameTestPkg = n: nixpkgs.lib.nameValuePair "test-${n}";
in
nixpkgs.lib.mapAttrs' renameTestPkg tests.build;
buildTestsNoBig =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
tests = import ./. {
inherit pkgs;
enableBig = false;
};
in
{
test-all-enableBig-false-enableLegacyIfd-false = tests.build.all;
};
buildTestsNoBigIfd =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
tests = import ./. {
inherit pkgs;
enableBig = false;
enableLegacyIfd = true;
};
in
{
test-all-enableBig-false-enableLegacyIfd-true = tests.build.all;
};
integrationTestPackages =
system:
let
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) lib;
tests = import ./integration { inherit pkgs lib; };
renameTestPkg = n: lib.nameValuePair "integration-test-${n}";
in
lib.mapAttrs' renameTestPkg tests;
in
{
# TODO: increase buildbot testing scope
buildbot = forCI (
system:
let
allIntegrationTests = integrationTests system;
workingIntegrationTests = nixpkgs.lib.filterAttrs (
name: _:
nixpkgs.lib.elem name [
"integration-nixos-basics"
"integration-nixos-legacy-profile-management"
]
) allIntegrationTests;
in
(testChunks system) // workingIntegrationTests
);
devShells = forAllSystems (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
tests = import ./. { inherit pkgs; };
in
tests.run
);
packages = forAllSystems (
system:
(buildTests system)
// (integrationTestPackages system)
// (buildTestsNoBig system)
// (buildTestsNoBigIfd system)
// (testChunks system)
// (integrationTests system)
);
};
}

View file

@ -0,0 +1,17 @@
{
home.username = "alice";
home.homeDirectory = "/home/alice";
home.stateVersion = "24.11";
# Let Home Manager install and manage itself.
programs.home-manager.enable = true;
programs.kitty = {
enable = true;
autoThemeFiles = {
light = "GitHub";
dark = "No Such Theme";
noPreference = "OneDark";
};
};
}

View file

@ -59,6 +59,14 @@
assert expected in actual, \
f"expected home-manager switch to contain {expected}, but got {actual}"
with subtest("Switch to Bad Kitty Auto Theme"):
succeed_as_alice("cp ${./kitty-auto-theme-bad-home.nix} /home/alice/.config/home-manager/home.nix")
actual = fail_as_alice("home-manager switch")
expected = "kitty-themes does not contain the theme file"
assert expected in actual, \
f"expected home-manager switch to contain {expected}, but got {actual}"
with subtest("Switch to Good Kitty"):
succeed_as_alice("cp ${./kitty-theme-good-home.nix} /home/alice/.config/home-manager/home.nix")

View file

@ -2,5 +2,7 @@
lib-types-dag-submodule = ./dag-submodule.nix;
lib-types-dag-merge = ./dag-merge.nix;
lib-types-either-suboptions-docs-lib = ./either-suboptions-docs-lib.nix;
lib-types-gvariant-merge = ./gvariant-merge.nix;
}

View file

@ -0,0 +1,49 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib) mkOption;
docs = import ../../../docs {
inherit pkgs lib;
inherit (config.home.version) release isReleaseBranch;
};
inherit (docs._internal.docsLib) types;
scalarOrSubmodule = types.either types.str (
types.submodule {
options = {
foo = mkOption { type = types.str; };
bar = mkOption { type = types.int; };
};
}
);
scalarOrSubmoduleSubOptions = scalarOrSubmodule.getSubOptions [ ];
nullOrScalarOrSubmoduleSubOptions = (types.nullOr scalarOrSubmodule).getSubOptions [ ];
in
{
assertions = [
{
assertion = scalarOrSubmoduleSubOptions ? foo;
message = "docsLib.types.either should expose submodule options when one side is scalar.";
}
{
assertion = scalarOrSubmoduleSubOptions ? bar;
message = "docsLib.types.either should expose all submodule options when one side is scalar.";
}
{
assertion = nullOrScalarOrSubmoduleSubOptions ? foo;
message = "docsLib.types.nullOr (types.either ...) should keep submodule options visible.";
}
{
assertion = nullOrScalarOrSubmoduleSubOptions ? bar;
message = "docsLib.types.nullOr (types.either ...) should keep all submodule options visible.";
}
];
}

View file

@ -5,4 +5,5 @@
nix-keep-old-nix-path = ./keep-old-nix-path.nix;
nix-example-channels = ./example-channels.nix;
nix-example-channels-xdg = ./example-channels-xdg.nix;
nix-use-xdg = ./use-xdg.nix;
}

View file

@ -0,0 +1,92 @@
{ lib, pkgs, ... }:
let
nixosLib = import /${pkgs.path}/nixos/lib { inherit lib; };
getUseXdg =
osNix: userNix:
(nixosLib.evalTest {
hostPkgs = pkgs;
nodes.machine.imports = [
../../../../nixos
{
nix = osNix;
home-manager.users.user = {
home.stateVersion = "26.05";
nix = userNix;
};
}
];
}).config.nodes.machine.home-manager.users.user.nix.useXdg;
in
{
nmt.script =
# Defaults to false
assert !getUseXdg { } { };
# Test OS config
assert !getUseXdg { enable = true; } { };
assert
!getUseXdg {
enable = false;
settings.use-xdg-base-directories = true;
} { };
assert getUseXdg {
enable = true;
settings.use-xdg-base-directories = true;
} { };
# Test user config
assert !getUseXdg { } { enable = true; };
assert
!getUseXdg { } {
enable = false;
settings.use-xdg-base-directories = true;
};
assert getUseXdg { } {
enable = true;
settings.use-xdg-base-directories = true;
};
# Fallback to OS config if user config is unset
assert getUseXdg
{
enable = true;
settings.use-xdg-base-directories = true;
}
{
enable = true;
};
# But user config takes precedence
assert
!getUseXdg
{
enable = true;
settings.use-xdg-base-directories = true;
}
{
enable = true;
settings.use-xdg-base-directories = false;
};
assert getUseXdg
{
enable = true;
settings.use-xdg-base-directories = false;
}
{
enable = true;
settings.use-xdg-base-directories = true;
};
# assumeXdg also takes precedence
assert getUseXdg { } { assumeXdg = true; };
assert getUseXdg
{
enable = true;
settings.use-xdg-base-directories = false;
}
{
enable = false;
assumeXdg = true;
};
"";
}

View file

@ -4,4 +4,7 @@
xdg-mime-disabled = ./mime-disabled.nix;
xdg-autostart = ./autostart.nix;
xdg-autostart-readonly = ./autostart-readonly.nix;
xdg-user-dirs-mixed = ./user-dirs-mixed.nix;
xdg-user-dirs-null = ./user-dirs-null.nix;
xdg-user-dirs-short = ./user-dirs-short.nix;
}

View file

@ -2,7 +2,6 @@
xdg-mime-apps-basics = ./mime-apps-basics.nix;
xdg-system-dirs = ./system-dirs.nix;
xdg-desktop-entries = ./desktop-entries.nix;
xdg-user-dirs-null = ./user-dirs-null.nix;
xdg-portal = ./portal.nix;
xdg-mime = ./mime.nix;
xdg-mime-package = ./mime-packages.nix;

View file

@ -0,0 +1,35 @@
{
config,
pkgs,
...
}:
{
config = {
home.stateVersion = "25.11";
xdg.userDirs = {
enable = true;
extraConfig.PROJECTS = "${config.home.homeDirectory}/Projects";
## This will trigger a warning.
extraConfig.XDG_MISC_DIR = "${config.home.homeDirectory}/Misc";
};
nmt.script = ''
configFile=home-files/.config/user-dirs.dirs
assertFileExists $configFile
assertFileContent $configFile ${pkgs.writeText "expected" ''
XDG_DESKTOP_DIR="/home/hm-user/Desktop"
XDG_DOCUMENTS_DIR="/home/hm-user/Documents"
XDG_DOWNLOAD_DIR="/home/hm-user/Downloads"
XDG_MISC_DIR="/home/hm-user/Misc"
XDG_MUSIC_DIR="/home/hm-user/Music"
XDG_PICTURES_DIR="/home/hm-user/Pictures"
XDG_PROJECTS_DIR="/home/hm-user/Projects"
XDG_PUBLICSHARE_DIR="/home/hm-user/Public"
XDG_TEMPLATES_DIR="/home/hm-user/Templates"
XDG_VIDEOS_DIR="/home/hm-user/Videos"
''}
'';
};
}

View file

@ -0,0 +1,30 @@
{
config,
pkgs,
...
}:
{
config = {
xdg.userDirs = {
enable = true;
extraConfig.PROJECTS = "${config.home.homeDirectory}/Projects";
};
nmt.script = ''
configFile=home-files/.config/user-dirs.dirs
assertFileExists $configFile
assertFileContent $configFile ${pkgs.writeText "expected" ''
XDG_DESKTOP_DIR="/home/hm-user/Desktop"
XDG_DOCUMENTS_DIR="/home/hm-user/Documents"
XDG_DOWNLOAD_DIR="/home/hm-user/Downloads"
XDG_MUSIC_DIR="/home/hm-user/Music"
XDG_PICTURES_DIR="/home/hm-user/Pictures"
XDG_PROJECTS_DIR="/home/hm-user/Projects"
XDG_PUBLICSHARE_DIR="/home/hm-user/Public"
XDG_TEMPLATES_DIR="/home/hm-user/Templates"
XDG_VIDEOS_DIR="/home/hm-user/Videos"
''}
'';
};
}

View file

@ -8,16 +8,6 @@
profileExtra = "profile extra commands";
};
nixpkgs.overlays = [
(self: super: {
xorg = super.xorg // {
setxkbmap = super.xorg.setxkbmap // {
outPath = "@setxkbmap@";
};
};
})
];
nmt.script = ''
assertFileExists home-files/.xprofile
assertFileContent \

View file

@ -17,16 +17,6 @@
profileExtra = "profile extra commands";
};
nixpkgs.overlays = [
(self: super: {
xorg = super.xorg // {
setxkbmap = super.xorg.setxkbmap // {
outPath = "@setxkbmap@";
};
};
})
];
nmt.script = ''
assertFileExists home-files/.config/systemd/user/setxkbmap.service
assertFileContent \

View file

@ -38,14 +38,14 @@
assertFileExists home-files/.claude/commands/path-command.md
assertFileExists home-files/.claude/agents/inline-agent.md
assertFileExists home-files/.claude/agents/path-agent.md
assertFileExists home-files/.claude/skills/inline-skill.md
assertFileExists home-files/.claude/skills/path-skill.md
assertFileExists home-files/.claude/skills/inline-skill/SKILL.md
assertFileExists home-files/.claude/skills/path-skill/SKILL.md
assertFileContent home-files/.claude/commands/path-command.md \
${./test-command.md}
assertFileContent home-files/.claude/agents/path-agent.md \
${./test-agent.md}
assertFileContent home-files/.claude/skills/path-skill.md \
assertFileContent home-files/.claude/skills/path-skill/SKILL.md \
${./test-skill.md}
'';
}

View file

@ -0,0 +1,12 @@
---
name: data-processing
description: Process and transform structured data files.
---
# Data Processing Skill
Use this skill for data-processing tasks.
## Supporting files
- `extract.md`: extraction workflow details
- `convert.md`: conversion workflow details

View file

@ -5,10 +5,10 @@
};
nmt.script = ''
assertFileExists home-files/.claude/skills/test-skill.md
assertLinkExists home-files/.claude/skills/test-skill.md
assertFileExists home-files/.claude/skills/test-skill/SKILL.md
assertLinkExists home-files/.claude/skills/test-skill/SKILL.md
assertFileContent \
home-files/.claude/skills/test-skill.md \
${./skills/test-skill.md}
home-files/.claude/skills/test-skill/SKILL.md \
${./skills/test-skill/SKILL.md}
'';
}

View file

@ -7,8 +7,8 @@
};
nmt.script = ''
assertFileExists home-files/.claude/skills/test-skill.md
assertFileContent home-files/.claude/skills/test-skill.md \
assertFileExists home-files/.claude/skills/test-skill/SKILL.md
assertFileContent home-files/.claude/skills/test-skill/SKILL.md \
${./test-skill.md}
'';
}

View file

@ -7,10 +7,15 @@
};
nmt.script = ''
assertFileExists home-files/.claude/skills/data-processing/SKILL.md
assertFileExists home-files/.claude/skills/data-processing/extract.md
assertFileExists home-files/.claude/skills/data-processing/convert.md
assertLinkExists home-files/.claude/skills/data-processing/SKILL.md
assertLinkExists home-files/.claude/skills/data-processing/extract.md
assertLinkExists home-files/.claude/skills/data-processing/convert.md
assertFileContent \
home-files/.claude/skills/data-processing/SKILL.md \
${./skill-subdir/SKILL.md}
assertFileContent \
home-files/.claude/skills/data-processing/extract.md \
${./skill-subdir/extract.md}

View file

@ -6,6 +6,8 @@
codex-custom-instructions = ./custom-instructions.nix;
codex-custom-instructions-prefer-xdg-directories = ./custom-instructions-prefer-xdg-directories.nix;
codex-empty-custom-instructions = ./empty-custom-instructions.nix;
codex-mcp-integration = ./mcp-integration.nix;
codex-mcp-integration-with-override = ./mcp-integration-with-override.nix;
codex-skills-inline = ./skills-inline.nix;
codex-skills-dir = ./skills-dir.nix;
codex-skills-path-not-directory = ./skills-path-not-directory.nix;

View file

@ -0,0 +1,49 @@
{
programs.mcp = {
enable = true;
servers = {
everything = {
command = "npx";
args = [
"-y"
"@modelcontextprotocol/server-everything"
];
};
context7 = {
url = "https://mcp.context7.com/mcp";
headers = {
CONTEXT7_API_KEY = "{env:CONTEXT7_API_KEY}";
};
};
};
};
programs.codex = {
enable = true;
enableMcpIntegration = true;
settings = {
model = "gpt-5-codex";
mcp_servers = {
custom-server = {
url = "http://localhost:3000/mcp";
enabled = true;
enabled_tools = [
"open"
"screenshot"
];
};
everything = {
command = "final-command";
enabled = false;
tool_timeout_sec = 45;
};
};
};
};
nmt.script = ''
assertFileExists home-files/.codex/config.toml
assertFileContent home-files/.codex/config.toml \
${./mcp-integration-with-override.toml}
'';
}

View file

@ -0,0 +1,18 @@
model = "gpt-5-codex"
[mcp_servers.context7]
enabled = true
url = "https://mcp.context7.com/mcp"
[mcp_servers.context7.http_headers]
CONTEXT7_API_KEY = "{env:CONTEXT7_API_KEY}"
[mcp_servers.custom-server]
enabled = true
enabled_tools = ["open", "screenshot"]
url = "http://localhost:3000/mcp"
[mcp_servers.everything]
command = "final-command"
enabled = false
tool_timeout_sec = 45

View file

@ -0,0 +1,36 @@
{
programs.mcp = {
enable = true;
servers = {
everything = {
command = "npx";
args = [
"-y"
"@modelcontextprotocol/server-everything"
];
};
context7 = {
url = "https://mcp.context7.com/mcp";
headers = {
CONTEXT7_API_KEY = "{env:CONTEXT7_API_KEY}";
};
};
disabled-server = {
command = "echo";
args = [ "test" ];
disabled = true;
};
};
};
programs.codex = {
enable = true;
enableMcpIntegration = true;
};
nmt.script = ''
assertFileExists home-files/.codex/config.toml
assertFileContent home-files/.codex/config.toml \
${./mcp-integration.toml}
'';
}

View file

@ -0,0 +1,16 @@
[mcp_servers.context7]
enabled = true
url = "https://mcp.context7.com/mcp"
[mcp_servers.context7.http_headers]
CONTEXT7_API_KEY = "{env:CONTEXT7_API_KEY}"
[mcp_servers.disabled-server]
args = ["test"]
command = "echo"
enabled = false
[mcp_servers.everything]
args = ["-y", "@modelcontextprotocol/server-everything"]
command = "npx"
enabled = true

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