forked from LordMZTE/confgen
Compare commits
4 commits
5a88ad31cf
...
614ec063f0
Author | SHA1 | Date | |
---|---|---|---|
614ec063f0 | |||
bfee9382bd | |||
dbc84f2c99 | |||
488a64809d |
9 changed files with 91 additions and 42 deletions
|
@ -79,8 +79,9 @@ confgenfs /path/to/confgen.lua ~/confgenfs
|
|||
This mounts a FUSE3 filesystem containing all the config files. The advantage of this is that
|
||||
the templates will be generated when the file is opened and not ahead of time.
|
||||
|
||||
Additionally, the filesystem will contain "meta-files" inside `_cgfs/`, currently only `_cgfs/eval`.
|
||||
You can write some Lua code to this file, and it will be evaluated in the global Lua context.
|
||||
Additionally, the filesystem will contain "meta-files" inside `_cgfs/`, currently only `_cgfs/eval`
|
||||
and `_cgfs/opts.json`.
|
||||
You can write some Lua code to the former file, and it will be evaluated in the global Lua context.
|
||||
This allows for dynamic configurations, here's a practical example:
|
||||
|
||||
`.config/waybar/config.cgt`:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.{
|
||||
.name = "confgen",
|
||||
.version = "0.5.0",
|
||||
.version = "0.6.0",
|
||||
|
||||
.dependencies = .{
|
||||
.zig_args = .{
|
||||
|
|
|
@ -66,6 +66,20 @@ pub fn main() u8 {
|
|||
, .{usage});
|
||||
},
|
||||
error.Explained => {},
|
||||
error.LuaError => {
|
||||
// Once Zig is smart enough to remove LuaError from the error set here, we'll
|
||||
// replace this branch with this compile-time check:
|
||||
//comptime {
|
||||
// const ret_errors = @typeInfo(@typeInfo(@typeInfo(@TypeOf(run)).Fn.return_type.?).ErrorUnion.error_set).ErrorSet.?;
|
||||
// for (ret_errors) |err| {
|
||||
// if (std.mem.eql(u8, err.name, "LuaError"))
|
||||
// @compileError("Run function must never return a LuaError!");
|
||||
// }
|
||||
//}
|
||||
|
||||
// We can't get the error message here as the Lua state will alread have been destroyed.
|
||||
std.log.err("UNKNOWN LUA ERROR! THIS IS A BUG!", .{});
|
||||
},
|
||||
else => {
|
||||
std.log.err("UNEXPECTED: {s}", .{@errorName(e)});
|
||||
if (@errorReturnTrace()) |ert| std.debug.dumpStackTrace(ert.*);
|
||||
|
@ -144,14 +158,14 @@ pub fn run() !void {
|
|||
libcg.c.lua_getfield(l, -1, "opt");
|
||||
|
||||
if (arg.positionals.len == 0) {
|
||||
try libcg.json.luaToJSON(l, &wstream);
|
||||
try libcg.format.formats.json.luaToJSON(l, &wstream);
|
||||
libcg.c.lua_pop(l, 1);
|
||||
} else {
|
||||
try wstream.beginObject();
|
||||
for (arg.positionals) |opt| {
|
||||
try wstream.objectField(opt);
|
||||
libcg.c.lua_getfield(l, -1, opt);
|
||||
try libcg.json.luaToJSON(l, &wstream);
|
||||
try libcg.format.formats.json.luaToJSON(l, &wstream);
|
||||
}
|
||||
libcg.c.lua_pop(l, 2);
|
||||
try wstream.endObject();
|
||||
|
|
|
@ -575,7 +575,7 @@ fn generateOptsJSON(self: *FileSystem) ![]const u8 {
|
|||
libcg.c.lua_getglobal(self.l, "cg");
|
||||
libcg.c.lua_getfield(self.l, -1, "opt");
|
||||
|
||||
try libcg.json.luaToJSON(self.l, &wstream);
|
||||
try libcg.format.formats.json.luaToJSON(self.l, &wstream);
|
||||
|
||||
return try buf.toOwnedSlice();
|
||||
}
|
||||
|
|
16
libcg/format.zig
Normal file
16
libcg/format.zig
Normal file
|
@ -0,0 +1,16 @@
|
|||
const std = @import("std");
|
||||
const ffi = @import("ffi.zig");
|
||||
const c = ffi.c;
|
||||
|
||||
pub const formats = struct {
|
||||
pub const json = @import("format/json.zig");
|
||||
};
|
||||
|
||||
pub fn pushFmtTable(l: *c.lua_State) void {
|
||||
c.lua_createtable(l, 0, @typeInfo(formats).Struct.decls.len);
|
||||
|
||||
inline for (@typeInfo(formats).Struct.decls) |decl| {
|
||||
@field(formats, decl.name).luaPush(l);
|
||||
c.lua_setfield(l, -2, decl.name);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,17 @@
|
|||
//! Tools for serialization of Lua values to JSON
|
||||
//! Used by the --json-opt flag
|
||||
const std = @import("std");
|
||||
const ffi = @import("ffi.zig");
|
||||
const ffi = @import("../ffi.zig");
|
||||
const c = ffi.c;
|
||||
|
||||
const luaapi = @import("../luaapi.zig");
|
||||
|
||||
pub fn luaPush(l: *c.lua_State) void {
|
||||
c.lua_createtable(l, 0, 1);
|
||||
c.lua_pushcfunction(l, ffi.luaFunc(lSerialize));
|
||||
c.lua_setfield(l, -2, "serialize");
|
||||
}
|
||||
|
||||
/// Writes a lua object to the stream. stream must be a json.WriteStream
|
||||
pub fn luaToJSON(l: *c.lua_State, stream: anytype) !void {
|
||||
const ty = c.lua_type(l, -1);
|
||||
|
@ -71,3 +79,29 @@ pub fn luaToJSON(l: *c.lua_State, stream: anytype) !void {
|
|||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn lSerialize(l: *c.lua_State) !c_int {
|
||||
c.luaL_checkany(l, 1);
|
||||
const pretty = if (c.lua_gettop(l) >= 2) c.lua_toboolean(l, 2) != 0 else false;
|
||||
|
||||
const state = luaapi.getState(l);
|
||||
|
||||
// If you're doing more than 16KiB of JSON, open an issue
|
||||
// and bring a VERY good explanation with you :D
|
||||
var buf: [1024 * 16]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf);
|
||||
|
||||
var wstream = std.json.WriteStream(@TypeOf(fbs.writer()), .assumed_correct).init(
|
||||
state.files.allocator,
|
||||
fbs.writer(),
|
||||
.{ .whitespace = if (pretty) .indent_2 else .minified },
|
||||
);
|
||||
defer wstream.deinit();
|
||||
|
||||
c.lua_pushvalue(l, 1);
|
||||
try @import("json.zig").luaToJSON(l, &wstream);
|
||||
|
||||
const written = fbs.getWritten();
|
||||
c.lua_pushlstring(l, written.ptr, written.len);
|
||||
return 1;
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
const std = @import("std");
|
||||
const ffi = @import("ffi.zig");
|
||||
const c = ffi.c;
|
||||
|
||||
const format = @import("format.zig");
|
||||
const luagen = @import("luagen.zig");
|
||||
|
||||
const TemplateCode = luagen.TemplateCode;
|
||||
|
@ -92,12 +94,12 @@ pub fn initLuaState(cgstate: *CgState) !*c.lua_State {
|
|||
c.lua_pushcfunction(l, ffi.luaFunc(lOnDone));
|
||||
c.lua_setfield(l, -2, "onDone");
|
||||
|
||||
c.lua_pushcfunction(l, ffi.luaFunc(lToJSON));
|
||||
c.lua_setfield(l, -2, "toJSON");
|
||||
|
||||
c.lua_pushcfunction(l, ffi.luaFunc(lFileIter));
|
||||
c.lua_setfield(l, -2, "fileIter");
|
||||
|
||||
format.pushFmtTable(l);
|
||||
c.lua_setfield(l, -2, "fmt");
|
||||
|
||||
// add cg table to globals
|
||||
c.lua_setglobal(l, "cg");
|
||||
|
||||
|
@ -187,12 +189,17 @@ pub fn generate(l: *c.lua_State, code: TemplateCode) !GeneratedFile {
|
|||
|
||||
if (c.lua_pcall(l, 0, 0, 0) != 0) {
|
||||
std.log.err("failed to run template: {?s}", .{ffi.luaToString(l, -1)});
|
||||
|
||||
return error.RunTemplate;
|
||||
}
|
||||
|
||||
return .{
|
||||
.content = try tmpl.getOutput(l),
|
||||
.content = tmpl.getOutput(l) catch |e| switch (e) {
|
||||
error.LuaError => {
|
||||
std.log.err("failed to run post-processor: {?s}", .{ffi.luaToString(l, -1)});
|
||||
return error.RunPostProcessor;
|
||||
},
|
||||
else => return e,
|
||||
},
|
||||
.mode = tmpl.mode,
|
||||
.assume_deterministic = tmpl.assume_deterministic,
|
||||
};
|
||||
|
@ -503,32 +510,6 @@ fn lOnDone(l: *c.lua_State) !c_int {
|
|||
return 0;
|
||||
}
|
||||
|
||||
fn lToJSON(l: *c.lua_State) !c_int {
|
||||
c.luaL_checkany(l, 1);
|
||||
const pretty = if (c.lua_gettop(l) >= 2) c.lua_toboolean(l, 2) != 0 else false;
|
||||
|
||||
const state = getState(l);
|
||||
|
||||
// If you're doing more than 16KiB of JSON, open an issue
|
||||
// and bring a VERY good explanation with you :D
|
||||
var buf: [1024 * 16]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&buf);
|
||||
|
||||
var wstream = std.json.WriteStream(@TypeOf(fbs.writer()), .assumed_correct).init(
|
||||
state.files.allocator,
|
||||
fbs.writer(),
|
||||
.{ .whitespace = if (pretty) .indent_2 else .minified },
|
||||
);
|
||||
defer wstream.deinit();
|
||||
|
||||
c.lua_pushvalue(l, 1);
|
||||
try @import("json.zig").luaToJSON(l, &wstream);
|
||||
|
||||
const written = fbs.getWritten();
|
||||
c.lua_pushlstring(l, written.ptr, written.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fn lFileIter(l: *c.lua_State) !c_int {
|
||||
const state = getState(l);
|
||||
|
||||
|
@ -650,7 +631,6 @@ pub const LTemplate = struct {
|
|||
/// caller owns return value.
|
||||
fn getOutput(self: *LTemplate, l: *c.lua_State) ![]const u8 {
|
||||
const top = c.lua_gettop(l);
|
||||
defer c.lua_settop(l, top);
|
||||
|
||||
c.lua_pushlightuserdata(l, self);
|
||||
c.lua_gettable(l, c.LUA_REGISTRYINDEX);
|
||||
|
@ -659,6 +639,7 @@ pub const LTemplate = struct {
|
|||
|
||||
// check if there's no post processor
|
||||
if (c.lua_isnil(l, -1)) {
|
||||
c.lua_settop(l, top);
|
||||
return try self.output.allocator.dupe(u8, self.output.items);
|
||||
}
|
||||
|
||||
|
@ -667,11 +648,14 @@ pub const LTemplate = struct {
|
|||
// call post processor
|
||||
if (c.lua_pcall(l, 1, 1, 0) != 0) {
|
||||
try ffi.luaFmtString(l, "running post processor: {?s}", .{ffi.luaToString(l, -1)});
|
||||
c.lua_insert(l, top + 1);
|
||||
c.lua_settop(l, top + 1);
|
||||
return error.LuaError;
|
||||
}
|
||||
|
||||
const out = ffi.luaConvertString(l, -1);
|
||||
|
||||
c.lua_settop(l, top);
|
||||
return try self.output.allocator.dupe(u8, out);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||
pub const c = ffi.c;
|
||||
|
||||
pub const ffi = @import("ffi.zig");
|
||||
pub const json = @import("json.zig");
|
||||
pub const format = @import("format.zig");
|
||||
pub const luaapi = @import("luaapi.zig");
|
||||
pub const luagen = @import("luagen.zig");
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ Example:
|
|||
.B cg.onDone(function(errors) print(\(dqHad errors: \(dq .. tostring(errors)) end)
|
||||
|
||||
.TP
|
||||
.B cg.toJSON(value[, pretty])
|
||||
.B cg.fmt.json.serialize(value[, pretty])
|
||||
Convert an arbitrary lua value to JSON and return that as a string. The JSON will be minified by
|
||||
default unless
|
||||
.IR pretty \ is \ true .
|
||||
|
@ -144,7 +144,7 @@ will be serialized as
|
|||
.IR null .
|
||||
|
||||
Example:
|
||||
.B local json = cg.toJSON({ x = \(dqy\(dq }) -- '{\(dqx\(dq: \(dqy\(dq}'
|
||||
.B local json = cg.fmt.json.serialize({ x = \(dqy\(dq }) -- '{\(dqx\(dq: \(dqy\(dq}'
|
||||
|
||||
.TP
|
||||
.B cg.fileIter()
|
||||
|
|
Loading…
Reference in a new issue