2011-02-28 14 views
7

he definido un archivo .dir-locals.el con el siguiente contenido:¿Cómo puedo acceder a las variables de directorio local en mis ganchos de modo principal?

((python-mode . ((cr/virtualenv-name . "saas")))) 

En mis .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"))) 

por último, en mi lista de python-mode-hook, 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))))) 

al abrir un nuevo archivo de pitón, el mensaje registrado por cr/python-mode-shell-setup indica que cr/virtualenv-name es nil. Sin embargo, cuando C-h v 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?

Respuesta

12

Esto ocurre porque normal-mode llama a (set-auto-mode) y (hack-local-variables) en ese orden.

Sin embargo hack-local-variables-hook se ejecuta después de las variables locales han sido procesados, lo que permite a algunas soluciones:

  1. La primera es hacer que Emacs ejecuta una nueva "variables locales gancho" para cada modo mayor:

    (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 utilizar sin modificar, con ese enfoque.)

  2. Una segunda opción es utilizar el programa opcional LOCAL argumento a add-hook que hace que la función especificada sea buffer-local. Con este enfoque se podría escribir su 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 carreras primera y registra la función anónima con hack-local-variables-hook por sólo el búfer en uso; 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 gustaba la idea de causar (hack-local-variables) ser llamado dos veces, pero veo que si establece el tampón localmente local-enable-local-variables, evita que (hack-local-variables) de hacer cualquier cosa, por lo que podría 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 configurado por una variable local comentario 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 la variable local (por ejemplo, -*- mode: foo -*-) son manejados por (set-auto-mode), por lo que están bien; pero un comentario mode: fooLocal Variables: parece que sería un problema, ya que es manejado por (hack-local-variables), y si el modo está configurado de esa manera pensé que causaría recursividad.

    En la práctica pude desencadenar el problema mediante el uso de una función simple como un 'modo', que no hizo más que intentan encontrar a su ganchos; Sin embargo las pruebas con un modo 'adecuado' no presentan el problema, por lo que es probable que sea seguro en la realidad. No miré más en esto (como las otras dos soluciones son mucho más limpio que esto), pero me imagino el mecanismo de modo de ganchos retraso probablemente lo explica?

+0

¿Tal vez podría llamar (hack-local-variables) desde su gancho? – Lindydancer

+2

Desearía poder votar esto dos veces. –

Cuestiones relacionadas