Repository: rust-lang/rust-mode (language: rust)

Issue:
Better support for `envrc`
I have been using `rust-mode` on a project whose Rust version I manage using `direnv` and the associated emacs package `envrc`.  When I try to use `rust-test`, it can't find `cargo`. 

How `envrc` works is by making `process-environment` a file-local variable and updating it analogously to running `direnv reload`. However, because `process-environment` has not historically been file-local, some uses of it don't work the way you would expect. In particular, invoking `with-temp-buffer` does not re-use the correct environment. It's idiomatic in elisp to call `call-process` inside `with-temp-buffer` to capture its output, and because `with-temp-buffer` uses another environment, `call-process` cannot find executables that "should" be available in that directory.

I filed https://github.com/purcell/envrc/issues/12 to try to identify the correct solution to this problem. It feels like a footgun in emacs/elisp itself, but in the short term, Steve Purcell has been kind enough to write a utility library called `inheritenv` which allows these temporary buffers to inherit the environment from the buffer where they are being created. Alternately, it's possible for affected packages (like `rust-mode`) to define a utility that is like `with-temp-buffer` but propagates the environment, as in https://github.com/magit/magit/pull/4169/. I think one of these approaches would be a good change for `rust-mode`.


Discussion / hints:
Pull requests are very welcome :+1: 

Fix patch:
diff --git a/rust-cargo.el b/rust-cargo.el
index 58f0151..9f6e611 100644
--- a/rust-cargo.el
+++ b/rust-cargo.el
@@ -30,13 +30,24 @@
 
 (defun rust-buffer-project ()
   "Get project root if possible."
-  (with-temp-buffer
-    (let ((ret (call-process rust-cargo-bin nil t nil "locate-project")))
-      (when (/= ret 0)
-        (error "`cargo locate-project' returned %s status: %s" ret (buffer-string)))
-      (goto-char 0)
-      (let ((output (json-read)))
-        (cdr (assoc-string "root" output))))))
+  ;; Copy environment variables into the new buffer, since
+  ;; with-temp-buffer will re-use the variables' defaults, even if
+  ;; they have been changed in this variable using e.g. envrc-mode.
+  ;; See https://github.com/purcell/envrc/issues/12.
+  (let ((env process-environment)
+        (path exec-path))
+    (with-temp-buffer
+      ;; Copy the entire environment just in case there's something we
+      ;; don't know we need.
+      (setq-local process-environment env)
+      ;; Set PATH so we can find cargo.
+      (setq-local exec-path path)
+      (let ((ret (call-process rust-cargo-bin nil t nil "locate-project")))
+        (when (/= ret 0)
+          (error "`cargo locate-project' returned %s status: %s" ret (buffer-string)))
+        (goto-char 0)
+        (let ((output (json-read)))
+          (cdr (assoc-string "root" output)))))))
 
 (defun rust-update-buffer-project ()
   (setq-local rust-buffer-project (rust-buffer-project)))


Test patch: