diff options
author | Lunaphied <lunaphied@lunaphied.me> | 2024-03-17 18:01:05 -0600 |
---|---|---|
committer | Lunaphied <lunaphied@lunaphied.me> | 2024-04-03 13:47:22 -0600 |
commit | 7a1054fa5f223126833718fc3f332579dba5f0f7 (patch) | |
tree | 790daae10628ec42436d79c943dcbcd8d7168fd6 /src/libcmd/repl.cc | |
parent | 56c7dfd65290dea957de6fad4e2df26f1630e407 (diff) |
repl: improve `:doc` builtin repl command to support lambdas.
For a long time `nix repl` has supported displaying documentation set on
builtins, however, it has long been convention to use Markdown comments
on Nix functions themselves for documentation. This exposes that
information to `nix repl` users in a nice and formatted way.
NixOS/rfcs#145 doc-comments are primarily what this feature is intended
to consume, however, support for lambda documentation in the repl is
experimental. We do our best effort to support the RFC here.
These changes are based on [the nix-doc library](https://github.com/lf-/nix-doc) and
are licensed under the terms described in the relevant source files.
Change-Id: Ic6fe947d39a22540705d890737e336c4720b0a22
Diffstat (limited to 'src/libcmd/repl.cc')
-rw-r--r-- | src/libcmd/repl.cc | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 45b56d012..0d7ad63a7 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -36,8 +36,26 @@ #include <gc/gc_cpp.h> #endif +// XXX: These are for nix-doc features and will be removed in a future rewrite where this functionality is integrated more natively. +extern "C" { + char const *nd_get_function_docs(char const *filename, size_t line, size_t col); + void nd_free_string(char const *str); +} + namespace nix { + +/** Wrapper around std::unique_ptr with a custom deleter for strings from nix-doc **/ +using NdString = std::unique_ptr<const char, decltype(&nd_free_string)>; + +/** + * Fetch a string representing the doc comment using nix-doc and wrap it in an RAII wrapper. + */ +NdString lambdaDocsForPos(SourcePath const path, nix::Pos const &pos) { + std::string const file = path.to_string(); + return NdString{nd_get_function_docs(file.c_str(), pos.line, pos.column), &nd_free_string}; +} + /** * Returned by `NixRepl::processLine`. */ @@ -400,7 +418,7 @@ ProcessLineResult NixRepl::processLine(std::string line) << " nix-shell\n" << " :t <expr> Describe result of evaluation\n" << " :u <expr> Build derivation, then start nix-shell\n" - << " :doc <expr> Show documentation of a builtin function\n" + << " :doc <expr> Show documentation for the provided function (experimental lambda support)\n" << " :log <expr> Show logs for a derivation\n" << " :te, :trace-enable [bool] Enable, disable or toggle showing traces for\n" << " errors\n" @@ -629,8 +647,24 @@ ProcessLineResult NixRepl::processLine(std::string line) markdown += stripIndentation(doc->doc); logger->cout(trim(renderMarkdownToTerminal(markdown))); - } else - throw Error("value does not have documentation"); + } else if (v.isLambda()) { + auto pos = state->positions[v.lambda.fun->pos]; + if (auto path = std::get_if<SourcePath>(&pos.origin)) { + // Path and position have now been obtained, feed to nix-doc library to get data. + auto docComment = lambdaDocsForPos(*path, pos); + if (!docComment) { + throw Error("lambda '%s' has no documentation comment", pos); + } + + // Build and print Markdown representation of documentation comment. + std::string markdown = stripIndentation(docComment.get()); + logger->cout(trim(renderMarkdownToTerminal(markdown))); + } else { + throw Error("lambda '%s' doesn't have a determinable source file", pos); + } + } else { + throw Error("value '%s' does not have documentation", arg); + } } else if (command == ":te" || command == ":trace-enable") { |