feat: lua render now handle indentation

dev
LeMarsu 2026-03-08 05:36:42 +01:00
parent 1d6bc88719
commit aff1dbc079
10 changed files with 275 additions and 80 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.direnv .direnv
.envrc .envrc
result

View File

@ -16,6 +16,7 @@
./dev ./dev
./flakeModule.nix ./flakeModule.nix
./lib ./lib
./tests
]; ];
}); });
} }

View File

@ -25,7 +25,7 @@
modules = mkOption { modules = mkOption {
description = "modules used to create your neovim package"; description = "modules used to create your neovim package";
type = with types; listOf attrs; type = with types; listOf deferredModule;
default = [config.module]; default = [config.module];
}; };

View File

@ -10,7 +10,7 @@
inherit (lib.attrsets) attrNames optionalAttrs; inherit (lib.attrsets) attrNames optionalAttrs;
inherit (lib.lists) concatMap; inherit (lib.lists) concatMap;
inherit (lib.strings) fileContents splitString; inherit (lib.strings) fileContents splitString;
lua = callPackage ./lua.nix {}; lua = callPackage ./legacyLua.nix {};
callPackage = lib.callPackageWith (pkgs // dependenciesExtraArgs); callPackage = lib.callPackageWith (pkgs // dependenciesExtraArgs);
hasMatch = pattern: str: isList (match pattern str); hasMatch = pattern: str: isList (match pattern str);
@ -144,7 +144,7 @@
''; '';
}; };
versionLua = version: with lua; nix2lua (return (lambda (return version))); versionLua = version: with lua; nix2lua (return (lambda [] (return version)));
textOrContent = content: textOrContent = content:
if isPath content if isPath content
@ -156,7 +156,7 @@
content = textOrContent plugin.${type}; content = textOrContent plugin.${type};
in in
optionalAttrs (! isNull plugin.${type}) { optionalAttrs (! isNull plugin.${type}) {
${type} = with lua; lambda (raw content); ${type} = with lua; lambda [] (raw content);
}; };
pluginName = plugin: pluginName = plugin:
if plugin ? pname if plugin ? pname

92
lib/legacyLua.nix Normal file
View File

@ -0,0 +1,92 @@
{...}: let
inherit (builtins) match isNull typeOf concatStringsSep attrNames concatMap;
fix = f: let x = f x; in x;
commaJoin = concatStringsSep ", ";
wrapNotNull' = val: value:
if isNull val
then []
else [value];
wrapNotNull = val: wrapNotNull' val val;
toLua = {
ast = {
raw = {data, ...}: data;
return = {data, ...}: "return ${nix2lua data}";
fn = {
data,
name,
args,
...
}: "function ${name}(${commaJoin args})\n${nix2lua data}\nend";
};
type = fix (type: {
null = _: "nil";
string = data: ''"${data}"'';
path = type.string;
lambda = data: builtins.trace "Skipping function" null;
int = data: toString data;
bool = data:
if data
then "true"
else "false";
ast = data: let
astType = data.__ast;
in
if toLua.ast ? ${astType}
then toLua.ast.${astType} data
else abort ''Unknown ast type ${astType}'';
list = data: let
nix2luaList = val: wrapNotNull (nix2lua val);
listContent = commaJoin (concatMap nix2luaList data);
in "{ ${listContent} }";
set = data: let
mkKeyValue = key: let
value = data.${key};
luaKey =
if isNull (match "[a-zA-Z_][a-zA-Z_0-9]+" key)
then ''["${key}"]''
else key;
luaValue = nix2lua value;
in
wrapNotNull' luaValue ''
${luaKey} = ${luaValue},
'';
attrsContent = concatMap mkKeyValue (attrNames data);
in ''
{
${concatStringsSep "" attrsContent}}
'';
});
};
newAst = type: set: set // {__ast = type;};
nix2lua = data: let
type = typeOf data;
in
if data ? __ast
then toLua.type.ast data
else if toLua.type ? ${type}
then toLua.type.${type} data
else abort ''Type "${type}"'';
in
fix (lua: {
inherit nix2lua;
raw = data: newAst "raw" {inherit data;};
function = name: args: data:
newAst "fn" {
inherit name data args;
};
lambda = lua.function "";
return = data: newAst "return" {inherit data;};
})

View File

@ -1,92 +1,132 @@
{...}: let {pkgs, ...}: let
inherit (builtins) match isNull typeOf concatStringsSep attrNames concatMap; inherit
(builtins)
attrNames
concatStringsSep
filter
isAttrs
isBool
isFloat
isInt
isList
isPath
isNull
isString
match
toJSON
typeOf
;
inherit
(pkgs.lib)
assertMsg
concatStrings
fix
imap0
isDerivation
mapAttrsToList
optionalString
splitString
toPretty
;
commaJoin = concatStringsSep ", "; commaJoin = concatStringsSep ", ";
wrapNotNull' = val: value:
if isNull val
then []
else [value];
wrapNotNull = val: wrapNotNull' val val;
toLua = { renderLua = {
multiline ? true,
indent ? "",
asBindings ? false,
} @ args: v: let
innerIndent = "${indent} ";
introSpace =
if multiline
then "\n${innerIndent}"
else " ";
outroSpace =
if multiline
then "\n${indent}"
else " ";
innerArgs =
args
// {
indent =
if asBindings
then indent
else innerIndent;
asBindings = false;
};
ast = { ast = {
raw = {data, ...}: data; render = args: data: let
return = {data, ...}: "return ${nix2lua data}"; astType = data.__ast;
fn = { in
if ast ? ${astType}
then ast.${astType} args data
else abort ''Unknown ast type ${astType}'';
raw = args: {
data,
__no_indent ? false,
...
}: let
content =
if __no_indent
then data
else concatStringsSep "\n" (imap0 (idx: line: "${optionalString (idx != 0) args.indent}${line}") (splitString "\n" data));
in
content;
return = args: {data, ...}: "return ${renderLua args data}";
fn = args: {
data, data,
name, name,
args, args,
... ...
}: "function ${name}(${commaJoin args})\n${nix2lua data}\nend"; }: "function ${name}(${commaJoin args})${introSpace}${renderLua innerArgs data}${outroSpace}end";
}; };
type = rec { generatedBindings = assert assertMsg (badBindingNames == []) "Bad Lua var names: ${toPretty {} badBindingNames}";
null = _: "nil"; concatStrings (mapAttrsToList (key: value: "${indent}${key} = ${renderLua innerArgs value}\n") v);
string = data: ''"${data}"'';
path = string;
lambda = data: builtins.trace "Skipping function" null;
int = data: toString data;
bool = data: concatItems = concatStringsSep ",${introSpace}";
if data varNameRe = "[[:alpha:]_][[:alnum:]_]*";
then "true" matchBindingName = match "${varNameRe}(\\.${varNameRe})*";
else "false"; badBindingNames = filter (name: matchBindingName name == null) (attrNames v);
ast = data: let luaKey = key:
astType = data.__ast; if match varNameRe key == null
in then "[${toJSON key}]"
if toLua.ast ? ${astType} else key;
then toLua.ast.${astType} data
else abort ''Unknown ast type ${astType}'';
list = data: let withSpaces = val: optionalString (val != "") "${introSpace}${val}${outroSpace}";
nix2luaList = val: wrapNotNull (nix2lua val);
listContent = commaJoin (concatMap nix2luaList data);
in "{ ${listContent} }";
set = data: let mkKV = key: value: "${luaKey key} = ${renderLua innerArgs value}";
mkKeyValue = key: let in
value = data.${key}; if asBindings
luaKey = then generatedBindings
if isNull (match "[a-zA-Z_][a-zA-Z_0-9]+" key) else if isNull v
then ''["${key}"]'' then "nil"
else key; else if isInt v || isFloat v || isString v || isBool v
luaValue = nix2lua value; then toJSON v
in else if isPath v || isDerivation v
wrapNotNull' luaValue '' then toJSON "${v}"
${luaKey} = ${luaValue}, else if isList v
''; then "{${withSpaces (concatItems (map (renderLua innerArgs) v))}}"
attrsContent = concatMap mkKeyValue (attrNames data); else if v ? __ast
in '' then ast.render args v
{ else if isAttrs v
${concatStringsSep "" attrsContent}} then "{${withSpaces (concatItems (mapAttrsToList mkKV v))}}"
''; else abort "generators.renderLua: type ${typeOf v} is unsupported";
};
};
newAst = type: set: set // {__ast = type;}; newAst = type: set: set // {__ast = type;};
in
fix (lua: {
inherit renderLua;
nix2lua = data: let writeLua = name: value: pkgs.writeText name (lua.renderLua {} value);
type = typeOf data;
in
if data ? __ast
then toLua.type.ast data
else if toLua.type ? ${type}
then toLua.type.${type} data
else abort ''Type "${type}"'';
in rec {
inherit nix2lua;
raw = data: newAst "raw" {inherit data;}; raw = data: newAst "raw" {inherit data;};
functionWithArgs = name: args: data: function = name: args: data: newAst "fn" {inherit name data args;};
newAst "fn" {
inherit name data args;
};
function = name: data: functionWithArgs name [] data; lambda = lua.function "";
lambda = function ""; return = data: newAst "return" {inherit data;};
})
return = data: newAst "return" {inherit data;};
}

