¿Hay alguna manera de encadenar archivos .dir-locals.el?

15

Supongamos que tengo un directorio con estos archivos.

/foo/bar/baz/.dir-locals.el
/foo/bar/.dir-locals.el
/foo/.dir-locals.el

Cuando voy a crear un archivo /foo/bar/baz/, me gustaría encadenarlos para que se /foo/.dir-locals.elapliquen primero, y luego /foo/bar/.dir-locals.el, y luego/foo/bar/baz/.dir-locals.el

Eric Johnson
fuente
No hay ninguna opción que haga eso (miré el código bastante de cerca), pero debería ser (casi seguro que es posible) con algún código adicional. Yo también lo uso, así que podría investigar esto ...
Constantino
Con elisp, todo es posible. :)
Eric Johnson

Respuestas:

7

Con base en la respuesta aquí , hacemos esto al aconsejar hack-dir-local-variablesque busquemos un directorio y carguemos si ese .dir-locals.elarchivo es legible. Continuará subiendo hasta que encuentre un directorio que no sea legible .dir-locals.el.

Dependiendo del valor de walk-dir-locals-upwardlos archivos se pueden leer desde el directorio actual hacia arriba o desde el último .dir-locals.elencontrado hacia abajo. Hacia abajo es el valor predeterminado para que los subdirectorios puedan cambiar la configuración de sus padres.

(defvar walk-dir-locals-upward nil
  "If non-nil, evaluate .dir-locals.el files starting in the
  current directory and going up. Otherwise they will be
  evaluated from the top down to the current directory.")

(defadvice hack-dir-local-variables (around walk-dir-locals-file activate)
  (let* ((dir-locals-list (list dir-locals-file))
         (walk-dir-locals-file (first dir-locals-list)))
    (while (file-readable-p (concat "../" walk-dir-locals-file))
      (progn
        (setq walk-dir-locals-file (concat "../" walk-dir-locals-file))
        (add-to-list 'dir-locals-list walk-dir-locals-file
                     walk-dir-locals-upward)
        ))
    (dolist (file dir-locals-list)
      (let ((dir-locals-file (expand-file-name file)))
        (message dir-locals-file)
        ad-do-it
        )))
  )
erikstokes
fuente
Esto parece esperar que cada directorio en el árbol (hasta cierto nivel desde la ruta actual) tenga un .dir-locals.el. ¿Funcionará si tengo un árbol de directorios a/b/cy existen a/.dir-locals.ely a/b/c/.dir-locals.el, pero no a/b/.dir-locals.el(supongo que estoy visitando a/b/c/foo.ely quiero a/.dir-locals.elque se aplique la configuración )?
Constantine
1
Sí, eso es lo que estoy asumiendo. Los dir-locales que faltan a/b/rompen la cadena. Tiene que detenerse en algún lugar y, si desea que continúe, puede agregar archivos dir-locales vacíos.
erikstokes
3
Por cierto, agradecería un parche para Emacs para admitir el encadenamiento de locales de directorio fuera de la caja.
Stefan
6

Aquí hay una forma diferente de hacer esto.

Defino una función que produce la lista de todos los directorios en la jerarquía de directorios actual.

(defun file-name-directory-nesting-helper (name previous-name accumulator)
  (if (string= name previous-name)
      accumulator                       ; stop when names stop changing (at the top)
      (file-name-directory-nesting-helper
       (directory-file-name (file-name-directory name))
       name
       (cons name accumulator))))

(defun file-name-directory-nesting (name)
  (file-name-directory-nesting-helper (expand-file-name name) "" ()))

Un ejemplo está en orden:

(file-name-directory-nesting "/foo/bar/baz/quux/foo.el")
;; => ("/" "/foo" "/foo/bar" "/foo/bar/baz" "/foo/bar/baz/quux" "/foo/bar/baz/quux/foo.el")

Ahora puedo agregar consejos para hack-dir-local-variables"simular" que estamos visitando un archivo en la parte superior del árbol, aplicar configuraciones locales de directorio, luego bajar un nivel, aplicar configuraciones nuevamente, y así sucesivamente.

(defun hack-dir-local-variables-chained-advice (orig)
  "Apply dir-local settings from the whole directory hierarchy,
from the top down."
  (let ((original-buffer-file-name (buffer-file-name))
        (nesting (file-name-directory-nesting (or (buffer-file-name)
                                                  default-directory))))
    (unwind-protect
        (dolist (name nesting)
          ;; make it look like we're in a directory higher up in the
          ;; hierarchy; note that the file we're "visiting" does not
          ;; have to exist
          (setq buffer-file-name (expand-file-name "ignored" name))
          (funcall orig))
      ;; cleanup
      (setq buffer-file-name original-buffer-file-name))))

(advice-add 'hack-dir-local-variables :around
            #'hack-dir-local-variables-chained-advice)
Constantina
fuente