diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/customisation.nix | 22 | ||||
-rw-r--r-- | lib/maintainers.nix | 34 | ||||
-rw-r--r-- | lib/modules.nix | 32 | ||||
-rw-r--r-- | lib/options.nix | 2 | ||||
-rw-r--r-- | lib/types.nix | 152 |
5 files changed, 179 insertions, 63 deletions
diff --git a/lib/customisation.nix b/lib/customisation.nix index efe82d7866001..3e6e279824be4 100644 --- a/lib/customisation.nix +++ b/lib/customisation.nix @@ -56,16 +56,18 @@ rec { ff = f origArgs; overrideWith = newArgs: origArgs // (if builtins.isFunction newArgs then newArgs origArgs else newArgs); in - if builtins.isAttrs ff then (ff // - { override = newArgs: makeOverridable f (overrideWith newArgs); - overrideDerivation = fdrv: - makeOverridable (args: overrideDerivation (f args) fdrv) origArgs; - }) - else if builtins.isFunction ff then - { override = newArgs: makeOverridable f (overrideWith newArgs); - __functor = self: ff; - overrideDerivation = throw "overrideDerivation not yet supported for functors"; - } + if builtins.isAttrs ff then (ff // { + override = newArgs: makeOverridable f (overrideWith newArgs); + overrideDerivation = fdrv: + makeOverridable (args: overrideDerivation (f args) fdrv) origArgs; + ${if ff ? overrideAttrs then "overrideAttrs" else null} = fdrv: + makeOverridable (args: (f args).overrideAttrs fdrv) origArgs; + }) + else if builtins.isFunction ff then { + override = newArgs: makeOverridable f (overrideWith newArgs); + __functor = self: ff; + overrideDerivation = throw "overrideDerivation not yet supported for functors"; + } else ff; diff --git a/lib/maintainers.nix b/lib/maintainers.nix index dbe45ee010a85..2ad631cb19aa4 100644 --- a/lib/maintainers.nix +++ b/lib/maintainers.nix @@ -30,6 +30,7 @@ all = "Nix Committers <nix-commits@lists.science.uu.nl>"; ambrop72 = "Ambroz Bizjak <ambrop7@gmail.com>"; amiddelk = "Arie Middelkoop <amiddelk@gmail.com>"; + amiloradovsky = "Andrew Miloradovsky <miloradovsky@gmail.com>"; amorsillo = "Andrew Morsillo <andrew.morsillo@gmail.com>"; AndersonTorres = "Anderson Torres <torres.anderson.85@gmail.com>"; anderspapitto = "Anders Papitto <anderspapitto@gmail.com>"; @@ -105,8 +106,8 @@ cstrahan = "Charles Strahan <charles@cstrahan.com>"; cwoac = "Oliver Matthews <oliver@codersoffortune.net>"; DamienCassou = "Damien Cassou <damien@cassou.me>"; - dasuxullebt = "Christoph-Simon Senjak <christoph.senjak@googlemail.com>"; danbst = "Danylo Hlynskyi <abcz2.uprola@gmail.com>"; + dasuxullebt = "Christoph-Simon Senjak <christoph.senjak@googlemail.com>"; davidak = "David Kleuker <post@davidak.de>"; davidrusu = "David Rusu <davidrusu.me@gmail.com>"; davorb = "Davor Babic <davor@davor.se>"; @@ -115,6 +116,7 @@ deepfire = "Kosyrev Serge <_deepfire@feelingofgreen.ru>"; demin-dmitriy = "Dmitriy Demin <demindf@gmail.com>"; DerGuteMoritz = "Moritz Heidkamp <moritz@twoticketsplease.de>"; + DerTim1 = "Tim Digel <tim.digel@active-group.de>"; desiderius = "Didier J. Devroye <didier@devroye.name>"; devhell = "devhell <\"^\"@regexmail.net>"; dezgeg = "Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>"; @@ -123,6 +125,7 @@ dipinhora = "Dipin Hora <dipinhora+github@gmail.com>"; dmalikov = "Dmitry Malikov <malikov.d.y@gmail.com>"; dochang = "Desmond O. Chang <dochang@gmail.com>"; + domenkozar = "Domen Kozar <domen@dev.si>"; doublec = "Chris Double <chris.double@double.co.nz>"; drets = "Dmytro Rets <dmitryrets@gmail.com>"; drewkett = "Andrew Burkett <burkett.andrew@gmail.com>"; @@ -173,29 +176,29 @@ globin = "Robin Gloster <mail@glob.in>"; gnidorah = "Alex Ivanov <yourbestfriend@opmbx.org>"; goibhniu = "Cillian de Róiste <cillian.deroiste@gmail.com>"; - goodrone = "Andrew Trachenko <goodrone@gmail.com>"; Gonzih = "Max Gonzih <gonzih@gmail.com>"; + goodrone = "Andrew Trachenko <goodrone@gmail.com>"; gpyh = "Yacine Hmito <yacine.hmito@gmail.com>"; grahamc = "Graham Christensen <graham@grahamc.com>"; gridaphobe = "Eric Seidel <eric@seidel.io>"; guibert = "David Guibert <david.guibert@gmail.com>"; + guillaumekoenig = "Guillaume Koenig <guillaume.edward.koenig@gmail.com>"; hakuch = "Jesse Haber-Kucharsky <hakuch@gmail.com>"; havvy = "Ryan Scheel <ryan.havvy@gmail.com>"; hbunke = "Hendrik Bunke <bunke.hendrik@gmail.com>"; hce = "Hans-Christian Esperer <hc@hcesperer.org>"; henrytill = "Henry Till <henrytill@gmail.com>"; - hiberno = "Christian Lask <hiberno@hiberno.net>"; hinton = "Tom Hinton <t@larkery.com>"; hrdinka = "Christoph Hrdinka <c.nix@hrdinka.at>"; iand675 = "Ian Duncan <ian@iankduncan.com>"; ianwookim = "Ian-Woo Kim <ianwookim@gmail.com>"; - domenkozar = "Domen Kozar <domen@dev.si>"; igsha = "Igor Sharonov <igor.sharonov@gmail.com>"; ikervagyok = "Balázs Lengyel <ikervagyok@gmail.com>"; j-keck = "Jürgen Keck <jhyphenkeck@gmail.com>"; jagajaga = "Arseniy Seroka <ars.seroka@gmail.com>"; javaguirre = "Javier Aguirre <contacto@javaguirre.net>"; jb55 = "William Casarin <bill@casarin.me>"; + jbedo = "Justin Bedő <cu@cua0.org>"; jcumming = "Jack Cummings <jack@mudshark.org>"; jefdaj = "Jeffrey David Johnson <jefdaj@gmail.com>"; jerith666 = "Matt McHenry <github@matt.mchenryfamily.org>"; @@ -247,7 +250,6 @@ lucas8 = "Luc Chabassier <luc.linux@mailoo.org>"; ludo = "Ludovic Courtès <ludo@gnu.org>"; luispedro = "Luis Pedro Coelho <luis@luispedro.org>"; - sternenseemann = "Lukas Epple <post@lukasepple.de>"; lukego = "Luke Gorrie <luke@snabb.co>"; lw = "Sergey Sofeychuk <lw@fmap.me>"; madjar = "Georges Dubus <georges.dubus@compiletoi.net>"; @@ -263,19 +265,22 @@ martingms = "Martin Gammelsæter <martin@mg.am>"; matejc = "Matej Cotman <cotman.matej@gmail.com>"; mathnerd314 = "Mathnerd314 <mathnerd314.gph+hs@gmail.com>"; + matthewbauer = "Matthew Bauer <mjbauer95@gmail.com>"; matthiasbeyer = "Matthias Beyer <mail@beyermatthias.de>"; maurer = "Matthew Maurer <matthew.r.maurer+nix@gmail.com>"; mbakke = "Marius Bakke <mbakke@fastmail.com>"; - matthewbauer = "Matthew Bauer <mjbauer95@gmail.com>"; mbe = "Brandon Edens <brandonedens@gmail.com>"; mboes = "Mathieu Boespflug <mboes@tweag.net>"; mcmtroffaes = "Matthias C. M. Troffaes <matthias.troffaes@gmail.com>"; + mdaiter = "Matthew S. Daiter <mdaiter8121@gmail.com>"; meditans = "Carlo Nucera <meditans@gmail.com>"; meisternu = "Matt Miemiec <meister@krutt.org>"; + mguentner = "Maximilian Güntner <code@klandest.in>"; mic92 = "Jörg Thalheim <joerg@higgsboson.tk>"; michaelpj = "Michael Peyton Jones <michaelpj@gmail.com>"; michalrus = "Michal Rus <m@michalrus.com>"; michelk = "Michel Kuhlmann <michel@kuhlmanns.info>"; + mikefaille = "Michaël Faille <michael@faille.io>"; mimadrid = "Miguel Madrid <mimadrid@ucm.es>"; mingchuan = "Ming Chuan <ming@culpring.com>"; mirdhyn = "Merlin Gaillard <mirdhyn@gmail.com>"; @@ -299,16 +304,16 @@ muflax = "Stefan Dorn <mail@muflax.com>"; myrl = "Myrl Hex <myrl.0xf@gmail.com>"; nand0p = "Fernando Jose Pando <nando@hex7.com>"; - nathan-gs = "Nathan Bijnens <nathan@nathan.gs>"; Nate-Devv = "Nathan Moore <natedevv@gmail.com>"; + nathan-gs = "Nathan Bijnens <nathan@nathan.gs>"; nckx = "Tobias Geerinckx-Rice <tobias.geerinckx.rice@gmail.com>"; nequissimus = "Tim Steinbach <tim@nequissimus.com>"; nfjinjing = "Jinjing Wang <nfjinjing@gmail.com>"; nhooyr = "Anmol Sethi <anmol@aubble.com>"; - nico202 = "Nicolò Balzarotti <anothersms@gmail.com>"; nicknovitski = "Nick Novitski <nixpkgs@nicknovitski.com>"; - notthemessiah = "Brian Cohen <brian.cohen.88@gmail.com>"; + nico202 = "Nicolò Balzarotti <anothersms@gmail.com>"; NikolaMandic = "Ratko Mladic <nikola@mandic.email>"; + notthemessiah = "Brian Cohen <brian.cohen.88@gmail.com>"; np = "Nicolas Pouillard <np.nix@nicolaspouillard.fr>"; nslqqq = "Nikita Mikhailov <nslqqq@gmail.com>"; obadz = "obadz <obadz-nixos@obadz.com>"; @@ -317,6 +322,7 @@ offline = "Jaka Hudoklin <jakahudoklin@gmail.com>"; olcai = "Erik Timan <dev@timan.info>"; olejorgenb = "Ole Jørgen Brønner <olejorgenb@yahoo.no>"; + orbekk = "KJ Ørbekk <kjetil.orbekk@gmail.com>"; orbitz = "Malcolm Matalka <mmatalka@gmail.com>"; osener = "Ozan Sener <ozan@ozansener.com>"; otwieracz = "Slawomir Gonet <slawek@otwiera.cz>"; @@ -360,6 +366,7 @@ rardiol = "Ricardo Ardissone <ricardo.ardissone@gmail.com>"; rasendubi = "Alexey Shmalko <rasen.dubi@gmail.com>"; raskin = "Michael Raskin <7c6f434c@mail.ru>"; + rbasso = "Rafael Basso <rbasso@sharpgeeks.net>"; redbaron = "Maxim Ivanov <ivanov.maxim@gmail.com>"; redvers = "Redvers Davies <red@infect.me>"; refnil = "Martin Lavoie <broemartino@gmail.com>"; @@ -383,8 +390,8 @@ rvl = "Rodney Lorrimar <dev+nix@rodney.id.au>"; rvlander = "Gaëtan André <rvlander@gaetanandre.eu>"; ryanartecona = "Ryan Artecona <ryanartecona@gmail.com>"; - ryantm = "Ryan Mulligan <ryan@ryantm.com>"; ryansydnor = "Ryan Sydnor <ryan.t.sydnor@gmail.com>"; + ryantm = "Ryan Mulligan <ryan@ryantm.com>"; rycee = "Robert Helgesson <robert@rycee.net>"; ryneeverett = "Ryne Everett <ryneeverett@gmail.com>"; s1lvester = "Markus Silvester <s1lvester@bockhacker.me>"; @@ -408,8 +415,8 @@ skeidel = "Sven Keidel <svenkeidel@gmail.com>"; skrzyp = "Jakub Skrzypnik <jot.skrzyp@gmail.com>"; sleexyz = "Sean Lee <freshdried@gmail.com>"; - solson = "Scott Olson <scott@solson.me>"; smironov = "Sergey Mironov <grrwlf@gmail.com>"; + solson = "Scott Olson <scott@solson.me>"; spacefrogg = "Michael Raitza <spacefrogg-nixos@meterriblecrew.net>"; spencerjanssen = "Spencer Janssen <spencerjanssen@gmail.com>"; spinus = "Tomasz Czyż <tomasz.czyz@gmail.com>"; @@ -417,6 +424,7 @@ spwhitt = "Spencer Whitt <sw@swhitt.me>"; SShrike = "Severen Redwood <severen@shrike.me>"; stephenmw = "Stephen Weinberg <stephen@q5comm.com>"; + sternenseemann = "Lukas Epple <post@lukasepple.de>"; steveej = "Stefan Junker <mail@stefanjunker.de>"; swarren83 = "Shawn Warren <shawn.w.warren@gmail.com>"; swistak35 = "Rafał Łasocha <me@swistak35.com>"; @@ -454,6 +462,7 @@ vbgl = "Vincent Laporte <Vincent.Laporte@gmail.com>"; vbmithr = "Vincent Bernardoff <vb@luminar.eu.org>"; vcunat = "Vladimír Čunát <vcunat@gmail.com>"; + vdemeester = "Vincent Demeester <vincent@sbr.pm>"; veprbl = "Dmitry Kalinkin <veprbl@gmail.com>"; viric = "Lluís Batlle i Rossell <viric@viric.name>"; vizanto = "Danny Wilson <danny@prime.vc>"; @@ -474,6 +483,7 @@ wscott = "Wayne Scott <wsc9tt@gmail.com>"; wyvie = "Elijah Rum <elijahrum@gmail.com>"; yarr = "Dmitry V. <savraz@gmail.com>"; + yochai = "Yochai <yochai@titat.info>"; yurrriq = "Eric Bailey <eric@ericb.me>"; z77z = "Marco Maggesi <maggesi@math.unifi.it>"; zagy = "Christian Zagrodnick <cz@flyingcircus.io>"; @@ -481,6 +491,4 @@ zimbatm = "zimbatm <zimbatm@zimbatm.com>"; zohl = "Al Zohali <zohl@fmap.me>"; zoomulator = "Kim Simmons <zoomulator@gmail.com>"; - amiloradovsky = "Andrew Miloradovsky <miloradovsky@gmail.com>"; - yochai = "Yochai <yochai@titat.info>"; } diff --git a/lib/modules.nix b/lib/modules.nix index 8db17c605799a..e66d6a6926cb5 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -231,12 +231,20 @@ rec { correspond to the definition of 'loc' in 'opt.file'. */ mergeOptionDecls = loc: opts: foldl' (res: opt: - if opt.options ? default && res ? default || - opt.options ? example && res ? example || - opt.options ? description && res ? description || - opt.options ? apply && res ? apply || - # Accept to merge options which have identical types. - opt.options ? type && res ? type && opt.options.type.name != res.type.name + let t = res.type; + t' = opt.options.type; + mergedType = t.typeMerge t'.functor; + typesMergeable = mergedType != null; + typeSet = if (bothHave "type") && typesMergeable + then { type = mergedType; } + else {}; + bothHave = k: opt.options ? ${k} && res ? ${k}; + in + if bothHave "default" || + bothHave "example" || + bothHave "description" || + bothHave "apply" || + (bothHave "type" && (! typesMergeable)) then throw "The option `${showOption loc}' in `${opt.file}' is already declared in ${showFiles res.declarations}." else @@ -258,7 +266,7 @@ rec { in opt.options // res // { declarations = res.declarations ++ [opt.file]; options = submodules; - } + } // typeSet ) { inherit loc; declarations = []; options = []; } opts; /* Merge all the definitions of an option to produce the final @@ -422,12 +430,14 @@ rec { options = opt.options or (throw "Option `${showOption loc'}' has type optionSet but has no option attribute, in ${showFiles opt.declarations}."); f = tp: + let optionSetIn = type: (tp.name == type) && (tp.functor.wrapped.name == "optionSet"); + in if tp.name == "option set" || tp.name == "submodule" then throw "The option ${showOption loc} uses submodules without a wrapping type, in ${showFiles opt.declarations}." - else if tp.name == "attribute set of option sets" then types.attrsOf (types.submodule options) - else if tp.name == "list or attribute set of option sets" then types.loaOf (types.submodule options) - else if tp.name == "list of option sets" then types.listOf (types.submodule options) - else if tp.name == "null or option set" then types.nullOr (types.submodule options) + else if optionSetIn "attrsOf" then types.attrsOf (types.submodule options) + else if optionSetIn "loaOf" then types.loaOf (types.submodule options) + else if optionSetIn "listOf" then types.listOf (types.submodule options) + else if optionSetIn "nullOr" then types.nullOr (types.submodule options) else tp; in if opt.type.getSubModules or null == null diff --git a/lib/options.nix b/lib/options.nix index 444ec37e6eaf3..2092b65bbc3a6 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -92,7 +92,7 @@ rec { internal = opt.internal or false; visible = opt.visible or true; readOnly = opt.readOnly or false; - type = opt.type.name or null; + type = opt.type.description or null; } // (if opt ? example then { example = scrubOptionValue opt.example; } else {}) // (if opt ? default then { default = scrubOptionValue opt.default; } else {}) diff --git a/lib/types.nix b/lib/types.nix index 991fa0e5c2914..9366d394da73e 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -17,10 +17,43 @@ rec { }; + # Default type merging function + # takes two type functors and return the merged type + defaultTypeMerge = f: f': + let wrapped = f.wrapped.typeMerge f'.wrapped.functor; + payload = f.binOp f.payload f'.payload; + in + # cannot merge different types + if f.name != f'.name + then null + # simple types + else if (f.wrapped == null && f'.wrapped == null) + && (f.payload == null && f'.payload == null) + then f.type + # composed types + else if (f.wrapped != null && f'.wrapped != null) && (wrapped != null) + then f.type wrapped + # value types + else if (f.payload != null && f'.payload != null) && (payload != null) + then f.type payload + else null; + + # Default type functor + defaultFunctor = name: { + inherit name; + type = types."${name}" or null; + wrapped = null; + payload = null; + binOp = a: b: null; + }; + isOptionType = isType "option-type"; mkOptionType = - { # Human-readable representation of the type. + { # Human-readable representation of the type, should be equivalent to + # the type function name. name + , # Description of the type, defined recursively by embedding the the wrapped type if any. + description ? null , # Function applied to each definition that should return true if # its type-correct, false otherwise. check ? (x: true) @@ -36,12 +69,26 @@ rec { getSubOptions ? prefix: {} , # List of modules if any, or null if none. getSubModules ? null - , # Function for building the same option type with a different list of + , # Function for building the same option type with a different list of # modules. substSubModules ? m: null + , # Function that merge type declarations. + # internal, takes a functor as argument and returns the merged type. + # returning null means the type is not mergeable + typeMerge ? defaultTypeMerge functor + , # The type functor. + # internal, representation of the type as an attribute set. + # name: name of the type + # type: type function. + # wrapped: the type wrapped in case of compound types. + # payload: values of the type, two payloads of the same type must be + # combinable with the binOp binary operation. + # binOp: binary operation that merge two payloads of the same type. + functor ? defaultFunctor name }: { _type = "option-type"; - inherit name check merge getSubOptions getSubModules substSubModules; + inherit name check merge getSubOptions getSubModules substSubModules typeMerge functor; + description = if description == null then name else description; }; @@ -52,29 +99,39 @@ rec { }; bool = mkOptionType { - name = "boolean"; + name = "bool"; + description = "boolean"; check = isBool; merge = mergeEqualOption; }; - int = mkOptionType { - name = "integer"; + int = mkOptionType rec { + name = "int"; + description = "integer"; check = isInt; merge = mergeOneOption; }; str = mkOptionType { - name = "string"; + name = "str"; + description = "string"; check = isString; merge = mergeOneOption; }; # Merge multiple definitions by concatenating them (with the given # separator between the values). - separatedString = sep: mkOptionType { - name = "string"; + separatedString = sep: mkOptionType rec { + name = "separatedString"; + description = "string"; check = isString; merge = loc: defs: concatStringsSep sep (getValues defs); + functor = (defaultFunctor name) // { + payload = sep; + binOp = sepLhs: sepRhs: + if sepLhs == sepRhs then sepLhs + else null; + }; }; lines = separatedString "\n"; @@ -86,7 +143,8 @@ rec { string = separatedString ""; attrs = mkOptionType { - name = "attribute set"; + name = "attrs"; + description = "attribute set"; check = isAttrs; merge = loc: foldl' (res: def: mergeAttrs res def.value) {}; }; @@ -114,8 +172,9 @@ rec { # drop this in the future: list = builtins.trace "`types.list' is deprecated; use `types.listOf' instead" types.listOf; - listOf = elemType: mkOptionType { - name = "list of ${elemType.name}s"; + listOf = elemType: mkOptionType rec { + name = "listOf"; + description = "list of ${elemType.description}s"; check = isList; merge = loc: defs: map (x: x.value) (filter (x: x ? value) (concatLists (imap (n: def: @@ -132,10 +191,12 @@ rec { getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]); getSubModules = elemType.getSubModules; substSubModules = m: listOf (elemType.substSubModules m); + functor = (defaultFunctor name) // { wrapped = elemType; }; }; - attrsOf = elemType: mkOptionType { - name = "attribute set of ${elemType.name}s"; + attrsOf = elemType: mkOptionType rec { + name = "attrsOf"; + description = "attribute set of ${elemType.description}s"; check = isAttrs; merge = loc: defs: mapAttrs (n: v: v.value) (filterAttrs (n: v: v ? value) (zipAttrsWith (name: defs: @@ -147,6 +208,7 @@ rec { getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name>"]); getSubModules = elemType.getSubModules; substSubModules = m: attrsOf (elemType.substSubModules m); + functor = (defaultFunctor name) // { wrapped = elemType; }; }; # List or attribute set of ... @@ -165,18 +227,21 @@ rec { def; listOnly = listOf elemType; attrOnly = attrsOf elemType; - in mkOptionType { - name = "list or attribute set of ${elemType.name}s"; + in mkOptionType rec { + name = "loaOf"; + description = "list or attribute set of ${elemType.description}s"; check = x: isList x || isAttrs x; merge = loc: defs: attrOnly.merge loc (imap convertIfList defs); getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["<name?>"]); getSubModules = elemType.getSubModules; substSubModules = m: loaOf (elemType.substSubModules m); + functor = (defaultFunctor name) // { wrapped = elemType; }; }; # List or element of ... - loeOf = elemType: mkOptionType { - name = "element or list of ${elemType.name}s"; + loeOf = elemType: mkOptionType rec { + name = "loeOf"; + description = "element or list of ${elemType.description}s"; check = x: isList x || elemType.check x; merge = loc: defs: let @@ -189,18 +254,22 @@ rec { else if !isString res then throw "The option `${showOption loc}' does not have a string value, in ${showFiles (getFiles defs)}." else res; + functor = (defaultFunctor name) // { wrapped = elemType; }; }; - uniq = elemType: mkOptionType { - inherit (elemType) name check; + uniq = elemType: mkOptionType rec { + name = "uniq"; + inherit (elemType) description check; merge = mergeOneOption; getSubOptions = elemType.getSubOptions; getSubModules = elemType.getSubModules; substSubModules = m: uniq (elemType.substSubModules m); + functor = (defaultFunctor name) // { wrapped = elemType; }; }; - nullOr = elemType: mkOptionType { - name = "null or ${elemType.name}"; + nullOr = elemType: mkOptionType rec { + name = "nullOr"; + description = "null or ${elemType.description}"; check = x: x == null || elemType.check x; merge = loc: defs: let nrNulls = count (def: def.value == null) defs; in @@ -211,6 +280,7 @@ rec { getSubOptions = elemType.getSubOptions; getSubModules = elemType.getSubModules; substSubModules = m: nullOr (elemType.substSubModules m); + functor = (defaultFunctor name) // { wrapped = elemType; }; }; submodule = opts: @@ -236,6 +306,12 @@ rec { args = { name = ""; }; }).options; getSubModules = opts'; substSubModules = m: submodule m; + functor = (defaultFunctor name) // { + # Merging of submodules is done as part of mergeOptionDecls, as we have to annotate + # each submodule with its location. + payload = []; + binOp = lhs: rhs: []; + }; }; enum = values: @@ -245,23 +321,43 @@ rec { else if builtins.isInt v then builtins.toString v else ''<${builtins.typeOf v}>''; in - mkOptionType { - name = "one of ${concatMapStringsSep ", " show values}"; + mkOptionType rec { + name = "enum"; + description = "one of ${concatMapStringsSep ", " show values}"; check = flip elem values; merge = mergeOneOption; + functor = (defaultFunctor name) // { payload = values; binOp = a: b: unique (a ++ b); }; }; - either = t1: t2: mkOptionType { - name = "${t1.name} or ${t2.name}"; + either = t1: t2: mkOptionType rec { + name = "either"; + description = "${t1.description} or ${t2.description}"; check = x: t1.check x || t2.check x; - merge = mergeOneOption; + merge = loc: defs: + let + defList = map (d: d.value) defs; + in + if all (x: t1.check x) defList + then t1.merge loc defs + else if all (x: t2.check x) defList + then t2.merge loc defs + else mergeOneOption loc defs; + typeMerge = f': + let mt1 = t1.typeMerge (elemAt f'.wrapped 0).functor; + mt2 = t2.typeMerge (elemAt f'.wrapped 1).functor; + in + if (name == f'.name) && (mt1 != null) && (mt2 != null) + then functor.type mt1 mt2 + else null; + functor = (defaultFunctor name) // { wrapped = [ t1 t2 ]; }; }; # Obsolete alternative to configOf. It takes its option # declarations from the ‘options’ attribute of containing option # declaration. optionSet = mkOptionType { - name = builtins.trace "types.optionSet is deprecated; use types.submodule instead" "option set"; + name = builtins.trace "types.optionSet is deprecated; use types.submodule instead" "optionSet"; + description = "option set"; }; # Augment the given type with an additional type check function. |