aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval.cc19
-rw-r--r--src/libexpr/eval.hh11
-rw-r--r--src/nix/repl.cc25
3 files changed, 42 insertions, 13 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index a5ebd1bf0..4f2fd36c1 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -563,6 +563,25 @@ Value & EvalState::getBuiltin(const string & name)
}
+std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
+{
+ if (v.type == tPrimOp || v.type == tPrimOpApp) {
+ auto v2 = &v;
+ while (v2->type == tPrimOpApp)
+ v2 = v2->primOpApp.left;
+ if (v2->primOp->doc)
+ return Doc {
+ .pos = noPos,
+ .name = v2->primOp->name,
+ .arity = v2->primOp->arity,
+ .args = v2->primOp->args,
+ .doc = v2->primOp->doc,
+ };
+ }
+ return {};
+}
+
+
/* Every "format" object (even temporary) takes up a few hundred bytes
of stack space, which is a real killer in the recursive
evaluator. So here are some helper functions for throwing
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index db8eb3e16..80078d8a5 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -248,6 +248,17 @@ public:
Value & getBuiltin(const string & name);
+ struct Doc
+ {
+ Pos pos;
+ std::optional<Symbol> name;
+ size_t arity;
+ std::vector<std::string> args;
+ const char * doc;
+ };
+
+ std::optional<Doc> getDoc(Value & v);
+
private:
inline Value * lookupVar(Env * env, const ExprVar & var, bool noEval);
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index c7f8af742..8ecf11900 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -514,23 +514,22 @@ bool NixRepl::processLine(string line)
else if (command == ":doc") {
Value v;
evalString(arg, v);
- if (v.type == tPrimOp || v.type == tPrimOpApp) {
- auto v2 = &v;
- while (v2->type == tPrimOpApp)
- v2 = v2->primOpApp.left;
- if (v2->primOp->doc) {
- auto args = v2->primOp->args;
+ if (auto doc = state->getDoc(v)) {
+ std::string markdown;
+
+ if (!doc->args.empty() && doc->name) {
+ auto args = doc->args;
for (auto & arg : args)
arg = "*" + arg + "*";
- auto markdown =
- "**Synopsis:** `builtins." + (std::string) v2->primOp->name + "` "
- + concatStringsSep(" ", args) + "\n\n"
- + trim(stripIndentation(v2->primOp->doc));
+ markdown +=
+ "**Synopsis:** `builtins." + (std::string) (*doc->name) + "` "
+ + concatStringsSep(" ", args) + "\n\n";
+ }
+
+ markdown += trim(stripIndentation(doc->doc));
- std::cout << renderMarkdownToTerminal(markdown);
- } else
- throw Error("builtin function '%s' does not have documentation", v2->primOp->name);
+ std::cout << renderMarkdownToTerminal(markdown);
} else
throw Error("value does not have documentation");
}