repl: allow :p to print derivation attrs.

Change-Id: I6a6a6964a58c3340acca9272c616c079c5218d6e
This commit is contained in:
Lunaphied
2025-11-19 17:46:52 +01:00
parent 04a4b15991
commit f3b2f3496b
5 changed files with 66 additions and 5 deletions
+20
View File
@@ -0,0 +1,20 @@
---
synopsis: Derivations can now be printed in detail in `nix repl`
cls: [3842]
category: Improvements
credits: [Lunaphied]
---
Traditionally derivations printed in the REPL would only print a formatted object
representing the path of the derivation file it refers to. This makes inspecting
the enhanced derivation attribute sets encountered from `mkDerivation` or similar
wrappers more difficult. Even the `:p`/`:print` command would not elaborate attribute sets
tagged as a derivation.
With this change you can now use `:p`/`:print` to directly inspect a derivation
by providing one as the top-level object. Derivation attribute sets will only be
printed two levels deep and internal derivation attrsets will remain in unexpanded
path form as before. `drvAttrs` will also be elided as these attributes are already
present in the top-level attribute set of the derivation. These heuristics provide
a balance between readability and functionality. When the `:p`/`:print` is omitted,
a bare derivation is printed in the path format as before.
+7 -3
View File
@@ -209,12 +209,14 @@ struct NixRepl
void printValue(std::ostream & str,
Value & v,
unsigned int maxDepth = std::numeric_limits<unsigned int>::max())
unsigned int maxDepth = std::numeric_limits<unsigned int>::max(),
bool replDerivation = false)
{
::nix::printValue(state, str, v, PrintOptions {
.ansiColors = true,
.force = true,
.derivationPaths = true,
.derivationPaths = !replDerivation,
.replDerivation = replDerivation,
.maxDepth = maxDepth,
.prettyIndent = 2,
.errors = ErrorPrintBehavior::ThrowTopLevel,
@@ -793,8 +795,10 @@ ProcessLineResult NixRepl::processLine(std::string line)
evalString(arg, v);
if (v.type() == nString) {
std::cout << v.str();
} else if (v.type() == nAttrs && state.isDerivation(v)) {
printValue(std::cout, v, 2, true);
} else {
printValue(std::cout, v);
printValue(std::cout, v, std::numeric_limits<unsigned int>::max());
}
std::cout << std::endl;
}
+6
View File
@@ -53,6 +53,12 @@ struct PrintOptions
*/
bool derivationPaths = false;
/**
* If true, we are interactively printing a full derivation and should
* switch back to printing paths as desired normally after the first entry.
*/
bool replDerivation = false;
/**
* If true, track which values have been printed and skip them on
* subsequent encounters. Useful for self-referential values.
+21 -2
View File
@@ -286,6 +286,11 @@ private:
} else if (seen && !v.attrs()->empty() && !seen->insert(v.attrs()).second) {
printRepeated();
} else if (depth < options.maxDepth || v.attrs()->empty()) {
bool isPrintingReplDerivation = depth == 0 && options.replDerivation && state.isDerivation(v);
if (isPrintingReplDerivation) {
// Switch back to eliding paths if it was initially off.
options.derivationPaths = true;
}
increaseIndent();
output << "{";
@@ -304,7 +309,7 @@ private:
for (auto & i : sorted) {
printSpace(prettyPrint);
if (attrsPrinted >= options.maxAttrs) {
if (attrsPrinted >= options.maxAttrs ) {
printElided(sorted.size() - printedHere, "attribute", "attributes");
break;
}
@@ -324,6 +329,21 @@ private:
}
output << " = ";
// Elide repeated drvAttrs attribute.
if (isPrintingReplDerivation && i.first == "drvAttrs") {
state.forceValue(i.second->value, noPos);
if (i.second->value.type() == ValueType::nAttrs) {
printElided(i.second->value.attrs()->size(), "attribute", "attributes");
} else {
print(i.second->value, depth + 1);
}
output << ";";
attrsPrinted++;
printedHere++;
continue;
}
print(i.second->value, depth + 1);
output << ";";
attrsPrinted++;
@@ -582,7 +602,6 @@ public:
seen.reset();
}
ValuesSeen seen;
print(v, 0);
}
};
@@ -100,3 +100,15 @@ Printing an environment with :env after adding a variable to the scope
Env level 1
abort baseNameOf break builtins derivation derivationStrict dirOf false fetchGit fetchMercurial fetchTarball fetchTree fromTOML import isNull map null placeholder removeAttrs scopedImport throw toString true
Printing a derivation or something
nix-repl> fakeDrv = let drvAttrs = { builder = "meow"; system = "meower"; name = "mrowmrow"; }; in { inherit (drvAttrs) builder system name; inherit drvAttrs; type = "derivation"; }
nix-repl> :p fakeDrv
{
builder = "meow";
drvAttrs = «3 attributes elided»;
name = "mrowmrow";
system = "meower";
type = "derivation";
}