Skip to content

Commit 03ae5e6

Browse files
committedMay 8, 2017
Add "nix edit" command
This is a little convenience command that opens the Nix expression of the specified package. For example, nix edit nixpkgs.perlPackages.Moose opens <nixpkgs/pkgs/top-level/perl-packages.nix> in $EDITOR (at the right line number for some editors). This requires the package to have a meta.position attribute.
1 parent 7689181 commit 03ae5e6

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed
 

‎src/nix/edit.cc

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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

Comments
 (5)

copumpkin commented on May 8, 2017

@copumpkin
Member

Won't most users find that the editor points at a read-only file in the store? Otherwise seems like a cool feature.

matthewbauer commented on May 9, 2017

@matthewbauer
Member

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 commented on May 9, 2017

@edolstra
MemberAuthor

@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 commented on May 9, 2017

@copumpkin
Member

With the URL of the repo, we could also make a more interactive prompt:

  1. nix edit foo
  2. "Your config doesn't have a configured clone right now. Would you like to clone one now, or give us a path to an existing clone that's safe to adjust the working directory on?"
  3. Automatically clone, create a temporary branch, open $EDITOR

etc.

Probably excessive but making that workflow super smooth would probably get us a ton more contributions.

bjornfor commented on May 9, 2017

@bjornfor
Contributor

Regarding git log, that's pretty nice, but it does require a git tree (so it wouldn't work with channels).

Maybe nix-channel eventually can learn about fetching directly from git repos?

Please sign in to comment.