-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
lib: add flattenAttrs, remove category processing
Flattening attributes means we no longer need to process categories separately. For all intents and purposes, they do not exist. Simplify the codebase once again, while introducing an easy to grasp recursive function. Add a bit of documentation for toHyprlang, though I doubt it's clear enough even now. Still needs proper NixDoc.
- Loading branch information
Showing
1 changed file
with
100 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,59 +1,122 @@ | ||
lib: with lib; { | ||
lib: with lib; let | ||
toHyprlang = { | ||
topCommandsPrefixes ? ["$"], | ||
bottomCommandsPrefixes ? [], | ||
}: attrs: let | ||
toHyprlang' = attrs: let | ||
toStr = x: | ||
if isBool x | ||
then boolToString x | ||
else toString x; | ||
|
||
categories = filterAttrs (n: v: isAttrs v || (isList v && all isAttrs v)) attrs; | ||
mkCategory = parent: attrs: | ||
if lib.isList attrs | ||
then concatMapStringsSep "\n" (a: mkCategory parent a) attrs | ||
else | ||
concatStringsSep "\n" ( | ||
mapAttrsToList ( | ||
k: v: | ||
if isAttrs v | ||
then mkCategory "${parent}:${k}" v | ||
else if isList v | ||
then concatMapStringsSep "\n" (item: "${parent}:${k} = ${toStr item}") v | ||
else "${parent}:${k} = ${toStr v}" | ||
) | ||
attrs | ||
); | ||
|
||
mkCommands = toKeyValue { | ||
mkKeyValue = mkKeyValueDefault {} " = "; | ||
# Specially configured `toKeyValue` generator with support for duplicate | ||
# keys and legible key-value separator. | ||
mkCommands = generators.toKeyValue { | ||
mkKeyValue = generators.mkKeyValueDefault {} " = "; | ||
listsAsDuplicateKeys = true; | ||
# No indent, since we don't have nesting | ||
indent = ""; | ||
}; | ||
|
||
allCommands = filterAttrs (n: v: !(isAttrs v || (isList v && all isAttrs v))) attrs; | ||
# Flatten the attrset, combining keys in a "path" like `"a:b:c" = "x"`. | ||
# See `flattenAttrs` for more info. | ||
commands = flattenAttrs (p: k: "${p}:${k}") attrs; | ||
|
||
# General filtering command. Used for filtering top/bottom commands. | ||
# Takes a list of prefixes and an element to check. | ||
# Returns true if any of the prefixes matched, otherwise false. | ||
filterCommands = list: n: foldl (acc: prefix: acc || hasPrefix prefix n) false list; | ||
|
||
# Get topCommands attr names | ||
result = partition (filterCommands topCommandsPrefixes) (attrNames allCommands); | ||
# Filter top commands from all commands | ||
topCommands = filterAttrs (n: _: (builtins.elem n result.right)) allCommands; | ||
# FIXME(docs): improve explanations for the below amalgamation | ||
|
||
# Get topCommands attribute names | ||
result = partition (filterCommands topCommandsPrefixes) (attrNames commands); | ||
# Filter top commands from all commands, using the attribute names | ||
# previously obtained | ||
topCommands = filterAttrs (n: _: (builtins.elem n result.right)) commands; | ||
# Remaining commands = allcallCommands - topCommands | ||
remainingCommands = removeAttrs allCommands result.right; | ||
remainingCommands = removeAttrs commands result.right; | ||
|
||
# Get bottomCommands attr names | ||
# Get bottomCommands attr names from commands remaining (in result.wrong) | ||
result2 = partition (filterCommands bottomCommandsPrefixes) result.wrong; | ||
# Filter bottom commands from remainingCommands | ||
# Filter bottom commands from remainingCommands using the attribute names | ||
# previously obtained | ||
bottomCommands = filterAttrs (n: _: (builtins.elem n result2.right)) remainingCommands; | ||
# Regular commands = allCommands - topCommands - bottomCommands | ||
regularCommands = removeAttrs remainingCommands result2.right; | ||
in | ||
mkCommands topCommands | ||
+ concatStringsSep "\n" (mapAttrsToList mkCategory categories) | ||
+ mkCommands regularCommands | ||
+ mkCommands bottomCommands; | ||
# Concatenate the strings resulting from mapping `mkCommands` over the | ||
# list of commands. | ||
concatMapStrings mkCommands [ | ||
topCommands | ||
regularCommands | ||
bottomCommands | ||
]; | ||
in | ||
toHyprlang' attrs; | ||
|
||
|
||
/** | ||
Flatten a nested attribute set into a flat attribute set, joining keys with a user-defined function. | ||
This function takes a function `pred` that determines how nested keys should be joined, | ||
and an attribute set `attrs` that should be flattened. | ||
## Example | ||
```nix | ||
let | ||
nested = { | ||
a = "3"; | ||
b = { c = "4"; d = "5"; }; | ||
}; | ||
separator = (prefix: key: "${prefix}.${key}"); # Use dot notation | ||
in flattenAttrs separator nested | ||
``` | ||
**Output:** | ||
```nix | ||
{ | ||
"a" = "3"; | ||
"b.c" = "4"; | ||
"b.d" = "5"; | ||
} | ||
``` | ||
## Parameters | ||
- **pred** : function `(string -> string -> string)` | ||
A function that takes a prefix and a key and returns the new flattened key. | ||
- **attrs** : attrset | ||
The nested attribute set to be flattened. | ||
## Returns | ||
- **attrset** : A flattened attribute set where keys are joined according to `pred`. | ||
## Notes | ||
- This function works recursively for any level of nesting. | ||
- It does not modify non-attribute values. | ||
- If `pred` is `prefix: key: "${prefix}.${key}"`, it mimics dot notation. | ||
*/ | ||
flattenAttrs = pred: attrs: let | ||
flattenAttrs' = prefix: attrs: | ||
builtins.foldl' ( | ||
acc: key: let | ||
value = attrs.${key}; | ||
newKey = | ||
if prefix == "" | ||
then key | ||
else pred prefix key; | ||
in | ||
acc | ||
// ( | ||
if builtins.isAttrs value | ||
then flattenAttrs' newKey value | ||
else {"${newKey}" = value;} | ||
) | ||
) {} (builtins.attrNames attrs); | ||
in | ||
flattenAttrs' "" attrs; | ||
in | ||
{ | ||
inherit flattenAttrs toHyprlang; | ||
} |