diff options
author | eldritch horrors <pennae@lix.systems> | 2024-03-08 08:25:42 +0100 |
---|---|---|
committer | eldritch horrors <pennae@lix.systems> | 2024-03-09 07:20:23 -0700 |
commit | 1958152d146389b00c50a149c33012a16864ef83 (patch) | |
tree | 1a6fb0cbaa147e26dc661092d88bdb6dd7adfdf1 /src/libexpr | |
parent | b221a14f0a477db06f8ab705bd08404e431ec135 (diff) |
Pretty-print values in the REPL
Pretty-print values in the REPL by printing each item in a list or
attrset on a separate line. When possible, single-item lists and
attrsets are printed on one line, as long as they don't contain a nested
list, attrset, or thunk.
Before:
```
{ attrs = { a = { b = { c = { }; }; }; }; list = [ 1 ]; list' = [ 1 2 3 ]; }
```
After:
```
{
attrs = {
a = {
b = {
c = { };
};
};
};
list = [ 1 ];
list' = [
1
2
3
];
}
```
(cherry picked from commit c0a15fb7d03dfb8f53bc6726c414bc88aa362592)
Change-Id: Ia2b41849165a5ddb63f7a8c272a2476b3e4292df
Diffstat (limited to 'src/libexpr')
-rw-r--r-- | src/libexpr/print-options.hh | 22 | ||||
-rw-r--r-- | src/libexpr/print.cc | 112 |
2 files changed, 124 insertions, 10 deletions
diff --git a/src/libexpr/print-options.hh b/src/libexpr/print-options.hh index e03746ece..94767df9c 100644 --- a/src/libexpr/print-options.hh +++ b/src/libexpr/print-options.hh @@ -17,24 +17,29 @@ struct PrintOptions * If true, output ANSI color sequences. */ bool ansiColors = false; + /** * If true, force values. */ bool force = false; + /** * If true and `force` is set, print derivations as * `«derivation /nix/store/...»` instead of as attribute sets. */ bool derivationPaths = false; + /** * If true, track which values have been printed and skip them on * subsequent encounters. Useful for self-referential values. */ bool trackRepeated = true; + /** * Maximum depth to evaluate to. */ size_t maxDepth = std::numeric_limits<size_t>::max(); + /** * Maximum number of attributes in attribute sets to print. * @@ -42,6 +47,7 @@ struct PrintOptions * attribute set encountered. */ size_t maxAttrs = std::numeric_limits<size_t>::max(); + /** * Maximum number of list items to print. * @@ -49,10 +55,26 @@ struct PrintOptions * list encountered. */ size_t maxListItems = std::numeric_limits<size_t>::max(); + /** * Maximum string length to print. */ size_t maxStringLength = std::numeric_limits<size_t>::max(); + + /** + * Indentation width for pretty-printing. + * + * If set to 0 (the default), values are not pretty-printed. + */ + size_t prettyIndent = 0; + + /** + * True if pretty-printing is enabled. + */ + inline bool prettyPrint() + { + return prettyIndent > 0; + } }; /** diff --git a/src/libexpr/print.cc b/src/libexpr/print.cc index b792f657d..53d0861bf 100644 --- a/src/libexpr/print.cc +++ b/src/libexpr/print.cc @@ -151,6 +151,7 @@ struct ImportantFirstAttrNameCmp }; typedef std::set<const void *> ValuesSeen; +typedef std::vector<std::pair<std::string, Value *>> AttrVec; class Printer { @@ -161,6 +162,21 @@ private: std::optional<ValuesSeen> seen; size_t attrsPrinted = 0; size_t listItemsPrinted = 0; + std::string indent; + + void increaseIndent() + { + if (options.prettyPrint()) { + indent.append(options.prettyIndent, ' '); + } + } + + void decreaseIndent() + { + if (options.prettyPrint()) { + indent.resize(indent.size() - options.prettyIndent); + } + } void printRepeated() { @@ -258,6 +274,28 @@ private: } } + bool shouldPrettyPrintAttrs(AttrVec & v) + { + if (!options.prettyPrint() || v.empty()) { + return false; + } + + // Pretty-print attrsets with more than one item. + if (v.size() > 1) { + return true; + } + + auto item = v[0].second; + if (!item) { + return true; + } + + // Pretty-print single-item attrsets only if they contain nested + // structures. + auto itemType = item->type(); + return itemType == nList || itemType == nAttrs || itemType == nThunk; + } + void printAttrs(Value & v, size_t depth) { if (seen && !seen->insert(v.attrs).second) { @@ -268,9 +306,10 @@ private: if (options.force && options.derivationPaths && state.isDerivation(v)) { printDerivation(v); } else if (depth < options.maxDepth) { - output << "{ "; + increaseIndent(); + output << "{"; - std::vector<std::pair<std::string, Value *>> sorted; + AttrVec sorted; for (auto & i : *v.attrs) sorted.emplace_back(std::pair(state.symbols[i.name], i.value)); @@ -279,7 +318,15 @@ private: else std::sort(sorted.begin(), sorted.end(), ImportantFirstAttrNameCmp()); + auto prettyPrint = shouldPrettyPrintAttrs(sorted); + for (auto & i : sorted) { + if (prettyPrint) { + output << "\n" << indent; + } else { + output << " "; + } + if (attrsPrinted >= options.maxAttrs) { printElided(sorted.size() - attrsPrinted, "attribute", "attributes"); break; @@ -288,13 +335,42 @@ private: printAttributeName(output, i.first); output << " = "; print(*i.second, depth + 1); - output << "; "; + output << ";"; attrsPrinted++; } + decreaseIndent(); + if (prettyPrint) { + output << "\n" << indent; + } else { + output << " "; + } output << "}"; - } else + } else { output << "{ ... }"; + } + } + + bool shouldPrettyPrintList(std::span<Value * const> list) + { + if (!options.prettyPrint() || list.empty()) { + return false; + } + + // Pretty-print lists with more than one item. + if (list.size() > 1) { + return true; + } + + auto item = list[0]; + if (!item) { + return true; + } + + // Pretty-print single-item lists only if they contain nested + // structures. + auto itemType = item->type(); + return itemType == nList || itemType == nAttrs || itemType == nThunk; } void printList(Value & v, size_t depth) @@ -304,9 +380,18 @@ private: return; } - output << "[ "; if (depth < options.maxDepth) { - for (auto elem : v.listItems()) { + increaseIndent(); + output << "["; + auto listItems = v.listItems(); + auto prettyPrint = shouldPrettyPrintList(listItems); + for (auto elem : listItems) { + if (prettyPrint) { + output << "\n" << indent; + } else { + output << " "; + } + if (listItemsPrinted >= options.maxListItems) { printElided(v.listSize() - listItemsPrinted, "item", "items"); break; @@ -317,13 +402,19 @@ private: } else { printNullptr(); } - output << " "; listItemsPrinted++; } + + decreaseIndent(); + if (prettyPrint) { + output << "\n" << indent; + } else { + output << " "; + } + output << "]"; + } else { + output << "[ ... ]"; } - else - output << "... "; - output << "]"; } void printFunction(Value & v) @@ -486,6 +577,7 @@ public: { attrsPrinted = 0; listItemsPrinted = 0; + indent.clear(); if (options.trackRepeated) { seen.emplace(); |