Gibt es eine Möglichkeit, .dir-locals.el-Dateien zu verketten?

16

Angenommen, ich habe ein Verzeichnis mit diesen Dateien.

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

Wenn ich zum Erstellen einer Datei gehe /foo/bar/baz/, möchte ich sie so verketten, dass sie /foo/.dir-locals.elzuerst und dann /foo/bar/.dir-locals.elund dann angewendet werden/foo/bar/baz/.dir-locals.el

Eric Johnson
quelle
Dazugehöriger Thread: Wie kann ich eine Sekunde haben .dir-locals? .
Dan
Es gibt keine Option, die dies tun würde (ich habe mir den Code ziemlich genau angesehen), aber es sollte (mit ziemlicher Sicherheit) mit etwas zusätzlichem Code möglich sein. Ich kann es auch gebrauchen, also könnte ich das untersuchen ...
Constantine
Mit elisp ist alles möglich. :)
Eric Johnson

Antworten:

7

Basierend auf der Antwort hier raten wir dazu hack-dir-local-variables, ein Verzeichnis nachzuschlagen und zu überprüfen, ob diese .dir-locals.elDatei lesbar ist. Es wird so lange hochgefahren, bis ein nicht lesbares Verzeichnis gefunden wird .dir-locals.el.

Je nach Wert walk-dir-locals-upwardder Dateien kann vom aktuellen Verzeichnis aufwärts oder vom zuletzt .dir-locals.elgefundenen abwärts gelesen werden . Abwärts ist die Standardeinstellung, damit Unterverzeichnisse die Einstellungen ihrer Eltern löschen können.

(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
quelle
Dies scheint zu erwarten, dass jedes Verzeichnis in der Struktur (bis zu einer bestimmten Ebene über dem aktuellen Pfad) eine hat .dir-locals.el. Wird es funktionieren , wenn ich einen Baum von Verzeichnissen haben a/b/cund es existieren a/.dir-locals.elund a/b/c/.dir-locals.el, aber nicht a/b/.dir-locals.el(davon ausgehen , dass ich besuche a/b/c/foo.elund ich möchte Einstellungen a/.dir-locals.elangewendet werden)?
Constantine
1
Ja, das nehme ich an. Die fehlenden Einheimischen a/b/unterbrechen die Kette. Es muss irgendwo anhalten und wenn Sie möchten, dass es weitergeht, können Sie leere Verzeichnisdateien hinzufügen.
Erikstokes
3
Übrigens, ich würde einen Patch für Emacs begrüßen, der Dir-Locals direkt nach dem Auspacken unterstützt.
Stefan
5

Hier ist ein anderer Weg, dies zu tun.

Ich definiere eine Funktion, die die Liste aller Verzeichnisse in der aktuellen Verzeichnishierarchie erzeugt.

(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) "" ()))

Ein Beispiel ist in Ordnung:

(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")

Jetzt kann ich Ratschläge hinzufügen hack-dir-local-variables, um vorzutäuschen, dass wir eine Datei ganz oben in der Baumstruktur besuchen, verzeichnislokale Einstellungen anwenden, dann eine Ebene nach unten gehen, Einstellungen erneut anwenden und so weiter.

(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)
Konstantin
quelle