由于 exec-path-from-shell
启动一个子进程并加载比起 doom
生成一个 env
文件并加载的方式重太多了, 从论坛里没搜到类似的分享, 所以就自己从 doom
中把这部分单独拿出来了.
;; 首先是一个env.el脚本用来生成写入环境变量
;; -*- lexical-binding: t -*-
(defvar doom-env-deny '()
"Environment variables to omit from envvar files.
Each string is a regexp, matched against variable names to omit from
`doom-env-file'.")
(defvar doom-env-allow '()
"Environment variables to include in envvar files.
This overrules `doom-env-deny'. Each string is a regexp, matched against
variable names to omit from `doom-env-file'.")
(setq env-file (expand-file-name "env" user-emacs-directory))
(delete-file env-file)
(with-temp-file env-file
(let (
(rpartial (lambda (&rest args)
(lambda (&rest pre-args)
(apply #'string-match-p (append pre-args args))))))
(insert "(")
(dolist (env process-environment)
(catch 'skip
(let* (
(var (car (split-string env "=")))
(pred (funcall rpartial var))
)
(when (seq-find pred doom-env-deny)
(if (seq-find pred doom-env-allow)
(message "cli:env allow %s" var)
(message "cli:env deny %s" var)
(throw 'skip t)))
(insert (prin1-to-string env) "\n "))))
(insert ")"))
)
;; 然后是启动子进程拿到完整的环境变量, 并使用 `emacs --batch` 去执行上面的文件
(setq env-file (expand-file-name "env" user-emacs-directory))
(defun doom-call-process (command &rest args)
"Execute COMMAND with ARGS synchronously.
Returns (STATUS . OUTPUT) when it is done, where STATUS is the returned error
code of the process and OUTPUT is its stdout output."
(with-temp-buffer
(cons (or (apply #'call-process command nil t nil (remq nil args))
-1)
(string-trim (buffer-string)))))
(defun generate-env-file ()
(interactive)
(doom-call-process "zsh" "-lic" "emacs --batch -l 'env.el'"))
;; 从文件中加载环境变量
(defun doom-load-envvars-file (file &optional noerror)
"Read and set envvars from FILE.
If NOERROR is non-nil, don't throw an error if the file doesn't exist or is
unreadable. Returns the names of envvars that were changed."
(if (null (file-exists-p file))
(unless noerror
(signal 'file-error (list "No envvar file exists" file)))
(with-temp-buffer
(insert-file-contents file)
(when-let (env (read (current-buffer)))
(let ((tz (getenv-internal "TZ")))
(setq-default
process-environment
(append env (default-value 'process-environment))
exec-path
(append (split-string (getenv "PATH") path-separator t)
(list exec-directory))
shell-file-name
(or (getenv "SHELL")
(default-value 'shell-file-name)))
(when-let (newtz (getenv-internal "TZ"))
(unless (equal tz newtz)
(set-time-zone-rule newtz))))
env))))
(doom-load-envvars-file env-file)