11.stylix/stylix/mk-target.nix
awwpotato 0e7b897c73
flake: update all inputs (#1881)
Update all inputs, rename the KDE platform, and apply formatter changes
by running the following commands:

    biome check --unsafe --write
    pre-commit run --all-files

Rename the KDE platform, following local commit f47c0edcf7 ("treewide:
remove Plasma 5 support dropped upstream (#1860)") and upstream commits
[1] ("nixos/treewide: clean up some more references to deleted qt5
things") and [2] ("qt: deprecate kde6").

[1]: 31d5c4e753
[2]: 1e759786e5

Closes: https://github.com/nix-community/stylix/issues/1865
Link: https://github.com/nix-community/stylix/pull/1866
Link: https://github.com/nix-community/stylix/pull/1881

Reviewed-by: NAHO <90870942+trueNAHO@users.noreply.github.com>
Co-authored-by: Samuel Meenzen <samuel@meenzen.net>
Co-authored-by: NAHO <90870942+trueNAHO@users.noreply.github.com>
Reviewed-by: Daniel Thwaites <danth@danth.me>
2025-09-05 22:22:06 +02:00

271 lines
7.5 KiB
Nix

/**
Provides a consistent target interface, minimizing boilerplate and
automatically safeguarding declarations related to disabled options.
# Type
```
mkTarget :: AttrSet -> ModuleBody
```
Where `ModuleBody` is a module that doesn't take any arguments. This allows
the caller to use module arguments.
# Examples
The `modules/«MODULE»/«PLATFORM».nix` modules should use this function as
follows:
```nix
{ mkTarget, lib... }:
mkTarget {
name = "«name»";
humanName = "«human readable name»";
generalConfig =
lib.mkIf complexCondition {
home.packages = [ pkgs.hello ];
};
configElements = [
{ programs.«name».theme.name = "stylix"; }
(
{ colors }:
{
programs.«name».theme.background = colors.base00;
}
)
(
{ fonts }:
{
programs.«name».font.name = fonts.monospace.name;
}
)
];
}
```
# Inputs
`config` (Attribute set)
: `name` (String)
: The target name used to generate options in the `stylix.targets.${name}`
namespace.
`humanName` (String)
: The descriptive target name passed to the lib.mkEnableOption function
when generating the `stylix.targets.${name}.enable` option.
`autoEnable` (Boolean)
: Whether the target should be automatically enabled by default according
to the `stylix.autoEnable` option.
This should be disabled if manual setup is required or if auto-enabling
causes issues.
The default (`true`) is inherited from `mkEnableTargetWith`.
`autoEnableExpr` (String)
: A string representation of `autoEnable`, for use in documentation.
Not required if `autoEnable` is a literal `true` or `false`, but **must**
be used when `autoEnable` is a dynamic expression.
E.g. `"pkgs.stdenv.hostPlatform.isLinux"`.
`autoWrapEnableExpr` (Boolean)
: Whether to automatically wrap `autoEnableExpr` with parenthesis, when it
contains a potentially problematic infix.
The default (`true`) is inherited from `mkEnableTargetWith`.
`enableExample` (Boolean or literal expression)
: An example to include on the enable option. The default is calculated
automatically by `mkEnableTargetWith` and depends on `autoEnable` and
whether an `autoEnableExpr` is used.
`extraOptions` (Attribute set)
: Additional options to be added in the `stylix.targets.${name}` namespace
along the `stylix.targets.${name}.enable` option.
For example, an extension guard used in the configuration can be declared
as follows:
```nix
{ extension.enable = lib.mkEnableOption "the bloated dependency"; }
```
`configElements` (List or attribute set or function or path)
: Configuration functions that are automatically safeguarded when any of
their arguments is disabled. The provided `cfg` argument conveniently
aliases to `config.stylix.targets.${name}`.
For example, the following configuration is not merged if the stylix
colors option is null:
```nix
(
{ colors }:
{
programs.«name».theme.background = colors.base00;
}
)
```
The `cfg` alias can be accessed as follows:
```nix
(
{ cfg }:
{
programs.«name».extension.enable = cfg.extension.enable;
}
)
```
`generalConfig` (Attribute set or function or path)
: This argument mirrors the `configElements` argument but intentionally
lacks automatic safeguarding and should only be used for complex
configurations where `configElements` is unsuitable.
# Environment
The function is provided alongside module arguments in any modules imported
through `/stylix/autoload.nix`.
*/
# TODO: Ideally, in the future, this function returns an actual module by better
# integrating with the /stylix/autoload.nix logic, allowing the following target
# simplification and preventing access to unguarded module arguments by
# requiring /modules/<MODULE>/<PLATFORM>.nix files to be attribute sets instead
# of modules:
#
# {
# name = "example";
# humanName = "Example Target";
#
# generalConfig =
# { lib, pkgs }:
# lib.mkIf complexCondition {
# home.packages = [ pkgs.hello ];
# };
#
# configElements = [
# { programs.example.theme.name = "stylix"; }
#
# (
# { colors }:
# {
# programs.example.theme.background = colors.base00;
# }
# )
#
# (
# { fonts }:
# {
# programs.example.font.name = fonts.monospace.name;
# }
# )
# ];
# }
{
name,
humanName,
autoEnable ? null,
autoEnableExpr ? null,
autoWrapEnableExpr ? null,
enableExample ? null,
extraOptions ? { },
configElements ? [ ],
generalConfig ? null,
imports ? [ ],
}@args:
let
module =
{ config, lib, ... }:
let
cfg = config.stylix.targets.${name};
# Get the list of function de-structured argument names.
functionArgNames =
fn:
lib.pipe fn [
lib.functionArgs
builtins.attrNames
];
getStylixAttrs =
fn:
lib.genAttrs (functionArgNames fn) (
arg:
if arg == "cfg" then
cfg
else if arg == "colors" then
config.lib.stylix.colors
else
config.stylix.${arg}
or (throw "stylix: mkTarget expected one of `cfg`, `colors`, ${
lib.concatMapStringsSep ", " (name: "`${name}`") (
builtins.attrNames config.stylix
)
}, but got: ${arg}")
);
# Call the configuration function with its required Stylix arguments.
mkConfig = fn: fn (getStylixAttrs fn);
# Safeguard configuration functions when any of their arguments is
# disabled.
mkConditionalConfig =
c:
if builtins.isFunction c then
let
allAttrsEnabled = lib.pipe c [
getStylixAttrs
builtins.attrValues
# If the attr has no enable option, it is instead disabled when null
(builtins.all (attr: attr.enable or (attr != null)))
];
in
lib.mkIf allAttrsEnabled (mkConfig c)
else
c;
in
{
imports = imports ++ [
{ options.stylix.targets.${name} = mkConfig (lib.toFunction extraOptions); }
];
options.stylix.targets.${name}.enable =
let
enableArgs = {
name = humanName;
}
// lib.optionalAttrs (args ? autoEnable) { inherit autoEnable; }
// lib.optionalAttrs (args ? autoEnableExpr) { inherit autoEnableExpr; }
// lib.optionalAttrs (args ? autoWrapEnableExpr) {
autoWrapExpr = autoWrapEnableExpr;
}
// lib.optionalAttrs (args ? enableExample) { example = enableExample; };
in
config.lib.stylix.mkEnableTargetWith enableArgs;
config = lib.mkIf (config.stylix.enable && cfg.enable) (
lib.mkMerge (
lib.optional (generalConfig != null) (
mkConfig (
if builtins.isPath generalConfig then import generalConfig else generalConfig
)
)
++ map (c: mkConditionalConfig (if builtins.isPath c then import c else c)) (
lib.toList configElements
)
)
);
};
in
{
imports = [ module ];
}