aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 000000000..632b55577
--- /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>());