niri: move config to nix
Signed-off-by: faukah <fau@faukah.com> Change-Id: I6a6a6964cffaba7ce75488a48739398758d49363
This commit is contained in:
parent
0c995da8af
commit
c5915e1d24
4 changed files with 690 additions and 434 deletions
323
modules/wms/niri/kdl.nix
Normal file
323
modules/wms/niri/kdl.nix
Normal file
|
@ -0,0 +1,323 @@
|
|||
# https://github.com/NixOS/nixpkgs/pull/426828
|
||||
# The KDL document language (https://kdl.dev/)
|
||||
/*
|
||||
Original file: formats.nix
|
||||
|
||||
Copyright (c) 2003-2025 Eelco Dolstra and the Nixpkgs/NixOS contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* Modificatied by faukah (2025)
|
||||
*
|
||||
* This modified version is part of the Nichts project and is licensed under
|
||||
* the GNU General Public License v3.0.
|
||||
*
|
||||
* See <https://www.gnu.org/licenses/> for details.
|
||||
*/
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
|
||||
inherit (lib.types)
|
||||
listOf
|
||||
attrsOf
|
||||
str
|
||||
bool
|
||||
number
|
||||
oneOf
|
||||
nullOr
|
||||
submodule
|
||||
coercedTo
|
||||
path
|
||||
;
|
||||
inherit (lib.lists) isList;
|
||||
inherit (lib.attrsets) isAttrs;
|
||||
inherit (lib.trivial) isBool;
|
||||
in
|
||||
{
|
||||
type = (
|
||||
let
|
||||
mergeUniq =
|
||||
mergeOne:
|
||||
lib.mergeUniqueOption {
|
||||
message = "";
|
||||
merge =
|
||||
loc: defs:
|
||||
let
|
||||
inherit (lib.head defs) file value;
|
||||
in
|
||||
mergeOne file loc value;
|
||||
};
|
||||
|
||||
mergeFlat =
|
||||
elemType: loc: file: value:
|
||||
if value ? _type then
|
||||
throw "${lib.showOption loc} has wrong type: expected '${elemType.description}', got `${value._type}`"
|
||||
else
|
||||
elemType.merge loc [ { inherit file value; } ];
|
||||
|
||||
uniqFlatListOf =
|
||||
elemType:
|
||||
lib.mkOptionType {
|
||||
name = "uniqFlatListOf";
|
||||
inherit (listOf elemType) description descriptionClass;
|
||||
check = isList;
|
||||
merge = mergeUniq (
|
||||
file: loc: lib.imap1 (i: mergeFlat elemType (loc ++ [ "[entry ${toString i}]" ]) file)
|
||||
);
|
||||
};
|
||||
|
||||
uniqFlatAttrsOf =
|
||||
elemType:
|
||||
lib.mkOptionType {
|
||||
name = "uniqFlatAttrsOf";
|
||||
inherit (attrsOf elemType) description descriptionClass;
|
||||
check = isAttrs;
|
||||
merge = mergeUniq (file: loc: lib.mapAttrs (name: mergeFlat elemType (loc ++ [ name ]) file));
|
||||
};
|
||||
|
||||
kdlUntypedValue = lib.mkOptionType {
|
||||
name = "kdlUntypedValue";
|
||||
description = "KDL value without type annotation";
|
||||
descriptionClass = "noun";
|
||||
|
||||
inherit
|
||||
(nullOr (oneOf [
|
||||
str
|
||||
bool
|
||||
number
|
||||
path
|
||||
]))
|
||||
check
|
||||
merge
|
||||
;
|
||||
};
|
||||
|
||||
kdlTypedValue = lib.mkOptionType {
|
||||
name = "kdlTypedValue";
|
||||
description = "KDL value with type annotation";
|
||||
descriptionClass = "noun";
|
||||
|
||||
check = isAttrs;
|
||||
merge =
|
||||
(submodule {
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
[Type annotation](https://kdl.dev/spec/#name-type-annotation) of a [KDL value](https://kdl.dev/spec/#name-value).
|
||||
'';
|
||||
};
|
||||
value = lib.mkOption {
|
||||
type = kdlUntypedValue;
|
||||
description = ''
|
||||
Scalar part of a [KDL value](https://kdl.dev/spec/#name-value)
|
||||
'';
|
||||
};
|
||||
};
|
||||
}).merge;
|
||||
};
|
||||
|
||||
# https://kdl.dev/spec/#name-value
|
||||
kdlValue = lib.mkOptionType {
|
||||
name = "kdlValue";
|
||||
description = "KDL value";
|
||||
descriptionClass = "noun";
|
||||
|
||||
inherit (coercedTo kdlUntypedValue (value: { inherit value; }) kdlTypedValue) check merge;
|
||||
|
||||
nestedTypes = {
|
||||
type = nullOr str;
|
||||
scalar = kdlUntypedValue;
|
||||
};
|
||||
};
|
||||
|
||||
# https://kdl.dev/spec/#name-node
|
||||
kdlNode = lib.mkOptionType {
|
||||
name = "kdlNode";
|
||||
description = "KDL node";
|
||||
descriptionClass = "noun";
|
||||
|
||||
check = isAttrs;
|
||||
merge =
|
||||
(submodule {
|
||||
options = {
|
||||
type = lib.mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
[Type annotation](https://kdl.dev/spec/#name-type-annotation) of a KDL node.
|
||||
'';
|
||||
};
|
||||
name = lib.mkOption {
|
||||
type = str;
|
||||
description = ''
|
||||
Name of a [KDL node](https://kdl.dev/spec/#name-node).
|
||||
'';
|
||||
};
|
||||
arguments = lib.mkOption {
|
||||
type = uniqFlatListOf kdlValue;
|
||||
default = [ ];
|
||||
description = ''
|
||||
[Arguments](https://kdl.dev/spec/#name-argument) of a KDL node.
|
||||
'';
|
||||
};
|
||||
properties = lib.mkOption {
|
||||
type = uniqFlatAttrsOf kdlValue;
|
||||
default = { };
|
||||
description = ''
|
||||
[Properties](https://kdl.dev/spec/#name-property) of a KDL node.
|
||||
'';
|
||||
};
|
||||
children = lib.mkOption {
|
||||
type = kdlDocument;
|
||||
default = [ ];
|
||||
description = ''
|
||||
[Children](https://kdl.dev/spec/#children-block) of a KDL node.
|
||||
'';
|
||||
};
|
||||
};
|
||||
}).merge;
|
||||
|
||||
nestedTypes = {
|
||||
name = str;
|
||||
type = nullOr str;
|
||||
arguments = uniqFlatListOf kdlValue;
|
||||
properties = uniqFlatAttrsOf kdlValue;
|
||||
children = kdlDocument;
|
||||
};
|
||||
};
|
||||
|
||||
kdlDocument = lib.mkOptionType {
|
||||
name = "kdlDocument";
|
||||
description = "KDL document";
|
||||
descriptionClass = "noun";
|
||||
|
||||
check = isList;
|
||||
merge = mergeUniq (
|
||||
file:
|
||||
let
|
||||
mergeDocument =
|
||||
loc: toplevel:
|
||||
builtins.concatLists (
|
||||
lib.imap1 (i: mergeDocumentEntry (loc ++ [ "[entry ${toString i}]" ])) toplevel
|
||||
);
|
||||
|
||||
mergeDocumentEntry =
|
||||
loc: value:
|
||||
let
|
||||
inherit (lib.options) showDefs;
|
||||
defs = [ { inherit file value; } ];
|
||||
in
|
||||
if isList value then
|
||||
mergeDocument loc value
|
||||
else if value ? _type then
|
||||
if value._type == "if" then
|
||||
if isBool value.condition then
|
||||
if value.condition then mergeDocumentEntry loc value.content else [ ]
|
||||
else
|
||||
throw "`mkIf` called with non-Boolean condition at ${lib.showOption loc}. Definition value:${showDefs defs}"
|
||||
else if value._type == "merge" then
|
||||
throw ''
|
||||
${lib.showOption loc} has wrong type: expected a KDL node or document, got 'merge'.
|
||||
note: `mkMerge` is potentially ambiguous in a KDL document, as "merging" is application-specific. if you intended to "splat" all the nodes in a KDL document, you can just insert the list of nodes directly. you can arbitrarily nest KDL documents, and they will be concatenated.
|
||||
''
|
||||
else
|
||||
throw "${lib.showOption loc} has wrong type: expected a KDL node or document, got '${value._type}'. Definition value:${showDefs defs}"
|
||||
else if kdlNode.check value then
|
||||
[ (kdlNode.merge loc [ { inherit file value; } ]) ]
|
||||
else
|
||||
throw "${lib.showOption loc} has wrong type: expected a KDL node or document. Definition value:${showDefs defs}";
|
||||
in
|
||||
mergeDocument
|
||||
);
|
||||
|
||||
nestedTypes.node = kdlNode;
|
||||
};
|
||||
in
|
||||
kdlDocument
|
||||
);
|
||||
|
||||
lib = {
|
||||
/**
|
||||
Helper function for generating attrsets expected by pkgs.formats.kdl
|
||||
# Example
|
||||
```nix
|
||||
let
|
||||
settingsFormat = pkgs.formats.kdl { };
|
||||
inherit (settingsFormat.lib) node;
|
||||
in
|
||||
settingsFormat.generate "sample.kdl" [
|
||||
(node "foo" null [ ] { } [
|
||||
(node "bar" null [ "baz" ] { a = 1; } [ ])
|
||||
])
|
||||
]
|
||||
```
|
||||
# Arguments
|
||||
name
|
||||
: The name of the node, represented by a string
|
||||
type
|
||||
: The type annotation of the node, represented by a string, or null to avoid generating a type annotation
|
||||
arguments
|
||||
: The arguments of the node, represented as a list of KDL values
|
||||
properties
|
||||
: The properties of the node, represented as an attrset of KDL values
|
||||
children
|
||||
: The children of the node, represented as a list of nodes
|
||||
*/
|
||||
node = name: type: arguments: properties: children: {
|
||||
inherit
|
||||
name
|
||||
type
|
||||
arguments
|
||||
properties
|
||||
children
|
||||
;
|
||||
};
|
||||
|
||||
/**
|
||||
Helper function for generating the format of a typed value as expected by pkgs.formats.kdl
|
||||
type
|
||||
: The type of the value, represented by a string
|
||||
value
|
||||
: The value itself
|
||||
*/
|
||||
typed = type: value: { inherit type value; };
|
||||
};
|
||||
|
||||
generate =
|
||||
name: value:
|
||||
pkgs.callPackage (
|
||||
{ runCommand, jsonkdl }:
|
||||
runCommand name
|
||||
{
|
||||
nativeBuildInputs = [ jsonkdl ];
|
||||
value = builtins.toJSON value;
|
||||
passAsFile = [ "value" ];
|
||||
}
|
||||
''
|
||||
jsonkdl --kdl-v1 -- "$valuePath" "$out"
|
||||
''
|
||||
) { };
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue