dir-locals.el 设置未应用于某些变量
dir-locals.el settings not applied to some variables
我想使用我的 .dir-locals.el 在项目上设置 virtualenv 名称。该变量已设置,但在用作其他串联变量中的参数时不被视为。
我尝试将 .dir-locals.el 文件添加到 python 项目。我在其中设置了这个特定项目的 virtualenv 根名称。然后我启动 Emacs,打开一个 .py 文件来检查是否所有需要的变量都用 virtualenv 名称改变了。
我的 emacs 配置中关于 python-mode
的部分
;;; Python mode
(require 'python)
(ensure-package 'python-environment)
(require 'python-environment)
(ensure-package 'python-mode)
(require 'python-mode)
;;; dash used for pip-requirements
(ensure-package 'dash)
(require 'dash)
(require 'pip-requirements)
(require 'jedi-core)
(require 'company-jedi)
(defun init-python-mode()
(setq-local tab-width 4)
(setq-local indent-tabs-mode nil)
(set (make-local-variable 'company-backends)
'((company-jedi company-dabbrev-code)
company-capf company-files))
(setq python-environment-directory (expand-file-name "~/.virtualenvs")
python-indent-guess-indent-offset nil
python-indent-offset 4
jedi:complete-on-dot t
jedi:use-shortcuts t
jedi:tooltip-method nil
jedi:get-in-function-call-delay 0
python-shell-interpreter (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/python")
jedi:server-command (list (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/jediepcserver"))
python-shell-interpreter (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/python")
flycheck-python-pylint-executable (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/pylint")
flycheck-python-flake8-executable (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/flake8")
flycheck-python-pycompile-executable (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/python")
)
(flycheck-mode t)
)
(defun after-init-python-mode()
(eldoc-mode -1)
)
(define-key python-mode-map (kbd "C-c C-k") #'comment-dwim)
(add-to-list 'auto-mode-alist '("\.py\'" . python-mode))
(add-hook 'python-mode-hook #'init-python-mode)
(add-hook 'python-mode-hook #'jedi:setup)
(add-hook 'python-mode-hook #'after-init-python-mode)
项目的 .dir-locals.el 文件
;;; Directory Local Variables
;;; For more information see (info "(emacs) Directory Variables")
((python-mode . ((python-environment-default-root-name . "abc")
)))
Emacs 似乎对我确认在启动时安全的 .dir-locals.el 变量做出反应。之后,通过执行:'describe-variable python-environment-default-root-name' 我得到这个:
python-environment-default-root-name is a variable defined in ‘python-environment.el’.
Its value is "abc"
Original value was "default"
Local in buffer setup.py; global value is "default"
This variable’s value is directory-local, set by the file
‘/home/mkj/dev/adm/.dir-locals.el’.
...这是预期的。
执行时:'describe-variable jedi:server-command'、'describe-variable python-shell-interpreter',以及使用 python-environment-default-root-name 的其他变量,我得到这个:
jedi:server-command is a variable defined in ‘jedi-core.el’.
Its value is ("/home/mkj/.virtualenvs/default/bin/jediepcserver")
This variable may be risky if used as a file-local variable.
python-shell-interpreter is a variable defined in ‘python.el’.
Its value is "/home/mkj/.virtualenvs/default/bin/python"
Original value was "python"
在我看来,使用 python-environment-default-root-name 的变量名 setq 仅在设置默认值且 .dir-locals.el 值为忽略或设置太晚。
这里是否存在竞争条件,或者这只是为 python-模式设置基于 virtualenv 的变量的错误方法?
您可以在挂钩中添加对 hack-local-variables
的调用,以使 dir-locals 可用。通常,通过调用 (hack-local-variables t)
,只有 mode
局部变量会在您的挂钩之前设置。与 python-mode
、您的挂钩和 hack-local-variables
相关的调用通常看起来像
1 -> (normal-mode t)
| 2 -> (hack-local-variables t)
| 2 <- hack-local-variables: nil
| 2 -> (python-mode)
| | 3 -> (my-python-hook)
| | 3 <- my-python-hook: ("~/.virtualenvs/default/bin/jediepcserver")
| | 3 -> (hack-local-variables no-mode) ;; you want this called prior to your hook
| | 3 <- hack-local-variables: nil
| 2 <- python-mode: nil
1 <- normal-mode: t
所以,你可以修改你的钩子,
(defun my-python-hook ()
(hack-local-variables)
;; ...
)
不过,这似乎不是一个好的解决方案。我不使用 virtualenv,但似乎 python-environment-virtualenv
在这里是相关的。
我发现 elpy 在这方面效果更好。它似乎可以无缝更改公司后端、python 解释器、flycheck 等的变量,而无需任何修改,只需更改 pyvenv-workon 变量即可。
我想使用我的 .dir-locals.el 在项目上设置 virtualenv 名称。该变量已设置,但在用作其他串联变量中的参数时不被视为。
我尝试将 .dir-locals.el 文件添加到 python 项目。我在其中设置了这个特定项目的 virtualenv 根名称。然后我启动 Emacs,打开一个 .py 文件来检查是否所有需要的变量都用 virtualenv 名称改变了。
我的 emacs 配置中关于 python-mode
的部分;;; Python mode
(require 'python)
(ensure-package 'python-environment)
(require 'python-environment)
(ensure-package 'python-mode)
(require 'python-mode)
;;; dash used for pip-requirements
(ensure-package 'dash)
(require 'dash)
(require 'pip-requirements)
(require 'jedi-core)
(require 'company-jedi)
(defun init-python-mode()
(setq-local tab-width 4)
(setq-local indent-tabs-mode nil)
(set (make-local-variable 'company-backends)
'((company-jedi company-dabbrev-code)
company-capf company-files))
(setq python-environment-directory (expand-file-name "~/.virtualenvs")
python-indent-guess-indent-offset nil
python-indent-offset 4
jedi:complete-on-dot t
jedi:use-shortcuts t
jedi:tooltip-method nil
jedi:get-in-function-call-delay 0
python-shell-interpreter (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/python")
jedi:server-command (list (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/jediepcserver"))
python-shell-interpreter (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/python")
flycheck-python-pylint-executable (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/pylint")
flycheck-python-flake8-executable (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/flake8")
flycheck-python-pycompile-executable (concat python-environment-directory
"/" python-environment-default-root-name
"/bin" "/python")
)
(flycheck-mode t)
)
(defun after-init-python-mode()
(eldoc-mode -1)
)
(define-key python-mode-map (kbd "C-c C-k") #'comment-dwim)
(add-to-list 'auto-mode-alist '("\.py\'" . python-mode))
(add-hook 'python-mode-hook #'init-python-mode)
(add-hook 'python-mode-hook #'jedi:setup)
(add-hook 'python-mode-hook #'after-init-python-mode)
项目的 .dir-locals.el 文件
;;; Directory Local Variables
;;; For more information see (info "(emacs) Directory Variables")
((python-mode . ((python-environment-default-root-name . "abc")
)))
Emacs 似乎对我确认在启动时安全的 .dir-locals.el 变量做出反应。之后,通过执行:'describe-variable python-environment-default-root-name' 我得到这个:
python-environment-default-root-name is a variable defined in ‘python-environment.el’.
Its value is "abc"
Original value was "default"
Local in buffer setup.py; global value is "default"
This variable’s value is directory-local, set by the file
‘/home/mkj/dev/adm/.dir-locals.el’.
...这是预期的。
执行时:'describe-variable jedi:server-command'、'describe-variable python-shell-interpreter',以及使用 python-environment-default-root-name 的其他变量,我得到这个:
jedi:server-command is a variable defined in ‘jedi-core.el’.
Its value is ("/home/mkj/.virtualenvs/default/bin/jediepcserver")
This variable may be risky if used as a file-local variable.
python-shell-interpreter is a variable defined in ‘python.el’.
Its value is "/home/mkj/.virtualenvs/default/bin/python"
Original value was "python"
在我看来,使用 python-environment-default-root-name 的变量名 setq 仅在设置默认值且 .dir-locals.el 值为忽略或设置太晚。
这里是否存在竞争条件,或者这只是为 python-模式设置基于 virtualenv 的变量的错误方法?
您可以在挂钩中添加对 hack-local-variables
的调用,以使 dir-locals 可用。通常,通过调用 (hack-local-variables t)
,只有 mode
局部变量会在您的挂钩之前设置。与 python-mode
、您的挂钩和 hack-local-variables
相关的调用通常看起来像
1 -> (normal-mode t)
| 2 -> (hack-local-variables t)
| 2 <- hack-local-variables: nil
| 2 -> (python-mode)
| | 3 -> (my-python-hook)
| | 3 <- my-python-hook: ("~/.virtualenvs/default/bin/jediepcserver")
| | 3 -> (hack-local-variables no-mode) ;; you want this called prior to your hook
| | 3 <- hack-local-variables: nil
| 2 <- python-mode: nil
1 <- normal-mode: t
所以,你可以修改你的钩子,
(defun my-python-hook ()
(hack-local-variables)
;; ...
)
不过,这似乎不是一个好的解决方案。我不使用 virtualenv,但似乎 python-environment-virtualenv
在这里是相关的。
我发现 elpy 在这方面效果更好。它似乎可以无缝更改公司后端、python 解释器、flycheck 等的变量,而无需任何修改,只需更改 pyvenv-workon 变量即可。