From 73ff84f6a820ac1c6e0fe502692432c8945fd8b0 Mon Sep 17 00:00:00 2001 From: zimbatm Date: Wed, 23 Oct 2019 15:29:16 +0200 Subject: [PATCH] nix repl: add :edit command This allows to have a repl-centric workflow to working on nixpkgs. Usage: :edit - heuristic that find the package file path :edit - 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. --- src/nix/repl.cc | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) 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) << " = Bind expression to variable\n" << " :a Add attributes from resulting set to scope\n" << " :b Build derivation\n" + << " :e Open the derivation in $EDITOR\n" << " :i Build derivation, then install result into current profile\n" << " :l Load Nix expression and add it to scope\n" << " :p 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(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);