This commit is contained in:
atagen 2026-02-25 12:18:18 +11:00
commit 0e5218513e
4 changed files with 128 additions and 0 deletions

11
CMakeLists.txt Normal file
View file

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.9)
project(nix-scope-plugin)
find_package(PkgConfig REQUIRED)
pkg_check_modules(NIX_EXPR REQUIRED IMPORTED_TARGET nix-expr)
add_library(nix-scope-plugin MODULE scope.cc)
target_link_libraries(nix-scope-plugin PkgConfig::NIX_EXPR)
set_target_properties(nix-scope-plugin PROPERTIES PREFIX "lib")
install(TARGETS nix-scope-plugin DESTINATION lib/nix/plugins)

27
flake.lock generated Normal file
View file

@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1771923393,
"narHash": "sha256-Fy0+UXELv9hOE8WjYhJt8fMDLYTU2Dqn3cX4BwoGBos=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ea7f1f06811ce7fcc81d6c6fd4213150c23edcf2",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

38
flake.nix Normal file
View file

@ -0,0 +1,38 @@
{
description = "Nix plugin providing a `scope` builtin for constructing nested attrsets from dotted paths";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
outputs = { self, nixpkgs }:
let
supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
in
{
packages = forAllSystems (system:
let
pkgs = nixpkgs.legacyPackages.${system};
nix = pkgs.nix;
in
{
default = pkgs.stdenv.mkDerivation {
pname = "nix-scope-plugin";
version = "0.1.0";
src = self;
nativeBuildInputs = [ pkgs.cmake pkgs.pkg-config ];
buildInputs = [ nix nix.dev pkgs.boost pkgs.nlohmann_json ];
};
});
devShells = forAllSystems (system:
let
pkgs = nixpkgs.legacyPackages.${system};
nix = pkgs.nix;
in
{
default = pkgs.mkShell {
packages = [ pkgs.cmake pkgs.pkg-config nix nix.dev pkgs.boost pkgs.nlohmann_json ];
};
});
};
}

52
scope.cc Normal file
View file

@ -0,0 +1,52 @@
#include <nix/expr/primops.hh>
#include <nix/expr/eval.hh>
#include <nix/expr/eval-inline.hh>
#include <nix/expr/nixexpr.hh>
#include <nix/expr/attr-set.hh>
using namespace nix;
static void prim_scope(EvalState & state, const PosIdx pos, Value ** args, Value & v)
{
std::vector<Symbol> path;
state.forceStringNoCtx(*args[0], pos, "'scope' path argument");
auto s = std::string(args[0]->string_view());
if (s.empty())
state.error<TypeError>("'scope' requires a non-empty path")
.atPos(pos)
.debugThrow();
size_t start = 0;
while (start < s.size()) {
auto dot = s.find('.', start);
if (dot == std::string::npos) {
path.push_back(state.symbols.create(s.substr(start)));
break;
}
path.push_back(state.symbols.create(s.substr(start, dot - start)));
start = dot + 1;
}
// Build nested attrset from inside out
// Given path [a, b, c] and value v: { a = { b = { c = v; }; }; }
Value * inner = args[1];
for (auto it = path.rbegin(); it != path.rend(); ++it) {
auto attrs = state.buildBindings(1);
attrs.insert(*it, inner);
Value * wrapper = state.allocValue();
wrapper->mkAttrs(attrs.finish());
inner = wrapper;
}
v = *inner;
}
static RegisterPrimOp rp({
.name = "scope",
.args = {"path", "value"},
.doc = R"(
Construct a nested attribute set from a dotted string path and a value.
Example: `scope "a.b.c" 42` evaluates to `{ a = { b = { c = 42; }; }; }`.
)",
.fun = prim_scope,
});