aboutsummaryrefslogtreecommitdiff
path: root/modules/lib/types.nix
blob: f47f717c843ffdd59de5a8de51e5a4905d89b52c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
{ lib
, dag ? import ./dag.nix { inherit lib; }
, gvariant ? import ./gvariant.nix { inherit lib; }
}:

with lib;

let

  typesDag = import ./types-dag.nix { inherit dag lib; };

  # Needed since the type is called gvariant and its merge attribute
  # must refer back to the type.
  gvar = gvariant;

in

rec {

  inherit (typesDag) dagOf listOrDagOf;

  selectorFunction = mkOptionType {
    name = "selectorFunction";
    description =
      "Function that takes an attribute set and returns a list"
      + " containing a selection of the values of the input set";
    check = isFunction;
    merge = _loc: defs:
      as: concatMap (select: select as) (getValues defs);
  };

  overlayFunction = mkOptionType {
    name = "overlayFunction";
    description =
      "An overlay function, takes self and super and returns"
      + " an attribute set overriding the desired attributes.";
    check = isFunction;
    merge = _loc: defs:
      self: super:
        foldl' (res: def: mergeAttrs res (def.value self super)) {} defs;
  };

  fontType = types.submodule {
    options = {
      package = mkOption {
        type = types.nullOr types.package;
        default = null;
        example = literalExample "pkgs.dejavu_fonts";
        description = ''
          Package providing the font. This package will be installed
          to your profile. If <literal>null</literal> then the font
          is assumed to already be available in your profile.
        '';
      };

      name = mkOption {
        type = types.str;
        example = "DejaVu Sans 8";
        description = ''
          The family name and size of the font within the package.
        '';
      };
    };
  };

  gvariant = mkOptionType rec {
    name = "gvariant";
    description = "GVariant value";
    check = v: gvar.mkValue v != null;
    merge = loc: defs:
      let
        vdefs = map (d: d // { value = gvar.mkValue d.value; }) defs;
        vals = map (d: d.value) vdefs;
        defTypes = map (x: x.type) vals;
        sameOrNull = x: y: if x == y then y else null;
        # A bit naive to just check the first entry…
        sharedDefType = foldl' sameOrNull (head defTypes) defTypes;
        allChecked = all (x: check x) vals;
      in
        if sharedDefType == null then
          throw ("Cannot merge definitions of `${showOption loc}' with"
                 + " mismatched GVariant types given in"
                 + " ${showFiles (getFiles defs)}.")
        else if gvar.isArray sharedDefType && allChecked then
          (types.listOf gvariant).merge
            loc (map (d: d // { value = d.value.value; } ) vdefs)
        else if gvar.isTuple sharedDefType && allChecked then
          mergeOneOption loc defs
        else if gvar.type.string == sharedDefType && allChecked then
          types.str.merge loc defs
        else if gvar.type.double == sharedDefType && allChecked then
          types.float.merge loc defs
        else
          mergeDefaultOption loc defs;
  };

}