I have a long running emacs outside of nix-shell. Then I have a dev env in nix-shell -p rustc cargo rr
, where I build binaries.
How to call cargo and rr that are inside this nix-shell from emacs? I want to pass rr as an argument to M-x gdb
I have a long running emacs outside of nix-shell. Then I have a dev env in nix-shell -p rustc cargo rr
, where I build binaries.
How to call cargo and rr that are inside this nix-shell from emacs? I want to pass rr as an argument to M-x gdb
I don’t think you can send commands to a running shell. What you could probably do is make Emacs execute nix-shell /your/project/dir --run rr
.
My usual advice would be to run the editor from inside the nix-shell, but that obviously doesn’t work with a long running Emacs server that you presumably reuse between different projects.
have the nix-shell create dir-local variable with the path to rr?
Use direnv for the project(s) + some direnv plugin for emacs?
As a heavy emacs user, this is what I would recommend, with this package (available from melpa - and nixpkgs): GitHub - wbolster/emacs-direnv: direnv integration for emacs
With it emacs will enter the devshell/shell.nix
of any repository you open a file in.
I’d really recommend using devshell with rust anyway, since even subtle changes in the environment will make rust compile targets from scratch, making you waste a lot of time if you ever use M-x compile
and then a terminal command outside of emacs. Doubly so if you use rust-analyzer
.
So I use direnv a bunch, and I do all my editing in emacs, but I’d still call myself an emacs lightweight. I often have multiple projects open with wildly different direnv / shells. enviroment variables are global to the process, so presumably the global environment is swapped depending on whatever buffer is currently active? Seems like that could get funky if you have some async compile process running then swap projects by swapping out the active buffer. I’m tempted to pull in emacs-direnv, but I’m just wondering if you’ve experienced any of my hypothetical downsides?
Yep.
You could think so, but no, processes inherit the environment when they’re started, and the environment doesn’t magically update. It works for the same reason systemd
can actually do any process environment management.
The main downside is that activating direnv is synchronous (since it needs to complete before any other mode hooks to ensure they have the environment active at execution) and can sometimes take time.
This is noticeable when flake.nix
files are modified (since that wipes the eval cache), and especially when flake.lock
is updated, since that will make nix download stuff synchronously before your buffer loads. Spamming C-g
is useful when you don’t actually want to apply the environment, but often it just means you have to be a bit patient.
Using magit to process commits that include changes to flake.nix
or flake.lock
is especially annoying, because each commit will be played onto disk and then trigger a new direnv load. There’s probably a way to fix this (probably change by .envrc
to if git-is-rebasing; then use flake; fi
), but I’ve not bothered to yet, I just spam C-g
when using magit on nix repos with lots of flake.lock
update commits.
I’ve not really noticed any other issues. One detail maybe is that lsp-mode
determines which language servers are installed at startup time, and therefore doesn’t notice the language servers direnv
adds, so I use eglot
. eglot
is built-in and better in every way anyway.
For some reason I was imagining new processes spawning that were inheriting from emacs, but I guess yeah, it’s just going fork off a single process and all the children will be rooted in that process.
That makes sense. I’m not a flake user (yet), so I’ll take this on advice.
Happy eglot user. eglot is love, eglot is life!
shell.nix
in turn is slower to evaluate in general, so you might still notice a delay the first time you enter projects with a nix shell. Channel updates will cause the same issues as changing flake.lock
, though at least rebasing should be unaffected.
Thanks, this worked.
Here’s how:
M-x gud-gdb RET nix-shell -p rustc cargo rr --command "rr replay -M -d rust-gdb --fullname"
Has anyone tried envrc instead of emacs-direnv?
I often use M-x compile
while in *Help*
buffers and such, and find it nicer to not need to keep an eye on what buffer I am in. But yes, if you prefer buffer-local variables I don’t see why that would not work for you.