Hello im trying to create a different method to create an option and configure it with a variable in the samespace here is a template for the module in question:
say that the file is in the path: modules/example/module.nix
{ lib, config, ... }: let
# module = "modules.example.module";
module = modules.example.module;
in {
options.${module}.enable =
lib.mkEnableOption "enable module";
config = lib.mkIf config.${module}.enable {
# ...
};
}
this module would be imported and enabled like this:
{
imports = [ ./modules/example/module.nix ];
config = {
modules.example.module.enable = true;
};
}
is this possible?
If the value of the module
variable contains dots (let’s say it’s "foo.bar"
), don’t expect options.${module}.enable
to be the same attribute path as options.foo.bar.enable
. Instead, it’s the same attribute path as options."foo.bar".enable
.
If you would like to create a value that looks like
{ foo = { bar = { enable = whatever; }; }; }
but the foo
and bar
part is dynamically determined from a dot-separated string, perhaps you want this:
lib.setAttrByPath (lib.splitString "." module) whatever
Similarly, lib.getAttrFromPath
may be of interest for getting the value of config.foo.bar.enable
.
2 Likes
i just want a variable that would skip the work of writing that attribute path all the time in the file.
dont matter if its a dot separated string or whatever
There is no native first-class abstraction in the language for an attribute path (or subunits thereof larger than a single attribute string), though there are library functions like the ones I’ve pointed out that use lists of strings as an ersatz representation of such.
I have taken a look at setAttrbByPath that you mentioned and i think i can work that out to do what i need. thanks
You don’t have to?
{ lib, config, ... }:
let
cfg = config.modules.example.module;
in
{
options.modules.example.module = {
enable = lib.mkEnableOption "enable module";
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
};
};
config = lib.mkIf cfg.enable {
environment.etc."example-module.conf".text = cfg.extraConfig;
};
}
You only have to write it twice, rather than over and over. This is pretty standard practice. Messing around with setAttrbByPath
just seems like unnecessary complexity and effort.
1 Like
Oh that’s it, i was trying to have it both on the options and config, but at least reducing to twice on those modules that i need to write many times over is worth it.
thanks
adding to this, is there any way to fix this error without having to write the attset a third time?
{ lib, config, ... }:
let
cfg = config.modules.nixvim;
in
{
imports = [
./options.nix
./keys.nix
./ui
./theme
./utils
./language
];
options.modules.nixvim.enable =
lib.mkEnableOption "enable all nixvim modules"
// {default = true;};
cfg = lib.mkIf cfg.enable {
ui.enable = lib.mkDefault true;
language.enable = lib.mkDefault true;
utils.enable = lib.mkDefault true;
theme.enable = lib.mkDefault true;
keys.enable = lib.mkDefault true;
options.enable = lib.mkDefault true;
};
}
the error:
error: Module `/nix/store/dmf2j3whlc2jhxfvgiw55zmxchl3bw6r-source/config' has an unsupported attribute `cfg'. This is caused by introducing a top-level `config' or `options' attribute. Add configuration attributes immediately on the top level instead, or move all of them (namely: cfg) into the explicit `config' attribute.
I guess you could go back to the setAttrbByPath
thing, but I really think you’re trying to micro-optimize something that really doesn’t matter, and you’re only going to make things more complicated.
2 Likes
maybe you’re right, i will take what i can, doing the cfg
seems fine, at most seems like i have to repeat the attbset trice. so i guess its something.