aboutsummaryrefslogtreecommitdiff
path: root/src/libcmd
diff options
context:
space:
mode:
authorLunaphied <lunaphied@lunaphied.me>2024-03-17 18:01:05 -0600
committerLunaphied <lunaphied@lunaphied.me>2024-04-03 13:47:22 -0600
commit7a1054fa5f223126833718fc3f332579dba5f0f7 (patch)
tree790daae10628ec42436d79c943dcbcd8d7168fd6 /src/libcmd
parent56c7dfd65290dea957de6fad4e2df26f1630e407 (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')
-rw-r--r--src/libcmd/local.mk2
-rw-r--r--src/libcmd/meson.build1
-rw-r--r--src/libcmd/repl.cc40
3 files changed, 39 insertions, 4 deletions
diff --git a/src/libcmd/local.mk b/src/libcmd/local.mk
index afd35af08..dcd33e84c 100644
--- a/src/libcmd/local.mk
+++ b/src/libcmd/local.mk
@@ -8,7 +8,7 @@ libcmd_SOURCES := $(wildcard $(d)/*.cc)
libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers
-libcmd_LDFLAGS = $(EDITLINE_LIBS) $(LOWDOWN_LIBS) -pthread
+libcmd_LDFLAGS = $(EDITLINE_LIBS) $(LOWDOWN_LIBS) $(NIXDOC_LIBS) -pthread
libcmd_LIBS = libstore libutil libexpr libmain libfetchers
diff --git a/src/libcmd/meson.build b/src/libcmd/meson.build
index 6ef293c8f..167cb0f06 100644
--- a/src/libcmd/meson.build
+++ b/src/libcmd/meson.build
@@ -45,6 +45,7 @@ libcmd = library(
editline,
lowdown,
nlohmann_json,
+ nix_doc
],
install : true,
# FIXME(Qyriad): is this right?
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") {