!wfudwzqQUiJYJnqfSY:nixos.org

NixOS Module System

205 Members
48 Servers

Load older messages


SenderMessageTime
8 Jun 2026
@nbp:mozilla.orgnbp * I guess we could fix listOf by skipping if the elemType may contain any submodule, and use the elemType.check then. However, we should make sure the error message does not add more confusion. Such as complaining that this is not an enumerated value, while we expect a list of enumerated values. 13:00:53
@nbp:mozilla.orgnbp * I guess we could fix listOf by skipping if the elemType may contain any submodule, and use the elemType.check otherwise. However, we should make sure the error message does not add more confusion. Such as complaining that this is not an enumerated value, while we expect a list of enumerated values. 13:01:05
@johnny:yatrix.orgJohnny joined the room.22:31:59
9 Jun 2026
@aurelivia:matrix.orgaurelivia joined the room.16:07:54
@aurelivia:matrix.orgaurelivia Hello, what do I have to do to get the mk... family of functions (mkMerge, mkIf, mkOveride, mkOrder, etc.) to work within a custom option type? I'm fairly certain my merge function just wraps around existing ones and yet all of them just come through in the output unchanged and I can't understand why 16:12:39
@aurelivia:matrix.orgaurelivia If I have a mkMerge at the level just above the option type then it all seems to work but anything further into it and it doesn't 16:14:55
@hsjobeki:matrix.orghsjobekiDo you have an example what your type is trying to do? 16:15:20
@aurelivia:matrix.orgaurelivia
  nodelike = lib.mkOptionType {
    name = "nodelike";
    description = "Something that acts like a node, with attributes, a value, and children.";
    descriptionClass = "noun";
    check = val: true;
    merge = loc: defs: if (builtins.length defs == 1)
      then (builtins.head defs).value
      else (builtins.foldl' (acc: def: let
        acc-def = { value = acc.val; file = acc.file; };
        fail = throw "The option `${lib.options.showOption loc}` has conflicting option types:${lib.options.showDefs [ acc-def def ]}";
      in if (acc.type == "list")
        then if (builtins.typeOf def.value) == "list"
          then { type = "list"; file = def.file; val = (lib.types.listOf nodelike).merge loc [ acc-def def ]; }
          else if (builtins.typeOf def.value) == "set"
            then {
              type = "list"; file = def.file;
              val = (lib.types.listOf nodelike).merge loc [
                acc-def
                { value = [ def.value ]; file = def.file; }
              ];
            } else fail
        else if (acc.type == "set")
          then if (builtins.typeOf def.value) == "set"
            then { type = "set"; file = def.file; val = (lib.types.attrsOf nodelike).merge loc [ acc-def def ]; }
            else if (builtins.typeOf def.value) == "list"
              then {
                type = "list"; file = def.file;
                val = (lib.types.listOf nodelike).merge loc [
                  { value = [ acc.val ]; file = acc.file; }
                  def
                ];
              } else fail
          else if (builtins.typeOf def.value) == acc.type
            then { type = acc.type; file = def.file; val = lib.options.mergeEqualOption loc [ acc-def def ]; }
            else fail
      ) (let h = builtins.head defs; in { type = builtins.typeOf h; file = h.file; val = h.value; }) (builtins.tail defs)).val;
  };
16:15:40
@aurelivia:matrix.orgaureliviabasically XML as Nix, where you can have lists of attrsets to define multiple of a node, and if a different option defines only one, I want it to handle that gracefully16:16:32
@aurelivia:matrix.orgaurelivia* basically XML as Nix, where you can have lists of attrsets to define multiple of a node, and if a different module defines only one, I want it to handle that gracefully16:17:53
@hsjobeki:matrix.orghsjobeki A bit hard to tell from breifly reading.
Usually you call mergeDefinitions loc type defs in your type
You dont call the merge functions of other types.
16:18:31
@aurelivia:matrix.orgaureliviaIIRC I based it off of what the merge functions for attrsOf and listOf do16:20:02
@aurelivia:matrix.orgaurelivia Do you mean instead of (lib.types.attrsOf nodelike).merge loc ..., to do mergeDefinitons loc (lib.types.attrsOf nodelike) ...? 16:21:18
@hsjobeki:matrix.orghsjobekiYes16:21:43
@aurelivia:matrix.orgaureliviaalright, I'll give that a try, thanks16:22:01
@hsjobeki:matrix.orghsjobekiYou need to pass the correct type to mergeDefinitions which will be used for merging the defs16:22:29
@hsjobeki:matrix.orghsjobeki