View File

@ -5,7 +5,7 @@
}: let }: let
inherit (builtins) isPath; inherit (builtins) isPath;
inherit (pkgs.lib) fileContents fix literalExample mergeAttrsList mkOption optionalAttrs types; inherit (pkgs.lib) fileContents fix literalExample mergeAttrsList mkOption optionalAttrs types;
lua = import ../../lua.nix {}; lua = callModule ../../lua.nix {};
modules = { modules = {
keymap = callModule ./keymap.nix {}; keymap = callModule ./keymap.nix {};
@ -37,7 +37,7 @@
content = textOrContent plugin.${type}; content = textOrContent plugin.${type};
in in
optionalAttrs (! isNull plugin.${type}) { optionalAttrs (! isNull plugin.${type}) {
${type} = with lua; lambda (raw content); ${type} = with lua; lambda [] (raw content);
}; };
name = getPluginName plugin.plugin; name = getPluginName plugin.plugin;
in in

View File

@ -1,15 +1,16 @@
{ {
pkgs, pkgs,
sloth, sloth,
callModule,
... ...
}: let }: let
inherit (pkgs) vimUtils; inherit (pkgs) vimUtils;
inherit (pkgs.lib) fix listToAttrs nameValuePair; inherit (pkgs.lib) fix listToAttrs nameValuePair;
fs = pkgs.lib.fileset; fs = pkgs.lib.fileset;
lua = import ../lua.nix {}; lua = callModule ../lua.nix {};
versionLua = version: with lua; nix2lua (return (lambda (return version))); versionLua = version: with lua; renderLua {} (return (lambda [] (return version)));
luaDefsToLua = luaDefs: with lua; nix2lua (return luaDefs); luaDefsToLua = luaDefs: with lua; renderLua {} (return luaDefs);
in in
fix (self: { fix (self: {
mkSlothPlugin = luaDefs: mkSlothPlugin = luaDefs:

32
tests/default.nix Normal file
View File

@ -0,0 +1,32 @@
{
perSystem = {pkgs, ...}: let
lua = import ../lib/lua.nix {inherit pkgs;};
diffFiles = actual: expected:
pkgs.runCommandWith {
name = "diffFiles";
derivationArgs.nativeBuildInputs = [pkgs.diffutils];
}
''
diff -u ${expected} ${actual}
echo "Comparaison successful."
touch $out
'';
in {
checks.luaRender =
diffFiles ./luaRender.lua
<| lua.writeLua "debug.lua" {
a.b.c = 42;
list = [42 4.2 true false null];
fn = lua.lambda [] <| lua.raw "print('hello world')";
math.succ = lua.function "" ["n"] <| lua.return <| lua.raw "n + 1";
non-var-name = 42;
multilineFunc =
lua.function "" []
<| lua.raw ''
print("hello world")
print("goodbye world")
'';
};
};
}

28
tests/luaRender.lua Normal file
View File

@ -0,0 +1,28 @@
{
a = {
b = {
c = 42
}
},
fn = function ()
print('hello world')
end,
list = {
42,
4.2,
true,
false,
nil
},
math = {
succ = function (n)
return n + 1
end
},
multilineFunc = function ()
print("hello world")
print("goodbye world")
end,
["non-var-name"] = 42
}