How you can write ugly lisp code by compiling it from even uglier nix code...
So i just did a thing:
{lib, ...}:
with builtins;
with lib; let
# generates a space with the same length like a given string
genSpace = string: concatStrings (genList (x: " ") (stringLength string));
# concatStringsSep "\n" but separater at the begin too
myConcatStringsSep = sep: list: concatStrings (map (x: "\n" + sep + x) list);
# takes a list of objects and concatMaps them to a string
toYuck = list: assert isList list; concatStringsSep "\n" (map (mkValueString "") list);
# makes a yuck object (string, bool, integer, function call, etc) to string
mkValueString = oldindent: value:
if isAttrs value
then let
# name content and attrs are not vital attributes, empty by default
attrs =
{
name = "";
content = [];
attrs = {};
}
// value;
# create add new indentation level
indent = "${oldindent} ${genSpace attrs.func}";
in
# function call
"(${attrs.func} ${attrs.name}"
# newline if name is not empty
+ (
if attrs.name == ""
then ""
else "\n${indent}"
)
# the attributes the function is called with
+ concatStringsSep "\n${indent}" (
mapAttrsToList (name2: value2: ":${name2} " + mkValueString "${indent} ${genSpace name2}" value2)
attrs.attrs
)
# the content of the called function
+ myConcatStringsSep indent (
map (mkValueString "${indent}") attrs.content
)
# the ending parenthesis of a function call
+ ")"
else if isString value
then ''"${value}"''
else if isInt value
then toString value
else if isBool value
then
if value
then "true"
else "false"
else throw "Unrecognized value type";
in
toYuck
Because I hated how the yuck syntax looked and i wanted to create my Eww config in nix, being able to variate it with variables within nix.
The problem is, even tho this is ugly as hell:
(defwindow example
:geometry (geometry :anchor "top center"
:height "30px"
:width "90%"
:x "0%"
:y "20px")
:monitor 0
:reserve (struts :distance "40px"
:side "top")
:stacking "fg"
:windowtype "dock"
:wm-ignore false
"hello")
I still managed to make it even uglier and unreadable:
{lib, ...}:
import ./toYuck.nix {inherit lib;} [
{
func = "defwindow";
name = "example";
attrs = {
monitor = 0;
geometry = {
func = "geometry";
attrs = {
x = "0%";
y = "20px";
width = "90%";
height = "30px";
anchor = "top center";
};
};
stacking = "fg";
reserve = {
func = "struts";
attrs = {
distance = "40px";
side = "top";
};
};
windowtype = "dock";
wm-ignore = false;
};
content = ["hello"];
}
]
lol
edit: it is actually pretty easy to improve this, by just following the general paradigm of lisp dialects: everything is a list. So the conversion function would be:
{lib, ...}:
with builtins;
with lib; let
# generates a space with the same length like a given string
genSpace = string: concatStrings (genList (x: " ") (stringLength string));
# takes a list of objects and concats them to a string
toYuck = list: assert isList list; concatStringsSep "\n" (map (mkValueString "") list);
# makes a lisp object (string, bool, integer, list, etc) to string
mkValueString = oldindent: value:
if isList value
then let
# create add new indentation level
# first element of list has to be a string (function name)
indent = "${oldindent} ${genSpace (elemAt value 0)}";
# make string for the named arguments
mkNamedArguments = attrs:
concatStringsSep "\n${indent}" (
mapAttrsToList (
name2: value2:
":${name2} "
+ mkValueString "${indent} ${genSpace name2}" value2
)
attrs
);
in
"("
+ concatStringsSep "\n${indent}" (
map (
x:
if isAttrs x
then mkNamedArguments x
else mkValueString indent x
)
value
)
+ ")"
else if isString value
then value
else if isInt value
then toString value
else if isBool value
then
if value
then "true"
else "false"
else throw "Unrecognized value type";
in
toYuck
and the unconverted nix code:
[
[
"defwindow"
"example"
{
monitor = 0;
geometry = [
"geometry"
{
x = str "0%";
y = str "20px";
width = str "90%";
height = str "30px";
anchor = str "top center";
}
];
stacking = str "fg";
reserve = [
"struts"
{
distance = str "40px";
side = str "top";
}
];
windowtype = str "dock";
wm-ignore = false;
}
(str "hello")
]
]
we can also format this lisp-ly:
[
["defwindow" "example" {
monitor = 0;
geometry = [ "geometry" {
x = str "0%";
y = str "20px";
width = str "90%";
height = str "30px";
anchor = str "top center"; }];
stacking = str "fg";
reserve = [ "struts" {
distance = str "40px";
side = str "top"; }];
windowtype = str "dock";
wm-ignore = false;}
(str "hello")]
]
(licensed under CC BY-SA 4.0)