From: shipmints Date: Sun, 16 Feb 2025 19:30:45 +0000 (-0500) Subject: Ensure .dir-locals-2.el behavior as documented (bug#75890) X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=d1626c56949e26dbe4e5df1f34b902aca0b70d39;p=emacs.git Ensure .dir-locals-2.el behavior as documented (bug#75890) * lisp/files.el (dir-locals--all-files): New &optional 'base-el-only' argument. (dir-locals--base-file): New function. (dir-locals-find-file): 'locate-dominating-file' only for the base .dir-locals.el. * test/lisp/files-tests.el (files-test-dir-locals-2-solo): New test. * test/lisp/files-resources/dir-locals-2-solo: New test support. (files-test-dir-locals-2-paired): New test. * test/lisp/files-resources/dir-locals-and-2: New test support. (cherry picked from commit 81c21d89ede8dfa664b7a3700acd7bf4c9fa54aa) --- diff --git a/lisp/files.el b/lisp/files.el index 771e55effad..97d6280b5c6 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -4756,21 +4756,22 @@ the \".dir-locals.el\". See Info node `(elisp)Directory Local Variables' for details.") -(defun dir-locals--all-files (directory) +(defun dir-locals--all-files (directory &optional base-el-only) "Return a list of all readable dir-locals files in DIRECTORY. The returned list is sorted by increasing priority. That is, values specified in the last file should take precedence over those in the first." (when (file-readable-p directory) (let* ((file-1 (expand-file-name (if (eq system-type 'ms-dos) - (dosified-file-name dir-locals-file) - dir-locals-file) - directory)) + (dosified-file-name dir-locals-file) + dir-locals-file) + directory)) (file-2 (when (string-match "\\.el\\'" file-1) (replace-match "-2.el" t nil file-1))) - (out nil)) - ;; The order here is important. - (dolist (f (list file-2 file-1)) + out) + (dolist (f (or (and base-el-only (list file-1)) + ;; The order here is important. + (list file-2 file-1))) (when (and f (file-readable-p f) ;; FIXME: Aren't file-regular-p and @@ -4780,6 +4781,10 @@ those in the first." (push f out))) out))) +(defun dir-locals--base-file (directory) + "Return readable `dir-locals-file' in DIRECTORY, or nil." + (dir-locals--all-files directory 'base-el-only)) + (defun dir-locals-find-file (file) "Find the directory-local variables for FILE. This searches upward in the directory tree from FILE. @@ -4801,7 +4806,7 @@ This function returns either: entry." (setq file (expand-file-name file)) (let* ((locals-dir (locate-dominating-file (file-name-directory file) - #'dir-locals--all-files)) + #'dir-locals--base-file)) dir-elt) ;; `locate-dominating-file' may have abbreviated the name. (when locals-dir diff --git a/test/lisp/files-resources/dir-locals-2-solo/.dir-locals-2.el b/test/lisp/files-resources/dir-locals-2-solo/.dir-locals-2.el new file mode 100644 index 00000000000..08584933c41 --- /dev/null +++ b/test/lisp/files-resources/dir-locals-2-solo/.dir-locals-2.el @@ -0,0 +1 @@ +((nil . ((dir-locals-2-loaded . t)))) diff --git a/test/lisp/files-resources/dir-locals-2-solo/dir-locals-2-solo.txt b/test/lisp/files-resources/dir-locals-2-solo/dir-locals-2-solo.txt new file mode 100644 index 00000000000..83ed6482e06 --- /dev/null +++ b/test/lisp/files-resources/dir-locals-2-solo/dir-locals-2-solo.txt @@ -0,0 +1,3 @@ +# Used by files-test.el. +# Due to solo .dir-locals-2.el, the local variable `dir-locals-2-loaded' +# should be undefined. diff --git a/test/lisp/files-resources/dir-locals-and-2/.dir-locals-2.el b/test/lisp/files-resources/dir-locals-and-2/.dir-locals-2.el new file mode 100644 index 00000000000..08584933c41 --- /dev/null +++ b/test/lisp/files-resources/dir-locals-and-2/.dir-locals-2.el @@ -0,0 +1 @@ +((nil . ((dir-locals-2-loaded . t)))) diff --git a/test/lisp/files-resources/dir-locals-and-2/.dir-locals.el b/test/lisp/files-resources/dir-locals-and-2/.dir-locals.el new file mode 100644 index 00000000000..2b57bf9e7c0 --- /dev/null +++ b/test/lisp/files-resources/dir-locals-and-2/.dir-locals.el @@ -0,0 +1 @@ +((nil . ((dir-locals-loaded . t)))) diff --git a/test/lisp/files-resources/dir-locals-and-2/dir-locals-and-2.txt b/test/lisp/files-resources/dir-locals-and-2/dir-locals-and-2.txt new file mode 100644 index 00000000000..bb8a31ca147 --- /dev/null +++ b/test/lisp/files-resources/dir-locals-and-2/dir-locals-and-2.txt @@ -0,0 +1,4 @@ +# Used by files-test.el. +# .dir-locals.el and .dir-locals-2.el should define: +# local variable `dir-locals-loaded' +# local variable `dir-locals-2-loaded' diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el index 9f17747da1f..91ca557204e 100644 --- a/test/lisp/files-tests.el +++ b/test/lisp/files-tests.el @@ -1782,6 +1782,21 @@ set to." ;; Invocation through env, with modified environment. (files-tests--check-shebang "#!/usr/bin/env -S PYTHONPATH=/...:${PYTHONPATH} python" 'python-base-mode)) +(ert-deftest files-test-dir-locals-2-solo () + "Ensure that solo `.dir-locals-2.el' is ignored." + (with-current-buffer + (find-file-noselect (ert-resource-file + (concat "dir-locals-2-solo/dir-locals-2-solo.txt"))) + (should-not (local-variable-p 'dir-locals-2-loaded)))) + +(ert-deftest files-test-dir-locals-2-paired () + "Ensure that `.dir-locals-2.el' is loaded, if paired." + (let ((enable-local-variables :all)) + (with-current-buffer (find-file-noselect + (ert-resource-file (concat "dir-locals-and-2/dir-locals-and-2.txt"))) + (should (local-variable-p 'dir-locals-loaded)) + (should (local-variable-p 'dir-locals-2-loaded))))) + (ert-deftest files-test-dir-locals-auto-mode-alist () "Test an `auto-mode-alist' entry in `.dir-locals.el'" (find-file (ert-resource-file "whatever.quux"))