aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralois31 <alois1@gmx-topmail.de>2024-07-19 06:40:13 +0000
committerGerrit Code Review <gerrit@localhost>2024-07-19 06:40:13 +0000
commitaba5f19680b2f4c29d7ce2ff5e2a89128c1cb26d (patch)
treec1c3ce68cd7aab98167a394e11934ebcaed27ade
parent5ee1e6ea9887a54f0af3a66528abc04b17611516 (diff)
parent768d1f29a2dcd9ed9552fafb4ab836ea2e400738 (diff)
Merge changes I829581a3,I0016970d,I5dac8e77,Ib7560fe5 into main
* changes: doc/release-notes: add for pretty printing improvements libexpr/print: do not show elided nested items when there are none libexpr/print: never show empty attrsets or derivations as «repeated» libexpr/print: pretty-print idempotently
-rw-r--r--doc/manual/rl-next/pretty-printing.md58
-rw-r--r--src/libexpr/print.cc25
-rw-r--r--tests/functional/repl_characterization/data/idempotent.test13
-rw-r--r--tests/functional/repl_characterization/repl_characterization.cc1
-rw-r--r--tests/unit/libexpr/value/print.cc67
5 files changed, 132 insertions, 32 deletions
diff --git a/doc/manual/rl-next/pretty-printing.md b/doc/manual/rl-next/pretty-printing.md
new file mode 100644
index 000000000..f7953f9ff
--- /dev/null
+++ b/doc/manual/rl-next/pretty-printing.md
@@ -0,0 +1,58 @@
+---
+synopsis: "Eliminate some pretty-printing surprises"
+cls: [1616, 1617, 1618]
+prs: [11100]
+credits: [alois31, roberth]
+category: Improvements
+---
+
+Some inconsistent and surprising behaviours have been eliminated from the pretty-printing used by the REPL and `nix eval`:
+* Lists and attribute sets that contain only a single item without nested structures are no longer sometimes inappropriately indented in the REPL, depending on internal state of the evaluator.
+* Empty attribute sets and derivations are no longer shown as `«repeated»`, since they are always cheap to print.
+ This matches the existing behaviour of `nix-instantiate` on empty attribute sets.
+ Empty lists were never printed as `«repeated»` already.
+* The REPL by default does not print nested attribute sets and lists, and indicates elided items with an ellipsis.
+ Previously, the ellipsis was printed even when the structure was empty, so that such items do not in fact exist.
+ Since this behaviour was confusing, it does not happen any more.
+
+Before:
+```
+nix-repl> :p let x = 1 + 2; in [ [ x ] [ x ] ]
+[
+ [
+ 3
+ ]
+ [ 3 ]
+]
+
+nix-repl> let inherit (import <nixpkgs> { }) hello; in [ hello hello ]
+[
+ «derivation /nix/store/fqs92lzychkm6p37j7fnj4d65nq9fzla-hello-2.12.1.drv»
+ «repeated»
+]
+
+nix-repl> let x = {}; in [ x ]
+[
+ { ... }
+]
+```
+
+After:
+```
+nix-repl> :p let x = 1 + 2; in [ [ x ] [ x ] ]
+[
+ [ 3 ]
+ [ 3 ]
+]
+
+nix-repl> let inherit (import <nixpkgs> { }) hello; in [ hello hello ]
+[
+ «derivation /nix/store/fqs92lzychkm6p37j7fnj4d65nq9fzla-hello-2.12.1.drv»
+ «derivation /nix/store/fqs92lzychkm6p37j7fnj4d65nq9fzla-hello-2.12.1.drv»
+]
+
+nix-repl> let x = {}; in [ x ]
+[
+ { }
+]
+```
diff --git a/src/libexpr/print.cc b/src/libexpr/print.cc
index 87db004b2..b7ff50f48 100644
--- a/src/libexpr/print.cc
+++ b/src/libexpr/print.cc
@@ -264,22 +264,24 @@ private:
return true;
}
+ if (options.force) {
+ // The item is going to be forced during printing anyway, but we need its type now.
+ state.forceValue(*item, item->determinePos(noPos));
+ }
+
// Pretty-print single-item attrsets only if they contain nested
// structures.
auto itemType = item->type();
- return itemType == nList || itemType == nAttrs || itemType == nThunk;
+ return itemType == nList || itemType == nAttrs;
}
void printAttrs(Value & v, size_t depth)
{
- if (seen && !seen->insert(v.attrs).second) {
- printRepeated();
- return;
- }
-
if (options.force && options.derivationPaths && state.isDerivation(v)) {
printDerivation(v);
- } else if (depth < options.maxDepth) {
+ } else if (seen && !v.attrs->empty() && !seen->insert(v.attrs).second) {
+ printRepeated();
+ } else if (depth < options.maxDepth || v.attrs->empty()) {
increaseIndent();
output << "{";
@@ -335,10 +337,15 @@ private:
return true;
}
+ if (options.force) {
+ // The item is going to be forced during printing anyway, but we need its type now.
+ state.forceValue(*item, item->determinePos(noPos));
+ }
+
// Pretty-print single-item lists only if they contain nested
// structures.
auto itemType = item->type();
- return itemType == nList || itemType == nAttrs || itemType == nThunk;
+ return itemType == nList || itemType == nAttrs;
}
void printList(Value & v, size_t depth)
@@ -348,7 +355,7 @@ private:
return;
}
- if (depth < options.maxDepth) {
+ if (depth < options.maxDepth || v.listSize() == 0) {
increaseIndent();
output << "[";
auto listItems = v.listItems();
diff --git a/tests/functional/repl_characterization/data/idempotent.test b/tests/functional/repl_characterization/data/idempotent.test
new file mode 100644
index 000000000..4ab087d45
--- /dev/null
+++ b/tests/functional/repl_characterization/data/idempotent.test
@@ -0,0 +1,13 @@
+A previously unforced thunk in an attribute set does not lead to indentation when it won't evaluate to a nested structure:
+ nix-repl> :p let x = 1 + 2; in [ { inherit x; } { inherit x; } ]
+ [
+ { x = 3; }
+ { x = 3; }
+ ]
+
+Same for a list:
+ nix-repl> :p let x = 1 + 2; in [ [ x ] [ x ] ]
+ [
+ [ 3 ]
+ [ 3 ]
+ ]
diff --git a/tests/functional/repl_characterization/repl_characterization.cc b/tests/functional/repl_characterization/repl_characterization.cc
index c91d6c1e3..f2cf0ca3d 100644
--- a/tests/functional/repl_characterization/repl_characterization.cc
+++ b/tests/functional/repl_characterization/repl_characterization.cc
@@ -185,5 +185,6 @@ REPL_TEST(repl_overlays_error);
REPL_TEST(repl_printing);
REPL_TEST(stack_vars);
REPL_TEST(errors);
+REPL_TEST(idempotent);
}; // namespace nix
diff --git a/tests/unit/libexpr/value/print.cc b/tests/unit/libexpr/value/print.cc
index cdbc8f8f9..ddf8b8b99 100644
--- a/tests/unit/libexpr/value/print.cc
+++ b/tests/unit/libexpr/value/print.cc
@@ -193,6 +193,9 @@ TEST_F(ValuePrintingTests, vBlackhole)
TEST_F(ValuePrintingTests, depthAttrs)
{
+ Value vZero;
+ vZero.mkInt(0);
+
Value vOne;
vOne.mkInt(1);
@@ -203,10 +206,16 @@ TEST_F(ValuePrintingTests, depthAttrs)
Value vAttrsEmpty;
vAttrsEmpty.mkAttrs(builderEmpty.finish());
+ BindingsBuilder builderNested(state, state.allocBindings(1));
+ builderNested.insert(state.symbols.create("zero"), &vZero);
+ Value vAttrsNested;
+ vAttrsNested.mkAttrs(builderNested.finish());
+
BindingsBuilder builder(state, state.allocBindings(10));
builder.insert(state.symbols.create("one"), &vOne);
builder.insert(state.symbols.create("two"), &vTwo);
- builder.insert(state.symbols.create("nested"), &vAttrsEmpty);
+ builder.insert(state.symbols.create("empty"), &vAttrsEmpty);
+ builder.insert(state.symbols.create("nested"), &vAttrsNested);
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
@@ -220,9 +229,9 @@ TEST_F(ValuePrintingTests, depthAttrs)
vNested.mkAttrs(builder2.finish());
test(vNested, "{ nested = { ... }; one = 1; two = 2; }", PrintOptions { .maxDepth = 1 });
- test(vNested, "{ nested = { nested = { ... }; one = 1; two = 2; }; one = 1; two = 2; }", PrintOptions { .maxDepth = 2 });
- test(vNested, "{ nested = { nested = { }; one = 1; two = 2; }; one = 1; two = 2; }", PrintOptions { .maxDepth = 3 });
- test(vNested, "{ nested = { nested = { }; one = 1; two = 2; }; one = 1; two = 2; }", PrintOptions { .maxDepth = 4 });
+ test(vNested, "{ nested = { empty = { }; nested = { ... }; one = 1; two = 2; }; one = 1; two = 2; }", PrintOptions { .maxDepth = 2 });
+ test(vNested, "{ nested = { empty = { }; nested = { zero = 0; }; one = 1; two = 2; }; one = 1; two = 2; }", PrintOptions { .maxDepth = 3 });
+ test(vNested, "{ nested = { empty = { }; nested = { zero = 0; }; one = 1; two = 2; }; one = 1; two = 2; }", PrintOptions { .maxDepth = 4 });
}
TEST_F(ValuePrintingTests, depthList)
@@ -641,20 +650,24 @@ TEST_F(ValuePrintingTests, ansiColorsBlackhole)
TEST_F(ValuePrintingTests, ansiColorsAttrsRepeated)
{
- BindingsBuilder emptyBuilder(state, state.allocBindings(1));
+ Value vZero;
+ vZero.mkInt(0);
+
+ BindingsBuilder innerBuilder(state, state.allocBindings(1));
+ innerBuilder.insert(state.symbols.create("x"), &vZero);
- Value vEmpty;
- vEmpty.mkAttrs(emptyBuilder.finish());
+ Value vInner;
+ vInner.mkAttrs(innerBuilder.finish());
BindingsBuilder builder(state, state.allocBindings(10));
- builder.insert(state.symbols.create("a"), &vEmpty);
- builder.insert(state.symbols.create("b"), &vEmpty);
+ builder.insert(state.symbols.create("a"), &vInner);
+ builder.insert(state.symbols.create("b"), &vInner);
Value vAttrs;
vAttrs.mkAttrs(builder.finish());
test(vAttrs,
- "{ a = { }; b = " ANSI_MAGENTA "«repeated»" ANSI_NORMAL "; }",
+ "{ a = { x = " ANSI_CYAN "0" ANSI_NORMAL "; }; b = " ANSI_MAGENTA "«repeated»" ANSI_NORMAL "; }",
PrintOptions {
.ansiColors = true
});
@@ -662,19 +675,23 @@ TEST_F(ValuePrintingTests, ansiColorsAttrsRepeated)
TEST_F(ValuePrintingTests, ansiColorsListRepeated)
{
- BindingsBuilder emptyBuilder(state, state.allocBindings(1));
+ Value vZero;
+ vZero.mkInt(0);
+
+ BindingsBuilder innerBuilder(state, state.allocBindings(1));
+ innerBuilder.insert(state.symbols.create("x"), &vZero);
- Value vEmpty;
- vEmpty.mkAttrs(emptyBuilder.finish());
+ Value vInner;
+ vInner.mkAttrs(innerBuilder.finish());
Value vList;
state.mkList(vList, 3);
- vList.bigList.elems[0] = &vEmpty;
- vList.bigList.elems[1] = &vEmpty;
+ vList.bigList.elems[0] = &vInner;
+ vList.bigList.elems[1] = &vInner;
vList.bigList.size = 2;
test(vList,
- "[ { } " ANSI_MAGENTA "«repeated»" ANSI_NORMAL " ]",
+ "[ { x = " ANSI_CYAN "0" ANSI_NORMAL "; } " ANSI_MAGENTA "«repeated»" ANSI_NORMAL " ]",
PrintOptions {
.ansiColors = true
});
@@ -682,20 +699,24 @@ TEST_F(ValuePrintingTests, ansiColorsListRepeated)
TEST_F(ValuePrintingTests, listRepeated)
{
- BindingsBuilder emptyBuilder(state, state.allocBindings(1));
+ Value vZero;
+ vZero.mkInt(0);
+
+ BindingsBuilder innerBuilder(state, state.allocBindings(1));
+ innerBuilder.insert(state.symbols.create("x"), &vZero);
- Value vEmpty;
- vEmpty.mkAttrs(emptyBuilder.finish());
+ Value vInner;
+ vInner.mkAttrs(innerBuilder.finish());
Value vList;
state.mkList(vList, 3);
- vList.bigList.elems[0] = &vEmpty;
- vList.bigList.elems[1] = &vEmpty;
+ vList.bigList.elems[0] = &vInner;
+ vList.bigList.elems[1] = &vInner;
vList.bigList.size = 2;
- test(vList, "[ { } «repeated» ]", PrintOptions { });
+ test(vList, "[ { x = 0; } «repeated» ]", PrintOptions { });
test(vList,
- "[ { } { } ]",
+ "[ { x = 0; } { x = 0; } ]",
PrintOptions {
.trackRepeated = false
});