about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-05-08T16·39+0200
committerEelco Dolstra <edolstra@gmail.com>2017-05-08T16·42+0200
commit03ae5e64592d6d62f30158ccfa804f1b4135a596 (patch)
tree81e6f256c985d7a6e1efb4af457a595e792a48e0
parent7689181e4f5921d3356736996079ec0310e834c6 (diff)
Add "nix edit" command
This is a little convenience command that opens the Nix expression of
the specified package. For example,

  nix edit nixpkgs.perlPackages.Moose

opens <nixpkgs/pkgs/top-level/perl-packages.nix> in $EDITOR (at the
right line number for some editors).

This requires the package to have a meta.position attribute.
-rw-r--r--src/nix/edit.cc75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/nix/edit.cc b/src/nix/edit.cc
new file mode 100644
index 000000000000..632b555771c2
--- /dev/null
+++ b/src/nix/edit.cc
@@ -0,0 +1,75 @@
+#include "command.hh"
+#include "shared.hh"
+#include "eval.hh"
+#include "attr-path.hh"
+
+#include <unistd.h>
+
+using namespace nix;
+
+struct CmdEdit : InstallablesCommand
+{
+    std::string name() override
+    {
+        return "edit";
+    }
+
+    std::string description() override
+    {
+        return "open the Nix expression of a Nix package in $EDITOR";
+    }
+
+    Examples examples() override
+    {
+        return {
+            Example{
+                "To open the Nix expression of the GNU Hello package:",
+                "nix edit nixpkgs.hello"
+            },
+        };
+    }
+
+    void run(ref<Store> store) override
+    {
+        auto state = getEvalState();
+
+        for (auto & i : installables) {
+            auto v = i->toValue(*state);
+
+            Value * v2;
+            try {
+                auto dummyArgs = state->allocBindings(0);
+                v2 = findAlongAttrPath(*state, "meta.position", *dummyArgs, *v);
+            } catch (Error &) {
+                throw Error("package ‘%s’ has no source location information", i->what());
+            }
+
+            auto pos = state->forceString(*v2);
+            debug("position is %s", pos);
+
+            auto colon = pos.rfind(':');
+            if (colon == std::string::npos)
+                throw Error("cannot parse meta.position attribute ‘%s’", pos);
+
+            std::string filename(pos, 0, colon);
+            int lineno = std::stoi(std::string(pos, colon + 1));
+
+            auto editor = getEnv("EDITOR", "cat");
+
+            Strings args{editor};
+
+            if (editor.find("emacs") != std::string::npos ||
+                editor.find("nano") != std::string::npos ||
+                editor.find("vim") != std::string::npos)
+                args.push_back(fmt("+%d", lineno));
+
+            args.push_back(filename);
+
+            execvp(editor.c_str(), stringsToCharPtrs(args).data());
+
+            throw SysError("cannot run editor ‘%s’", editor);
+        }
+    }
+};
+
+static RegisterCommand r1(make_ref<CmdEdit>());