从doom中将生成环境变量的脚本单独拿出来

由于 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)
5 个赞