mirror of
https://github.com/nix-community/home-manager
synced 2024-11-20 01:59:45 +01:00
lib: add generator for KDL
Added a generator for the KDL document language. This is in order for home-manager to natively generate the new config format for zellij, as described in nix-community#3364. There is not a one to one mapping between KDL and nix types, but attrset translation is heavily based on KDLs JSON-IN-KDL microsyntax. The exception here is the `_args` and `_props` arguments, which lets you specify arguments and properties as described in the spec. See more here: - https://kdl.dev/ - https://github.com/kdl-org/kdl/blob/main/SPEC.md The generator also conforms to the interface from the nixpkgs manual: https://nixos.org/manual/nixpkgs/stable/#sec-generators Co-authored-by: Gaetan Lepage <gaetan@glepage.com>
This commit is contained in:
parent
36999b8d19
commit
fce9dbfeb4
7 changed files with 202 additions and 0 deletions
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
|
@ -16,6 +16,9 @@ Makefile @thiagokokada
|
||||||
|
|
||||||
/modules/launchd @midchildan
|
/modules/launchd @midchildan
|
||||||
|
|
||||||
|
/modules/lib/generators.nix @h7x4
|
||||||
|
/test/lib/generators @h7x4
|
||||||
|
|
||||||
/modules/misc/dconf.nix @rycee
|
/modules/misc/dconf.nix @rycee
|
||||||
|
|
||||||
/modules/misc/editorconfig.nix @loicreynier
|
/modules/misc/editorconfig.nix @loicreynier
|
||||||
|
|
|
@ -6,6 +6,7 @@ rec {
|
||||||
assertions = import ./assertions.nix { inherit lib; };
|
assertions = import ./assertions.nix { inherit lib; };
|
||||||
|
|
||||||
booleans = import ./booleans.nix { inherit lib; };
|
booleans = import ./booleans.nix { inherit lib; };
|
||||||
|
generators = import ./generators.nix { inherit lib; };
|
||||||
gvariant = import ./gvariant.nix { inherit lib; };
|
gvariant = import ./gvariant.nix { inherit lib; };
|
||||||
maintainers = import ./maintainers.nix;
|
maintainers = import ./maintainers.nix;
|
||||||
strings = import ./strings.nix { inherit lib; };
|
strings = import ./strings.nix { inherit lib; };
|
||||||
|
|
102
modules/lib/generators.nix
Normal file
102
modules/lib/generators.nix
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
{ lib }:
|
||||||
|
|
||||||
|
{
|
||||||
|
toKDL = { }:
|
||||||
|
let
|
||||||
|
inherit (lib) concatStringsSep splitString mapAttrsToList any;
|
||||||
|
inherit (builtins) typeOf replaceStrings elem;
|
||||||
|
|
||||||
|
# ListOf String -> String
|
||||||
|
indentStrings = let
|
||||||
|
# Although the input of this function is a list of strings,
|
||||||
|
# the strings themselves *will* contain newlines, so you need
|
||||||
|
# to normalize the list by joining and resplitting them.
|
||||||
|
unlines = lib.splitString "\n";
|
||||||
|
lines = lib.concatStringsSep "\n";
|
||||||
|
indentAll = lines: concatStringsSep "\n" (map (x: " " + x) lines);
|
||||||
|
in stringsWithNewlines: indentAll (unlines (lines stringsWithNewlines));
|
||||||
|
|
||||||
|
# String -> String
|
||||||
|
sanitizeString = replaceStrings [ "\n" ''"'' ] [ "\\n" ''\"'' ];
|
||||||
|
|
||||||
|
# OneOf [Int Float String Bool Null] -> String
|
||||||
|
literalValueToString = element:
|
||||||
|
lib.throwIfNot
|
||||||
|
(elem (typeOf element) [ "int" "float" "string" "bool" "null" ])
|
||||||
|
"Cannot convert value of type ${typeOf element} to KDL literal."
|
||||||
|
(if typeOf element == "null" then
|
||||||
|
"null"
|
||||||
|
else if element == false then
|
||||||
|
"false"
|
||||||
|
else if element == true then
|
||||||
|
"true"
|
||||||
|
else if typeOf element == "string" then
|
||||||
|
''"${sanitizeString element}"''
|
||||||
|
else
|
||||||
|
toString element);
|
||||||
|
|
||||||
|
# Attrset Conversion
|
||||||
|
# String -> AttrsOf Anything -> String
|
||||||
|
convertAttrsToKDL = name: attrs:
|
||||||
|
let
|
||||||
|
optArgsString = lib.optionalString (attrs ? "_args")
|
||||||
|
(lib.pipe attrs._args [
|
||||||
|
(map literalValueToString)
|
||||||
|
(lib.concatStringsSep " ")
|
||||||
|
(s: s + " ")
|
||||||
|
]);
|
||||||
|
|
||||||
|
optPropsString = lib.optionalString (attrs ? "_props")
|
||||||
|
(lib.pipe attrs._props [
|
||||||
|
(lib.mapAttrsToList
|
||||||
|
(name: value: "${name}=${literalValueToString value}"))
|
||||||
|
(lib.concatStringsSep " ")
|
||||||
|
(s: s + " ")
|
||||||
|
]);
|
||||||
|
|
||||||
|
children =
|
||||||
|
lib.filterAttrs (name: _: !(elem name [ "_args" "_props" ])) attrs;
|
||||||
|
in ''
|
||||||
|
${name} ${optArgsString}${optPropsString}{
|
||||||
|
${indentStrings (mapAttrsToList convertAttributeToKDL children)}
|
||||||
|
}'';
|
||||||
|
|
||||||
|
# List Conversion
|
||||||
|
# String -> ListOf (OneOf [Int Float String Bool Null]) -> String
|
||||||
|
convertListOfFlatAttrsToKDL = name: list:
|
||||||
|
let flatElements = map literalValueToString list;
|
||||||
|
in "${name} ${concatStringsSep " " flatElements}";
|
||||||
|
|
||||||
|
# String -> ListOf Anything -> String
|
||||||
|
convertListOfNonFlatAttrsToKDL = name: list: ''
|
||||||
|
${name} {
|
||||||
|
${indentStrings (map (x: convertAttributeToKDL "-" x) list)}
|
||||||
|
}'';
|
||||||
|
|
||||||
|
# String -> ListOf Anything -> String
|
||||||
|
convertListToKDL = name: list:
|
||||||
|
let elementsAreFlat = !any (el: elem (typeOf el) [ "list" "set" ]) list;
|
||||||
|
in if elementsAreFlat then
|
||||||
|
convertListOfFlatAttrsToKDL name list
|
||||||
|
else
|
||||||
|
convertListOfNonFlatAttrsToKDL name list;
|
||||||
|
|
||||||
|
# Combined Conversion
|
||||||
|
# String -> Anything -> String
|
||||||
|
convertAttributeToKDL = name: value:
|
||||||
|
let vType = typeOf value;
|
||||||
|
in if elem vType [ "int" "float" "bool" "null" "string" ] then
|
||||||
|
"${name} ${literalValueToString value}"
|
||||||
|
else if vType == "set" then
|
||||||
|
convertAttrsToKDL name value
|
||||||
|
else if vType == "list" then
|
||||||
|
convertListToKDL name value
|
||||||
|
else
|
||||||
|
throw ''
|
||||||
|
Cannot convert type `(${typeOf value})` to KDL:
|
||||||
|
${name} = ${toString value}
|
||||||
|
'';
|
||||||
|
in attrs: ''
|
||||||
|
${concatStringsSep "\n" (mapAttrsToList convertAttributeToKDL attrs)}
|
||||||
|
'';
|
||||||
|
}
|
|
@ -47,6 +47,7 @@ import nmt {
|
||||||
inherit lib pkgs modules;
|
inherit lib pkgs modules;
|
||||||
testedAttrPath = [ "home" "activationPackage" ];
|
testedAttrPath = [ "home" "activationPackage" ];
|
||||||
tests = builtins.foldl' (a: b: a // (import b)) { } ([
|
tests = builtins.foldl' (a: b: a // (import b)) { } ([
|
||||||
|
./lib/generators
|
||||||
./lib/types
|
./lib/types
|
||||||
./modules/files
|
./modules/files
|
||||||
./modules/home-environment
|
./modules/home-environment
|
||||||
|
|
1
tests/lib/generators/default.nix
Normal file
1
tests/lib/generators/default.nix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{ generators-tokdl = ./tokdl.nix; }
|
41
tests/lib/generators/tokdl-result.txt
Normal file
41
tests/lib/generators/tokdl-result.txt
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
a 1
|
||||||
|
b "string"
|
||||||
|
bigFlatItems 23847590283751 1.239000 "multiline \" \" \"\nstring\n" null
|
||||||
|
c "multiline string\nwith special characters:\n\t \n \\" \"\n"
|
||||||
|
extraAttrs 2 true arg1=1 arg2=false {
|
||||||
|
nested {
|
||||||
|
a 1
|
||||||
|
b null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flatItems 1 2 "asdf" true null
|
||||||
|
listInAttrsInList {
|
||||||
|
list1 {
|
||||||
|
- {
|
||||||
|
a 1
|
||||||
|
}
|
||||||
|
- {
|
||||||
|
b true
|
||||||
|
}
|
||||||
|
- {
|
||||||
|
c null
|
||||||
|
d {
|
||||||
|
- {
|
||||||
|
e "asdfadfasdfasdf"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list2 {
|
||||||
|
- {
|
||||||
|
a 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nested {
|
||||||
|
- 1 2
|
||||||
|
- true false
|
||||||
|
-
|
||||||
|
- null
|
||||||
|
}
|
||||||
|
unsafeString " \" \n "
|
53
tests/lib/generators/tokdl.nix
Normal file
53
tests/lib/generators/tokdl.nix
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
home.file."result.txt".text = lib.hm.generators.toKDL { } {
|
||||||
|
a = 1;
|
||||||
|
b = "string";
|
||||||
|
c = ''
|
||||||
|
multiline string
|
||||||
|
with special characters:
|
||||||
|
\t \n \" "
|
||||||
|
'';
|
||||||
|
unsafeString = " \" \n ";
|
||||||
|
flatItems = [ 1 2 "asdf" true null ];
|
||||||
|
bigFlatItems = [
|
||||||
|
23847590283751
|
||||||
|
1.239
|
||||||
|
''
|
||||||
|
multiline " " "
|
||||||
|
string
|
||||||
|
''
|
||||||
|
null
|
||||||
|
];
|
||||||
|
nested = [ [ 1 2 ] [ true false ] [ ] [ null ] ];
|
||||||
|
extraAttrs = {
|
||||||
|
_args = [ 2 true ];
|
||||||
|
_props = {
|
||||||
|
arg1 = 1;
|
||||||
|
arg2 = false;
|
||||||
|
};
|
||||||
|
nested = {
|
||||||
|
a = 1;
|
||||||
|
b = null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
listInAttrsInList = {
|
||||||
|
list1 = [
|
||||||
|
{ a = 1; }
|
||||||
|
{ b = true; }
|
||||||
|
{
|
||||||
|
c = null;
|
||||||
|
d = [{ e = "asdfadfasdfasdf"; }];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
list2 = [{ a = 8; }];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileContent \
|
||||||
|
home-files/result.txt \
|
||||||
|
${./tokdl-result.txt}
|
||||||
|
'';
|
||||||
|
}
|
Loading…
Reference in a new issue