Add getDoc() function
This commit is contained in:
parent
2a2121d264
commit
f53b5f1058
3 changed files with 42 additions and 13 deletions
|
@ -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
|
/* Every "format" object (even temporary) takes up a few hundred bytes
|
||||||
of stack space, which is a real killer in the recursive
|
of stack space, which is a real killer in the recursive
|
||||||
evaluator. So here are some helper functions for throwing
|
evaluator. So here are some helper functions for throwing
|
||||||
|
|
|
@ -248,6 +248,17 @@ public:
|
||||||
|
|
||||||
Value & getBuiltin(const string & name);
|
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:
|
private:
|
||||||
|
|
||||||
inline Value * lookupVar(Env * env, const ExprVar & var, bool noEval);
|
inline Value * lookupVar(Env * env, const ExprVar & var, bool noEval);
|
||||||
|
|
|
@ -514,23 +514,22 @@ bool NixRepl::processLine(string line)
|
||||||
else if (command == ":doc") {
|
else if (command == ":doc") {
|
||||||
Value v;
|
Value v;
|
||||||
evalString(arg, v);
|
evalString(arg, v);
|
||||||
if (v.type == tPrimOp || v.type == tPrimOpApp) {
|
if (auto doc = state->getDoc(v)) {
|
||||||
auto v2 = &v;
|
std::string markdown;
|
||||||
while (v2->type == tPrimOpApp)
|
|
||||||
v2 = v2->primOpApp.left;
|
if (!doc->args.empty() && doc->name) {
|
||||||
if (v2->primOp->doc) {
|
auto args = doc->args;
|
||||||
auto args = v2->primOp->args;
|
|
||||||
for (auto & arg : args)
|
for (auto & arg : args)
|
||||||
arg = "*" + arg + "*";
|
arg = "*" + arg + "*";
|
||||||
|
|
||||||
auto markdown =
|
markdown +=
|
||||||
"**Synopsis:** `builtins." + (std::string) v2->primOp->name + "` "
|
"**Synopsis:** `builtins." + (std::string) (*doc->name) + "` "
|
||||||
+ concatStringsSep(" ", args) + "\n\n"
|
+ concatStringsSep(" ", args) + "\n\n";
|
||||||
+ trim(stripIndentation(v2->primOp->doc));
|
}
|
||||||
|
|
||||||
std::cout << renderMarkdownToTerminal(markdown);
|
markdown += trim(stripIndentation(doc->doc));
|
||||||
} else
|
|
||||||
throw Error("builtin function '%s' does not have documentation", v2->primOp->name);
|
std::cout << renderMarkdownToTerminal(markdown);
|
||||||
} else
|
} else
|
||||||
throw Error("value does not have documentation");
|
throw Error("value does not have documentation");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue