如何在emacs中将环境变量设置为缓冲区本地范围

时间:2013-05-28 08:00:30

标签: emacs elisp

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

我的emacs环境依赖于环境变量(flymake,编译等),但我希望能够在一个emacs会话中同时打开多个项目,但这些项目可能存在冲突的环境。

例如类似于flymake的不同INCLUDE_PATH环境变量。

5 个答案:

答案 0 :(得分:15)

您可以通过process-environment buffer-local:

来完成此操作
(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)

答案 1 :(得分:1)

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

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

1)编写自己的函数,如my-compile,暂时更改环境并调用正常的编译命令。

2)修改低级流程函数并确保它们相应地修改环境。通常,您可以使用defadvice执行此操作。

答案 2 :(得分:0)

可以对这些变量使用动态绑定

动态绑定动态范围有点难以解释,有关解释,请参阅http://www.emacswiki.org/emacs/DynamicBindingVsLexicalBindinghttp://en.wikipedia.org/wiki/Scope_(computer_science)#Dynamic_scoping

答案 3 :(得分: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 ...))))

答案 4 :(得分:-1)

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

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

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