summaryrefslogtreecommitdiff
path: root/guix-shell.el
diff options
context:
space:
mode:
Diffstat (limited to 'guix-shell.el')
-rw-r--r--guix-shell.el102
1 files changed, 67 insertions, 35 deletions
diff --git a/guix-shell.el b/guix-shell.el
index bf5640f..61478c9 100644
--- a/guix-shell.el
+++ b/guix-shell.el
@@ -20,15 +20,15 @@
"Project environment variable cache.")
(defun guix-shell--current-directory ()
- (project-root (project-current)))
-
-(defvar guix-shell--hooks '(post-command-hook before-hack-local-variables-hook)
- "Hooks that guix shell should hook into.")
-
-(defvar guix-shell--last-directory nil
- "The last directory used for running guix shell.")
+ "Return the project directory for the current buffer."
+ (let ((project (project-current)))
+ (if project
+ (project-root project)
+ default-directory)))
(defun guix-shell--search-paths-for-directory (directory)
+ "Execute 'guix shell' in DIRECTORY, parse the output, and return
+an alist of search path environment variables."
(let ((buffer (get-buffer-create "*guix-shell-temp*"))
(names '()))
(with-current-buffer buffer
@@ -77,51 +77,83 @@
env-vars))))
(defun guix-shell--update-search-paths-for-directory (directory)
+ "Refresh the cached 'guix shell' search paths for DIRECTORY."
(when directory
(let ((search-paths (guix-shell--search-paths-for-directory directory)))
(setq guix-shell--search-paths
- (cons (cons directory search-paths)
+ (cons (cons directory (or search-paths 'none))
(assoc-delete-all directory guix-shell--search-paths)))
search-paths)))
(defun guix-shell--cached-search-paths-for-directory (directory)
+ "Return an alist of 'guix shell' search paths cached for
+DIRECTORY. If there are no cached search paths, nil is returned.
+If the search paths are cached but DIRECTORY has no 'guix shell'
+search paths present, 'none' is returned.."
(cdr (assoc directory guix-shell--search-paths)))
+;; From envrc.el
+(defun guix-shell--merged-environment (process-env pairs)
+ "Make a `process-environment' value that merges PROCESS-ENV with PAIRS.
+PAIRS is an alist obtained from direnv's output. Values from
+PROCESS-ENV will be included, but their values will be masked by
+Emacs' handling of `process-environment' if they also appear in
+PAIRS."
+ (append (mapcar (lambda (pair)
+ (format "%s=%s" (car pair) (cdr pair)))
+ pairs)
+ process-env))
+
(defun guix-shell--apply-search-paths (search-paths)
- (dolist (pair search-paths)
- (let ((name (car pair))
- (search-path (cdr pair)))
- (setenv name search-path)
- (when (string-equal name "PATH")
- (setq exec-path (append (parse-colon-path search-path)
- (list exec-directory)))))))
+ "Apply SEARCH-PATHS to the environment of the current buffer."
+ (setq-local process-environment
+ (guix-shell--merged-environment process-environment search-paths))
+ (setq-local exec-path (append (parse-colon-path (getenv "PATH"))
+ (list exec-directory)))
+ (when (derived-mode-p 'eshell-mode)
+ (setq-local eshell-path-env path)))
(defun guix-shell--apply-search-paths-for-directory (directory)
- ;; TODO: What if the search paths have been updated and need to be
- ;; re-applied? This doesn't account for that case currently. The only way
- ;; to update would be to switch to a buffer in a different project and then
- ;; change back.
- (when (and directory
- (not (string-equal directory guix-shell--last-directory)))
- (guix-shell--apply-search-paths
- (or (guix-shell--cached-search-paths-for-directory directory)
- (guix-shell--update-search-paths-for-directory directory)))
- (setq guix-shell--last-directory directory)))
+ "Set search path environment variables from 'guix shell' for
+DIRECTORY."
+ (when directory
+ (let ((search-paths
+ (or (guix-shell--cached-search-paths-for-directory directory)
+ (guix-shell--update-search-paths-for-directory directory))))
+ (unless (eq search-paths 'none)
+ (guix-shell--apply-search-paths search-paths)))))
(defun guix-shell--apply-search-paths-for-current-directory ()
+ "Set search path environment variables from 'guix shell' in the
+context of the current directory."
(guix-shell--apply-search-paths-for-directory (guix-shell--current-directory)))
-(defun guix-shell-enable ()
- (interactive)
- (dolist (hook guix-shell--hooks)
- (add-hook hook #'guix-shell--apply-search-paths-for-current-directory)))
-
-(defun guix-shell-disable ()
- (interactive)
- (dolist (hook guix-shell--hooks)
- (remove-hook hook #'guix-shell--apply-search-paths-for-current-directory)))
+(defun guix-shell--clear (buffer)
+ "Remove any effects of `guix-shell-mode' from BUFFER."
+ (with-current-buffer buffer
+ (kill-local-variable 'exec-path)
+ (kill-local-variable 'process-environment)
+ (kill-local-variable 'eshell-path-env)))
(defun guix-shell-update ()
+ "Update the search paths set by 'guix shell'."
(interactive)
(guix-shell--update-search-paths-for-directory
- (guix-shell--current-directory)))
+ (guix-shell--current-directory))
+ (guix-shell--clear (current-buffer))
+ (guix-shell-apply-search-paths-for-current-directory))
+
+;;;###autoload
+(define-minor-mode guix-shell-mode
+ "A local minor mode in which environment variables are set by
+'guix shell'."
+ :init-value nil
+ (if guix-shell-mode
+ (guix-shell--apply-search-paths-for-current-directory)
+ (guix-shell--clear (current-buffer))))
+
+;;;###autoload
+(define-globalized-minor-mode guix-shell-global-mode guix-shell-mode
+ (lambda ()
+ (unless (or (minibufferp) (file-remote-p default-directory))
+ (guix-shell-mode 1))))