From 7e3625f924825db2ffa5e58d4b414d93d9af2465 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Sat, 7 Sep 2013 00:35:54 +0200 Subject: [PATCH] Improved value display By default, we don't recurse into attribute sets or lists when printing a value. However, the new :p command does recurse. --- nix-repl.cc | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 15ac42dcc..d2179d77a 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -45,6 +45,7 @@ struct NixRepl void addVarToScope(const Symbol & name, Value * v); Expr * parseString(string s); void evalString(string s, Value & v); + std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth); }; @@ -255,14 +256,19 @@ void NixRepl::processLine(string line) runProgram("nix-shell", Strings{drvPath}); } + else if (command == ":p") { + Value v; + evalString(string(line, 2), v); + printValue(std::cout, v, 1000000000) << std::endl; + } + else if (string(line, 0, 1) == ":") throw Error(format("unknown command ‘%1%’") % string(line, 0, 2)); else { Value v; evalString(line, v); - state.strictForceValue(v); - std::cout << v << std::endl; + printValue(std::cout, v, 1) << std::endl; } } @@ -309,6 +315,114 @@ void NixRepl::evalString(string s, Value & v) } +// FIXME: lot of cut&paste from Nix's eval.cc. +std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth) +{ + str.flush(); + checkInterrupt(); + + state.forceValue(v); + + switch (v.type) { + + case tInt: + str << v.integer; + break; + + case tBool: + str << (v.boolean ? "true" : "false"); + break; + + case tString: + str << "\""; + for (const char * i = v.string.s; *i; i++) + if (*i == '\"' || *i == '\\') str << "\\" << *i; + else if (*i == '\n') str << "\\n"; + else if (*i == '\r') str << "\\r"; + else if (*i == '\t') str << "\\t"; + else str << *i; + str << "\""; + break; + + case tPath: + str << v.path; // !!! escaping? + break; + + case tNull: + str << "null"; + break; + + case tAttrs: { + bool isDrv = state.isDerivation(v); + if (isDrv) str << "(derivation "; + str << "{ "; + + if (maxDepth > 0) { + typedef std::map Sorted; + Sorted sorted; + foreach (Bindings::iterator, i, *v.attrs) + sorted[i->name] = i->value; + + /* If this is a derivation, then don't show the + self-references ("all", "out", etc.). */ + StringSet hidden; + if (isDrv) { + hidden.insert("all"); + Bindings::iterator i = v.attrs->find(state.sOutputs); + if (i == v.attrs->end()) + hidden.insert("out"); + else { + state.forceList(*i->value); + for (unsigned int j = 0; j < i->value->list.length; ++j) + hidden.insert(state.forceStringNoCtx(*i->value->list.elems[j])); + } + } + + foreach (Sorted::iterator, i, sorted) + if (hidden.find(i->first) == hidden.end()) + printValue(str << i->first << " = ", *i->second, maxDepth - 1) << "; "; + else + str << i->first << " = ...; "; + + } else + str << "... "; + + str << "}"; + if (isDrv) str << ")"; + break; + } + + case tList: + str << "[ "; + if (maxDepth > 0) + for (unsigned int n = 0; n < v.list.length; ++n) + printValue(str, *v.list.elems[n], maxDepth - 1) << " "; + else + str << "... "; + str << "]"; + break; + + case tLambda: + str << "«lambda»"; + break; + + case tPrimOp: + str << "«primop»"; + break; + + case tPrimOpApp: + str << "«primop-app»"; + break; + + default: + str << "«unknown»"; + break; + } + + return str; +} + + void run(Strings args) { NixRepl repl;