|
| 1 | +#include "command.hh" |
| 2 | +#include "shared.hh" |
| 3 | +#include "eval.hh" |
| 4 | +#include "attr-path.hh" |
| 5 | + |
| 6 | +#include <unistd.h> |
| 7 | + |
| 8 | +using namespace nix; |
| 9 | + |
| 10 | +struct CmdEdit : InstallablesCommand |
| 11 | +{ |
| 12 | + std::string name() override |
| 13 | + { |
| 14 | + return "edit"; |
| 15 | + } |
| 16 | + |
| 17 | + std::string description() override |
| 18 | + { |
| 19 | + return "open the Nix expression of a Nix package in $EDITOR"; |
| 20 | + } |
| 21 | + |
| 22 | + Examples examples() override |
| 23 | + { |
| 24 | + return { |
| 25 | + Example{ |
| 26 | + "To open the Nix expression of the GNU Hello package:", |
| 27 | + "nix edit nixpkgs.hello" |
| 28 | + }, |
| 29 | + }; |
| 30 | + } |
| 31 | + |
| 32 | + void run(ref<Store> store) override |
| 33 | + { |
| 34 | + auto state = getEvalState(); |
| 35 | + |
| 36 | + for (auto & i : installables) { |
| 37 | + auto v = i->toValue(*state); |
| 38 | + |
| 39 | + Value * v2; |
| 40 | + try { |
| 41 | + auto dummyArgs = state->allocBindings(0); |
| 42 | + v2 = findAlongAttrPath(*state, "meta.position", *dummyArgs, *v); |
| 43 | + } catch (Error &) { |
| 44 | + throw Error("package ‘%s’ has no source location information", i->what()); |
| 45 | + } |
| 46 | + |
| 47 | + auto pos = state->forceString(*v2); |
| 48 | + debug("position is %s", pos); |
| 49 | + |
| 50 | + auto colon = pos.rfind(':'); |
| 51 | + if (colon == std::string::npos) |
| 52 | + throw Error("cannot parse meta.position attribute ‘%s’", pos); |
| 53 | + |
| 54 | + std::string filename(pos, 0, colon); |
| 55 | + int lineno = std::stoi(std::string(pos, colon + 1)); |
| 56 | + |
| 57 | + auto editor = getEnv("EDITOR", "cat"); |
| 58 | + |
| 59 | + Strings args{editor}; |
| 60 | + |
| 61 | + if (editor.find("emacs") != std::string::npos || |
| 62 | + editor.find("nano") != std::string::npos || |
| 63 | + editor.find("vim") != std::string::npos) |
| 64 | + args.push_back(fmt("+%d", lineno)); |
| 65 | + |
| 66 | + args.push_back(filename); |
| 67 | + |
| 68 | + execvp(editor.c_str(), stringsToCharPtrs(args).data()); |
| 69 | + |
| 70 | + throw SysError("cannot run editor ‘%s’", editor); |
| 71 | + } |
| 72 | + } |
| 73 | +}; |
| 74 | + |
| 75 | +static RegisterCommand r1(make_ref<CmdEdit>()); |
5 commit comments
copumpkin commentedon May 8, 2017
Won't most users find that the editor points at a read-only file in the store? Otherwise seems like a cool feature.
matthewbauer commentedon May 9, 2017
Looks good! I'm glad these more user-facing commands are getting into nix.
I actually already have a similar script if anyone's interested: https://github.com/matthewbauer/nix-utils/blob/master/nix-edit
Another one inspired by Homebrew that might be useful is "nix log". It pulls open the "git log" results for an attribute: https://github.com/matthewbauer/nix-utils/blob/master/nix-log
edolstra commentedon May 9, 2017
@copumpkin Yes, in that case it's more of a "nix view". Still useful though.
@matthewbauer Yeah, I've been using a similar nix-edit shell function for years. Regarding git log, that's pretty nice, but it does require a git tree (so it wouldn't work with channels). Maybe channels could include the URL of the repo, which nix could then use...
copumpkin commentedon May 9, 2017
With the URL of the repo, we could also make a more interactive prompt:
nix edit foo
$EDITOR
etc.
Probably excessive but making that workflow super smooth would probably get us a ton more contributions.
bjornfor commentedon May 9, 2017
Maybe nix-channel eventually can learn about fetching directly from git repos?