python - emacs editor de texto
¿Cómo puedo acceder a las variables de directorio local en mis ganchos de modo principal? (1)
Esto sucede porque normal-mode
llamadas en normal-mode
(set-auto-mode)
y (hack-local-variables)
en ese orden.
Sin embargo, se ejecuta hack-local-variables-hook
después de que se hayan procesado las variables locales, lo que permite algunas soluciones:
El primero es hacer que Emacs ejecute un nuevo "enlace de variables locales" para cada modo principal:
(add-hook ''hack-local-variables-hook ''run-local-vars-mode-hook) (defun run-local-vars-mode-hook () "Run a hook for the major-mode after the local variables have been processed." (run-hooks (intern (concat (symbol-name major-mode) "-local-vars-hook")))) (add-hook ''python-mode-local-vars-hook ''cr/python-mode-shell-setup)
(Su función original se puede usar sin modificaciones, con ese enfoque).
Una segunda opción es utilizar el argumento
LOCAL
opcional paraadd-hook
que hace que la función especificada sea buffer-local. Con este enfoque, puedes escribir tu gancho de la siguiente manera:(add-hook ''python-mode-hook ''cr/python-mode-shell-setup) (defun cr/python-mode-shell-setup () (add-hook ''hack-local-variables-hook (lambda () (message "virtualenv-name is %s" cr/virtualenv-name) (let ((python-base (cr/virtualenv))) (cond ((and (fboundp ''ipython-shell-hook) (file-executable-p (concat python-base "/bin/ipython"))) (setq python-python-command (concat python-base "/bin/ipython")) (setq py-python-command (concat python-base "/bin/ipython")) (setq py-python-command-args ''( "-colors" "NoColor"))) (t (setq python-python-command (concat python-base "/bin/python")) (setq py-python-command (concat python-base "/bin/python")) (setq py-python-command-args nil))))) nil t)) ; buffer-local hack-local-variables-hook
es decir,
python-mode-hook
ejecuta primero y registra la función anónima conhack-local-variables-hook
para el búfer actual solamente; y esa función se llama luego de que las variables locales hayan sido procesadas.El comentario de Lindydancer sugiere un tercer enfoque. No es tan limpio como los otros dos, pero resultó interesante a pesar de todo. No me gustó la idea de provocar
(hack-local-variables)
dos veces, pero veo que si configuralocal-enable-local-variables
buffer-local, evita(hack-local-variables)
de haciendo cualquier cosa, entonces puedes hacer esto:(defun cr/python-mode-shell-setup () (report-errors "File local-variables error: %s" (hack-local-variables))) (set (make-local-variable ''local-enable-local-variables) nil) (let ((python-base (cr/virtualenv))) ...))
Obviamente eso modifica un poco la secuencia normal de ejecución, por lo que los efectos secundarios pueden ser posibles. Me preocupaba que si el mismo modo principal fuera establecido por un comentario de variable local en el archivo, esto podría causar una recursión infinita, pero eso en realidad no parece ser un problema.
Los comentarios del encabezado de variable local (por ejemplo,
-*- mode: foo -*-
) son manejados por(set-auto-mode)
, por lo que están bien; pero unmode: foo
Local Variables:
comentario parece ser un problema, ya que es manejado por(hack-local-variables)
, y si el modo está configurado de esa manera, pensé que causaría recursión.En la práctica, pude desencadenar el problema usando una función simple como un ''modo'' que no hizo más que tratar de ejecutar sus ganchos; sin embargo, las pruebas con un modo "apropiado" no presentaron el problema, por lo que probablemente sea seguro en realidad. No profundicé en esto (ya que las otras dos soluciones son mucho más limpias que esto), pero supongo que el mecanismo de ganchos de modo retardado probablemente lo explique.
Definí un archivo .dir-locals.el con el siguiente contenido:
((python-mode . ((cr/virtualenv-name . "saas"))))
En my .emacs tengo la siguiente función para recuperar este valor y proporcionar una ruta virtualenv:
(defun cr/virtualenv ()
(cond (cr/virtualenv-name (format "%s/%s" virtualenv-base cr/virtualenv-name))
((getenv "EMACS_VIRTUAL_ENV") (getenv "EMACS_VIRTUAL_ENV"))
(t "~/.emacs.d/python")))
Finalmente, en mi lista de gancho de modo de pitón, tengo esta función de enlace:
(add-hook ''python-mode-hook ''cr/python-mode-shell-setup)
(defun cr/python-mode-shell-setup ()
(message "virtualenv-name is %s" cr/virtualenv-name)
(let ((python-base (cr/virtualenv)))
(cond ((and (fboundp ''ipython-shell-hook) (file-executable-p (concat python-base "/bin/ipython")))
(setq python-python-command (concat python-base "/bin/ipython"))
(setq py-python-command (concat python-base "/bin/ipython"))
(setq py-python-command-args ''( "-colors" "NoColor")))
(t
(setq python-python-command (concat python-base "/bin/python"))
(setq py-python-command (concat python-base "/bin/python"))
(setq py-python-command-args nil)))))
Cuando abro un nuevo archivo python, el mensaje registrado por cr/python-mode-shell-setup
indica que cr/virtualenv-name
es nil
. Sin embargo, cuando me encuentro con el nombre, obtengo "saas" en su lugar.
Obviamente hay un problema de orden de carga aquí; ¿Hay alguna manera de que mis declaraciones hook de modo respondan a las variables de directorio local?