aboutsummaryrefslogtreecommitdiff
path: root/src/nix/repl.cc
diff options
context:
space:
mode:
authorzimbatm <zimbatm@zimbatm.com>2019-10-23 15:29:16 +0200
committerzimbatm <zimbatm@zimbatm.com>2019-10-23 16:09:42 +0200
commit73ff84f6a820ac1c6e0fe502692432c8945fd8b0 (patch)
treee8ca80c7725e0fd3c0bb73bb1d4e61ad684e1b00 /src/nix/repl.cc
parent389a2cebed7cd72bda524ece0a56af2888cd80b6 (diff)
nix repl: add :edit command
This allows to have a repl-centric workflow to working on nixpkgs. Usage: :edit <package> - heuristic that find the package file path :edit <path> - just open the editor on the file path Once invoked, `nix repl` will open $EDITOR on that file path. Once the editor exits, `nix repl` will automatically reload itself.
Diffstat (limited to 'src/nix/repl.cc')
-rw-r--r--src/nix/repl.cc57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index f857b2e89..79f365cdb 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,61 @@ bool NixRepl::processLine(string line)
reloadFiles();
}
+ else if (command == ":e" || command == ":edit") {
+ Value v;
+ evalString(arg, v);
+
+ std::string filename;
+ int lineno = 0;
+
+ if (v.type == tPath || v.type == tString) {
+ PathSet context;
+ filename = state.coerceToString(noPos, v, context);
+ lineno = 0;
+ } else {
+ // assume it's a derivation
+ 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", arg);
+ }
+
+ 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);
+
+ filename = std::string(pos, 0, colon);
+ try {
+ lineno = std::stoi(std::string(pos, colon + 1));
+ } catch (std::invalid_argument & e) {
+ throw Error("cannot parse line number '%s'", pos);
+ }
+
+ }
+
+ // Open in EDITOR
+ auto editor = getEnv("EDITOR", "cat");
+ auto args = tokenizeString<Strings>(editor);
+ if (lineno > 0 && (
+ 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);
+ 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);