diff options
author | zimbatm <zimbatm@zimbatm.com> | 2019-10-23 15:29:16 +0200 |
---|---|---|
committer | zimbatm <zimbatm@zimbatm.com> | 2019-10-23 16:09:42 +0200 |
commit | 73ff84f6a820ac1c6e0fe502692432c8945fd8b0 (patch) | |
tree | e8ca80c7725e0fd3c0bb73bb1d4e61ad684e1b00 /src/nix/repl.cc | |
parent | 389a2cebed7cd72bda524ece0a56af2888cd80b6 (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.cc | 57 |
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); |