Skip to content

Commit

Permalink
Add a REPL command if supported
Browse files Browse the repository at this point in the history
NixOS/nix#3934 allows for custom REPL commands
to be added. This had my name on it in several regards ;-)
  • Loading branch information
lf- committed Aug 22, 2020
1 parent b572ac8 commit 21df582
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 21 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ let
cargo = self.latest.rustChannels.stable.rust;
}
)
# You can put an overlay for your dev version of nix here.
# This is not great UX. I am sorry. I am not sure how to do it better :(
# Maybe flakes.
# (import ../nix).overlay
];
};
inherit (import sources.gitignore { inherit (pkgs) lib; }) gitignoreSource;
naersk = pkgs.callPackage sources.naersk {};
in
naersk.buildPackage {
name = "nix-doc";
version = "0.3.3";
version = "0.4.0";

src = gitignoreSource ./.;

Expand Down
2 changes: 1 addition & 1 deletion nix-doc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ authors = ["lf- <[email protected]>"]
description = "Nix documentation grepping tool"
edition = "2018"
name = "nix-doc"
version = "0.3.3"
version = "0.4.0"
license = "LGPL-3.0-or-later"
homepage = "https://github.com/lf-/nix-doc"
repository = "https://github.com/lf-/nix-doc"
Expand Down
2 changes: 1 addition & 1 deletion plugin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nix-doc-plugin"
version = "0.1.1"
version = "0.2.0"
edition = "2018"

[lib]
Expand Down
15 changes: 12 additions & 3 deletions plugin/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,23 @@ fn main() {
.probe("nix-main")
.unwrap();

cc::Build::new()
let nix_ver = nix_expr.version.clone();

let mut build = cc::Build::new();
build
.cpp(true)
.opt_level(2)
.shared_flag(true)
.flag("-std=c++17")
.add_pkg_config(nix_expr)
.add_pkg_config(nix_store)
.add_pkg_config(nix_main)
.file("plugin.cpp")
.compile("nix_doc_plugin.so");
.file("plugin.cpp");

// Indicate that we need to patch around an API change with macros
if nix_ver.chars().take(1).next().unwrap() >= '3' {
build.define("NIX_3_0_0", None);
}

build.compile("nix_doc_plugin.so");
}
60 changes: 47 additions & 13 deletions plugin/plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@

#endif

#ifdef NIX_3_0_0
#define throwTypeError_ throwTypeError
#define throwTypeError(msg, val, pos) throwTypeError_(pos, msg, val)
#endif

using namespace nix;

extern "C" {
Expand Down Expand Up @@ -40,37 +45,66 @@ void prim_getDoc(EvalState & state, const nix::Pos & pos, Value * * args, Value
}
}

/* Return documentation of the given lambda. */
void prim_printDoc(EvalState & state, const nix::Pos & pos, Value * * args, Value & v)
void printLambdaDocs(Value & v)
{
/* ensure the argument is a function */
state.forceValue(*args[0], pos);
if (args[0]->type != tLambda) {
throwTypeError("%2%: value is %1% while a lambda was expected", *args[0], pos);
}

auto poz = args[0]->lambda.fun->pos;
auto poz = v.lambda.fun->pos;
std::string const & file = poz.file;
char const * doc = nd_get_function_docs(file.c_str(), poz.line, poz.column);
mkNull(v);
if (doc != nullptr) {
std::cout << doc << std::endl;
nd_free_string(doc);
}

}

void forceLambda(Value & v, const Pos & pos)
{
if (v.type != tLambda) {
throwTypeError("%2%: value is %1% while a lambda was expected", v, pos);
}
}

/* Return documentation of the given lambda. */
void prim_printDoc(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
/* ensure the argument is a function */
state.forceValue(*args[0], pos);
forceLambda(*args[0], pos);

printLambdaDocs(*args[0]);
mkNull(v);
}

/* Return position information of the given lambda. */
void prim_unsafeGetLambdaPos(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
/* ensure the argument is a function */
state.forceValue(*args[0], pos);
if (args[0]->type != tLambda) {
throwTypeError("%2%: value is %1% while a lambda was expected", *args[0], pos);
}
forceLambda(*args[0], pos);

state.mkPos(v, &args[0]->lambda.fun->pos);
}

static RegisterPrimOp rp1("__getDoc", 1, prim_getDoc);
static RegisterPrimOp rp2("__doc", 1, prim_printDoc);
static RegisterPrimOp rp3("__unsafeGetLambdaPos", 1, prim_unsafeGetLambdaPos);

// only include the :doc repl command if our nix supports it
// https://github.com/NixOS/nix/pull/3934
#if __has_include("repl.hh")
#include "repl.hh"

void replCmd(NixRepl & repl, string, string arg)
{
Value v;
repl.evalString(arg, v);
// it has been evaluated now
// TODO: (pending nix-doc hacking), support non-function attributes
// We actually have all the info to use unsafeGetAttrPos (more or less) with
// nice syntax, but I don't think nix-doc can get docs for attributes
forceLambda(v, noPos);
printLambdaDocs(v);
}

static RegisterReplCmd rc1({"doc"}, "Get the `nix-doc` documentation for <expr>", replCmd, "<expr>");
#endif

0 comments on commit 21df582

Please sign in to comment.