Nix code generator using rnix/rowan. Build Nix AST programmatically with a closure-based builder API.
# Cargo.toml
[dependencies]
genemator = { git = "https://github.com/xinux-org/genemator" }Or via CLI:
cargo add --git https://github.com/xinux-org/genematoruse genemator::NixBuilder;
fn main() {
let mut b = NixBuilder::new();
b.attr_set(|b| {
b.binding("pname", |b| b.string("hello"));
b.binding("version", |b| b.string("1.0"));
b.binding("src", |b| b.path("./."));
});
// Raw output
println!("{}", b.finish());
// { pname = "hello"; version = "1.0"; src = ./.; }
// Or formatted via nixpkgs-fmt
// println!("{}", b.format());
}b.string("hello") // "hello"
b.int(42) // 42
b.float(3.14) // 3.14
b.bool(true) // true
b.null() // null
b.path("./src") // ./src
b.path("/etc/nixos") // /etc/nixos
b.path("~/config") // ~/config
b.ident("pkgs") // pkgsb.attr_set(|b| {
b.binding("foo", |b| b.string("bar"));
b.binding("nested", |b| {
b.attr_set(|b| b.binding("x", |b| b.int(1)))
});
});
// { foo = "bar"; nested = { x = 1; }; }
b.rec_attr_set(|b| {
b.binding("a", |b| b.int(1));
b.binding("b", |b| b.ident("a"));
});
// rec { a = 1; b = a; }b.list(|b| {
b.int(1);
b.ws();
b.string("two");
b.ws();
b.ident("three");
});
// [ 1 "two" three ]b.let_in(
|b| {
b.binding("x", |b| b.int(1));
b.binding("y", |b| b.int(2));
},
|b| b.ident("x")
);
// let x = 1; y = 2; in x// Lambda
b.lambda("x", |b| b.ident("x"));
// x: x
// Pattern lambda
use genemator::PatternParam;
let params: Vec<PatternParam> = vec![
("config", None),
("pkgs", None),
];
b.lambda_pattern(¶ms, |b| b.attr_set(|_| {}));
// { config, pkgs }: { }
// With default
let default: &dyn Fn(&mut NixBuilder) = &|b| b.int(1);
let params: Vec<PatternParam> = vec![("x", Some(default))];
b.lambda_pattern(¶ms, |b| b.ident("x"));
// { x ? 1 }: x
// Function application
b.apply(|b| b.ident("f"), |b| b.ident("x"));
// f x
b.apply(
|b| b.ident("f"),
|b| b.paren(|b| b.apply(|b| b.ident("g"), |b| b.ident("x")))
);
// f (g x)b.if_then_else(
|b| b.bool(true),
|b| b.int(1),
|b| b.int(2)
);
// if true then 1 else 2
b.with_expr(
|b| b.ident("pkgs"),
|b| b.list(|b| {
b.ident("git");
b.ws();
b.ident("vim");
})
);
// with pkgs; [ git vim ]b.attr_set(|b| {
b.inherit(&["foo", "bar"]);
});
// { inherit foo bar; }
b.attr_set(|b| {
b.inherit_from(|b| b.ident("pkgs"), &["git", "vim"]);
});
// { inherit (pkgs) foo bar; }b.interpolated_string(|s| {
s.literal("Hello ");
s.interpolate(|b| b.ident("name"));
s.literal("!");
});
// "Hello ${name}!"// Get SyntaxNode
let node = b.finish();
println!("{}", node);
// Get formatted string via nixpkgs-fmt
let formatted = b.format();let mut b = NixBuilder::new();
b.attr_set(|b| {
b.binding("pname", |b| b.string("myapp"));
b.binding("version", |b| b.string("1.0.0"));
b.binding("src", |b| b.path("./."));
b.binding("buildInputs", |b| {
b.with_expr(
|b| b.ident("pkgs"),
|b| b.list(|b| {
b.ident("openssl");
b.ws();
b.ident("zlib");
})
)
});
});let mut b = NixBuilder::new();
let params: Vec<PatternParam> = vec![
("config", None),
("lib", None),
("pkgs", None),
];
b.lambda_pattern(¶ms, |b| {
b.attr_set(|b| {
b.binding("options", |b| b.attr_set(|_| {}));
b.binding("config", |b| b.attr_set(|_| {}));
})
});let mut b = NixBuilder::new();
b.attr_set(|b| {
b.binding("description", |b| b.string("My flake"));
b.binding("inputs", |b| {
b.attr_set(|b| {
b.binding("nixpkgs", |b| {
b.attr_set(|b| {
b.binding("url", |b| b.string("github:nixos/nixpkgs/nixos-unstable"));
})
});
})
});
b.binding("outputs", |b| {
b.lambda("inputs", |b| b.attr_set(|_| {}))
});
});GPL-3.0