在 Emacs 中,我想在不同的缓冲区中改变环境变量的值。
我的 emacs 环境取决于环境变量(flymake、compile 等),但是我希望能够在一个 emacs 会话中同时打开多个项目,但这些项目可能有冲突的环境。
例如,flymake 的不同 INCLUDE_PATH 环境变量。
您可以通过使process-environment
缓冲区本地化来做到这一点:
(defun setup-some-mode-env ()
(make-local-variable 'process-environment)
;; inspect buffer-file-name and add stuff to process-environment as necessary
...)
(add-hook 'some-major-mode 'setup-some-mode-env)
更详细的示例是导入由外部脚本创建的 Guile 环境设置的代码。该脚本被设计为在 shell 中“获取”,但在这里它的结果被导入到单个 Emacs 缓冲区中:
(defun my-guile-setup ()
(make-local-variable 'process-environment)
(with-temp-buffer
(call-process "bash" nil t nil "-c"
"source ~/work/guileenv; env | egrep 'GUILE|LD_LIBRARY_PATH'")
(goto-char (point-min))
(while (not (eobp))
(setq process-environment
(cons (buffer-substring (point) (line-end-position))
process-environment))
(forward-line 1))))
(add-hook 'guile-hook 'my-guile-setup)
我将以下内容放在.dir-locals.el
要定义一些环境变量的树的根部:
;; variables local to this directory and its children
((nil . ((eval . (setenv "SOME_VARIABLE" "TRUE")))))
这将在您第一次打开该目录树中的文件时发出警告。接受后,将为您在那里打开的每个缓冲区定义给定的环境变量。
一种解决方案是在生成外部命令时临时更改环境。该命令将继承当前环境。请记住,Emacs 是一个单线程应用程序,因此我们不必担心竞争条件等。
您可以选择以下两种方式之一:
1)编写你自己的函数,这样my-compile
会暂时改变环境并调用正常的编译命令。
2) 修改低级进程函数,并确保它们相应地修改环境。通常,您可以使用defadvice
.
It may be possible to use dynamic binding for those variables.
Dynamic binding and Dynamic scoping are a bit hard to explain, for explanations see http://www.emacswiki.org/emacs/DynamicBindingVsLexicalBinding and http://en.wikipedia.org/wiki/Scope_(computer_science)#Dynamic_scoping.
这是一个示例,其中我创建了一个本地process-environment
而不必创建它buffer-local
。优点是设置只影响正在运行的进程,一旦进程结束它们就会消失。在这个例子中,我设置了 timzezone 环境变量并调用了这个函数,(funcall my-start-process ....)
其他的一切都和参数一样start-process
。
(let* ((my-start-process
(lambda (name buffer program &rest program-args)
(unless (fboundp 'make-process)
(error "Emacs was compiled without subprocess support"))
(let* (
(temp (mapcar 'concat process-environment))
(newenv
(cond
((equal (car (cdr (current-time-zone))) "PDT")
(setenv-internal temp "TZ" "UTC+7" t))
((equal (car (cdr (current-time-zone))) "PST")
(setenv-internal temp "TZ" "UTC+8" t))))
(process-environment (or newenv temp)))
(apply #'make-process
(append (list :name name :buffer buffer)
(when program
(list :command (cons program program-args))))))))
(proc (funcall my-start-process ...))))