From 7a1054fa5f223126833718fc3f332579dba5f0f7 Mon Sep 17 00:00:00 2001 From: Lunaphied Date: Sun, 17 Mar 2024 18:01:05 -0600 Subject: 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 --- src/libcmd/repl.cc | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) (limited to 'src/libcmd/repl.cc') 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 #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; + +/** + * 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 Describe result of evaluation\n" << " :u Build derivation, then start nix-shell\n" - << " :doc Show documentation of a builtin function\n" + << " :doc Show documentation for the provided function (experimental lambda support)\n" << " :log 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(&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") { -- cgit v1.2.3