【问题标题】:How can I set environment variables to a buffer-local scope in emacs如何在 emacs 中将环境变量设置为缓冲区本地范围
【发布时间】:2017-03-15 03:18:26
【问题描述】:

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

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

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

【问题讨论】:

    标签: emacs elisp


    【解决方案1】:

    您可以通过 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)
    

    【讨论】:

    • 这个“过程环境”变量正是我想要的。
    • 对于只想影响M-x compile 环境的任何人,您可以简单地使用compilation-environment 变量。详情见最后一段here。您还可以将此可变缓冲区本地化
    • @Felipe 好点,尽管 OP 确实特别提到了 flymake,它不是 compilation-mode 的一部分。
    【解决方案2】:

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

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

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

    【讨论】:

    • 您正在设置全局值。
    【解决方案3】:

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

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

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

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

    【讨论】:

    • 显然,@user4815162342 的回答比这个要好,因为 Emacs 似乎已经有了处理子进程环境的机制……
    【解决方案4】:

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

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

    【讨论】:

    • 这是关于 环境 变量,而不是 Lisp 变量。动态绑定本身并没有什么难解释的,事实上它仍然是 Emacs Lisp 中的默认设置。
    • 对,没仔细看问题。但是动态作用域很难向不习惯的人解释——它是 Elisp 中的默认设置并不能使其更容易理解
    • 动态作用域有很多问题,但难以理解不是其中之一。它实际上很容易理解,这就是为什么它是 BASIC、各种 shell、Perl、各种 Lisps 等语言的默认设置。
    【解决方案5】:

    这是一个示例,我创建了一个本地 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 ...))))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-20
      • 2018-08-04
      • 1970-01-01
      • 2011-01-06
      • 2013-07-11
      • 2021-09-09
      • 2013-09-01
      相关资源
      最近更新 更多