10

在 Emacs 中,我想在不同的缓冲区中改变环境变量的值。

我的 emacs 环境取决于环境变量(flymake、compile 等),但是我希望能够在一个 emacs 会话中同时打开多个项目,但这些项目可能有冲突的环境。

例如,flymake 的不同 INCLUDE_PATH 环境变量。

4

5 回答 5

15

您可以通过使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)
于 2013-05-28T09:59:57.863 回答
2

我将以下内容放在.dir-locals.el要定义一些环境变量的树的根部:

;; variables local to this directory and its children
((nil . ((eval . (setenv "SOME_VARIABLE" "TRUE")))))

这将在您第一次打开该目录树中的文件时发出警告。接受后,将为您在那里打开的每个缓冲区定义给定的环境变量。

于 2013-05-28T09:47:11.583 回答
1

一种解决方案是在生成外部命令时临时更改环境。该命令将继承当前环境。请记住,Emacs 是一个单线程应用程序,因此我们不必担心竞争条件等。

您可以选择以下两种方式之一:

1)编写你自己的函数,这样my-compile会暂时改变环境并调用正常的编译命令。

2) 修改低级进程函数,并确保它们相应地修改环境。通常,您可以使用defadvice.

于 2013-05-28T09:11:26.107 回答
0

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.

于 2013-05-28T10:49:33.217 回答
0

这是一个示例,其中我创建了一个本地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 ...))))
于 2017-03-14T03:16:48.740 回答