aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/attr-path.cc32
-rw-r--r--src/libexpr/attr-path.hh3
-rw-r--r--src/libutil/args.cc13
-rw-r--r--src/libutil/args.hh4
-rw-r--r--src/nix/edit.cc40
-rw-r--r--src/nix/repl.cc30
6 files changed, 88 insertions, 34 deletions
diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc
index b0f80db32..06b472d8b 100644
--- a/src/libexpr/attr-path.cc
+++ b/src/libexpr/attr-path.cc
@@ -93,4 +93,36 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath,
}
+Pos findDerivationFilename(EvalState & state, Value & v, std::string what)
+{
+ 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", what);
+ }
+
+ // FIXME: is it possible to extract the Pos object instead of doing this
+ // toString + parsing?
+ auto pos = state.forceString(*v2);
+
+ auto colon = pos.rfind(':');
+ if (colon == std::string::npos)
+ throw Error("cannot parse meta.position attribute '%s'", pos);
+
+ std::string filename(pos, 0, colon);
+ unsigned int lineno;
+ try {
+ lineno = std::stoi(std::string(pos, colon + 1));
+ } catch (std::invalid_argument & e) {
+ throw Error("cannot parse line number '%s'", pos);
+ }
+
+ Symbol file = state.symbols.create(filename);
+
+ return { file, lineno, 0 };
+}
+
+
}
diff --git a/src/libexpr/attr-path.hh b/src/libexpr/attr-path.hh
index 46a341950..716e5ba27 100644
--- a/src/libexpr/attr-path.hh
+++ b/src/libexpr/attr-path.hh
@@ -10,4 +10,7 @@ namespace nix {
Value * findAlongAttrPath(EvalState & state, const string & attrPath,
Bindings & autoArgs, Value & vIn);
+/* Heuristic to find the filename and lineno or a nix value. */
+Pos findDerivationFilename(EvalState & state, Value & v, std::string what);
+
}
diff --git a/src/libutil/args.cc b/src/libutil/args.cc
index 7af2a1bf7..b7baad375 100644
--- a/src/libutil/args.cc
+++ b/src/libutil/args.cc
@@ -178,6 +178,19 @@ Strings argvToStrings(int argc, char * * argv)
return args;
}
+Strings editorFor(Pos pos)
+{
+ auto editor = getEnv("EDITOR", "cat");
+ auto args = tokenizeString<Strings>(editor);
+ if (pos.line > 0 && (
+ editor.find("emacs") != std::string::npos ||
+ editor.find("nano") != std::string::npos ||
+ editor.find("vim") != std::string::npos))
+ args.push_back(fmt("+%d", pos.line));
+ args.push_back(pos.file);
+ return args;
+}
+
std::string renderLabels(const Strings & labels)
{
std::string res;
diff --git a/src/libutil/args.hh b/src/libutil/args.hh
index ad5fcca39..1e29bd4fa 100644
--- a/src/libutil/args.hh
+++ b/src/libutil/args.hh
@@ -5,6 +5,7 @@
#include <memory>
#include "util.hh"
+#include "nixexpr.hh"
namespace nix {
@@ -190,6 +191,9 @@ public:
Strings argvToStrings(int argc, char * * argv);
+/* Helper function to generate args that invoke $EDITOR on filename:lineno */
+Strings editorFor(Pos pos);
+
/* Helper function for rendering argument labels. */
std::string renderLabels(const Strings & labels);
diff --git a/src/nix/edit.cc b/src/nix/edit.cc
index a6169f118..553765f13 100644
--- a/src/nix/edit.cc
+++ b/src/nix/edit.cc
@@ -36,45 +36,17 @@ struct CmdEdit : InstallableCommand
auto v = installable->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", installable->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;
- try {
- lineno = std::stoi(std::string(pos, colon + 1));
- } catch (std::invalid_argument & e) {
- throw Error("cannot parse line number '%s'", pos);
- }
-
- auto editor = getEnv("EDITOR", "cat");
-
- auto args = tokenizeString<Strings>(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);
+ Pos pos = findDerivationFilename(*state, *v, installable->what());
stopProgressBar();
+ auto args = editorFor(pos);
+
execvp(args.front().c_str(), stringsToCharPtrs(args).data());
- throw SysError("cannot run editor '%s'", editor);
+ std::string command;
+ for (const auto &arg : args) command += " '" + arg + "'";
+ throw SysError("cannot run command%s", command);
}
};
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index f857b2e89..35c7aec66 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -22,6 +22,7 @@ extern "C" {
#include "shared.hh"
#include "eval.hh"
#include "eval-inline.hh"
+#include "attr-path.hh"
#include "store-api.hh"
#include "common-eval-args.hh"
#include "get-drvs.hh"
@@ -440,6 +441,7 @@ bool NixRepl::processLine(string line)
<< " <x> = <expr> Bind expression to variable\n"
<< " :a <expr> Add attributes from resulting set to scope\n"
<< " :b <expr> Build derivation\n"
+ << " :e <expr> Open the derivation in $EDITOR\n"
<< " :i <expr> Build derivation, then install result into current profile\n"
<< " :l <path> Load Nix expression and add it to scope\n"
<< " :p <expr> Evaluate and print expression recursively\n"
@@ -466,6 +468,34 @@ bool NixRepl::processLine(string line)
reloadFiles();
}
+ else if (command == ":e" || command == ":edit") {
+ Value v;
+ evalString(arg, v);
+
+ Pos pos;
+
+ if (v.type == tPath || v.type == tString) {
+ PathSet context;
+ auto filename = state.coerceToString(noPos, v, context);
+ pos.file = state.symbols.create(filename);
+ } else if (v.type == tLambda) {
+ pos = v.lambda.fun->pos;
+ } else {
+ // assume it's a derivation
+ pos = findDerivationFilename(state, v, arg);
+ }
+
+ // Open in EDITOR
+ auto args = editorFor(pos);
+ auto editor = args.front();
+ args.pop_front();
+ runProgram(editor, args);
+
+ // Reload right after exiting the editor
+ state.resetFileCache();
+ reloadFiles();
+ }
+
else if (command == ":t") {
Value v;
evalString(arg, v);