texto python emacs python-mode dot-emacs

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:

  1. 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).

  2. Una segunda opción es utilizar el argumento LOCAL opcional para add-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 con hack-local-variables-hook para el búfer actual solamente; y esa función se llama luego de que las variables locales hayan sido procesadas.

  3. 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 configura local-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 un mode: 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?