stylix: allow specifying autoEnableExpr in mkEnableTargetWith

This allows correctly documenting dynamic enable conditions.

E.g:
```nix
    enable = mkEnableTargetWith {
      name = "QT";
      autoEnable = pkgs.stdenv.hostPlatform.isLinux;
      autoEnableExpr = "pkgs.stdenv.hostPlatform.isLinux";
    };
```

`autoEnableExpr` will be wrapped in parentheses if it contains a nix
operator with lower precedence than `&&`.

Added a note in the docs mentioning `mkEnableTarget` should either have
a static `autoEnable` or specify `autoEnableExpr`.
This commit is contained in:
Matt Sturgeon 2025-05-09 13:31:54 +01:00
parent a4d92fea87
commit 0449dae6d4
No known key found for this signature in database
GPG key ID: 4F91844CED1A8299
2 changed files with 61 additions and 5 deletions

View file

@ -106,6 +106,13 @@ the following applies:
- There is no reliable way to detect whether the target is installed, *and*
enabling it unconditionally would cause problems.
> [!CAUTION]
> The boolean value after `mkEnableTarget` should usually be a static `true` or
> `false` literal.
>
> Using a dynamic value requires you to document the dynamic expression using
> `mkEnableTargetWith`'s `autoEnableExpr` argument.
### Overlays
If your module is provided as an overlay it uses a special format, where config

View file

@ -35,6 +35,42 @@
let
cfg = config.stylix;
self = config.lib.stylix;
# Will wrap with (parentheses) if the expr contains operators with lower precedence than `&&`
wrapExprWith =
{
autoWrapExpr ? true,
trimExpr ? true,
indentMultilineExpr ? true,
}:
expr:
let
trimmed = if trimExpr then lib.trim expr else expr;
isWrapped = builtins.match ''[(].*[)]'' trimmed != null;
hasNewlines = lib.hasInfix "\n" trimmed;
needsWrapping = builtins.any (op: lib.hasInfix op trimmed) [
# These operators have lower precedence than `&&`
# See https://nix.dev/manual/nix/2.28/language/operators
"||"
"->"
"|>"
"<|"
# These keywords would also need wrapping
"with "
"assert "
];
indented =
if indentMultilineExpr then
lib.pipe trimmed [
(lib.strings.splitString "\n")
(map (line: if line == "" then "" else " " + line))
(builtins.concatStringsSep "\n")
]
else
trimmed;
wrapped = if hasNewlines then "(\n${indented}\n)" else "(${trimmed})";
in
if autoWrapExpr && !isWrapped && needsWrapping then wrapped else trimmed;
in
{
mkEnableTarget =
@ -45,13 +81,26 @@
{
name,
autoEnable ? true,
}:
autoEnableExpr ? null,
autoWrapExpr ? true,
example ? if args ? autoEnableExpr then true else !autoEnable,
}@args:
let
wrapExpr = wrapExprWith {
inherit autoWrapExpr;
};
in
self.mkEnableIf {
description = "Whether to enable theming for ${name}.";
description = "Whether to enable theming for ${name}";
default = cfg.autoEnable && autoEnable;
${if autoEnable then "defaultText" else null} =
lib.literalExpression "stylix.autoEnable";
example = !autoEnable;
defaultText =
if args ? autoEnableExpr then
lib.literalExpression "stylix.autoEnable && ${wrapExpr autoEnableExpr}"
else if autoEnable then
lib.literalExpression "stylix.autoEnable"
else
false;
inherit example;
};
mkEnableWallpaper =