There are some more problems in your code.

h = builtins.head defs; # -> definition :: { file, value }
type = builtins.typeOf h; # -> attrs, always
16:26:03
@hsjobeki:matrix.orghsjobekiConceptually i think you shouldn probably reconsider if you need to use foldl' with head, tail on the defs16:27:18
@hsjobeki:matrix.orghsjobeki* Conceptually i think you should probably reconsider if you need to use foldl' with head, tail on the defs16:27:23
@hsjobeki:matrix.orghsjobeki acc.type is determined by the first element? But definitions don't have a predictable/stable order 16:29:33
@hsjobeki:matrix.orghsjobeki ah no acc.type is always attrs since the bug with typeOf h 16:30:26
@aurelivia:matrix.orgaureliviaoh nice catch thanks16:38:51
@aurelivia:matrix.orgaureliviaalright unfortunately changing the calls to use mergeDefinitions did not change the outcome16:53:04
@aurelivia:matrix.orgaureliviaso I'm still doing something wrong here16:53:14
@hsjobeki:matrix.orghsjobeki mergeDefintions is definetly the right track; There might be other quirks 16:53:48
@aurelivia:matrix.orgaurelivia
  nodelike = lib.mkOptionType {
    name = "nodelike";
    description = "Something that acts like a node, with attributes, a value, and children.";
    descriptionClass = "noun";
    check = val: true;
    merge = loc: defs: if (builtins.length defs == 1)
      then (builtins.head defs).value
      else (builtins.foldl' (acc: def: let
        acc-def = { value = acc.val; file = acc.file; };
        fail = throw "The option `${lib.options.showOption loc}` has conflicting option types:${lib.options.showDefs [ acc-def def ]}";
      in if (acc.type == "list")
        then if (builtins.typeOf def.value) == "list"
          then { type = "list"; file = def.file; val = (lib.modules.mergeDefinitions loc (lib.types.listOf nodelike) [ acc-def def ]).mergedValue; }
          else if (builtins.typeOf def.value) == "set"
            then {
              type = "list"; file = def.file;
              val = (lib.modules.mergeDefinitions loc (lib.types.listOf nodelike) [
                acc-def
                { value = [ def.value ]; file = def.file; }
              ]).mergedValue;
            } else fail
        else if (acc.type == "set")
          then if (builtins.typeOf def.value) == "set"
            then { type = "set"; file = def.file; val = (lib.modules.mergeDefinitions loc (lib.types.attrsOf nodelike) [ acc-def def ]).mergedValue; }
            else if (builtins.typeOf def.value) == "list"
              then {
                type = "list"; file = def.file;
                val = (lib.modules.mergeDefinitions loc (lib.types.listOf nodelike) [
                  { value = [ acc.val ]; file = acc.file; }
                  def
                ]).mergedValue;
              } else fail
          else { type = acc.type; file = def.file; val = (lib.modules.mergeDefinitions loc lib.types.anything [ acc-def def ]).mergedValue; }
      ) (let h = builtins.head defs; in { type = builtins.typeOf h.value; file = h.file; val = h.value; }) (builtins.tail defs)).val;
  };
16:53:51
@hsjobeki:matrix.orghsjobekiCan you give an example how the type should work ? 16:55:37
@hsjobeki:matrix.orghsjobekiWhat should the produced value look like?16:55:51
@hsjobeki:matrix.orghsjobeki* What should the final value look like?16:56:01
@aurelivia:matrix.orgaurelivia It's essentially just deep-merging an attrset, except that, because this represents nodes like XML, there can be multiple instances of any key, therefore if one module defines a single instance of that key as a set, and another module defines multiple instances as a list, the result should be a list of all the definitions 16:58:49

Show newer messages


Back to Room ListRoom Version: 10