diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi index 670848c65a1..7be660c85d1 100644 --- a/doc/emacs/custom.texi +++ b/doc/emacs/custom.texi @@ -1299,8 +1299,8 @@ named @file{.dir-locals.el}@footnote{ On MS-DOS, the name of this file should be @file{_dir-locals.el}, due to limitations of the DOS filesystems. If the filesystem is limited to 8+3 file names, the name of the file will be truncated by the OS to @file{_dir-loc.el}. -}@footnote{ You can also use files like @file{.dir-locals2.el}, which -are loaded in addition. This is useful when @file{.dir-locals.el} is +}@footnote{ You can also use @file{.dir-locals-2.el}, which +is loaded in addition. This is useful when @file{.dir-locals.el} is under version control in a shared repository and can't be used for personal customizations. } in a directory. Whenever Emacs visits any file in that directory or any of diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index 42701614365..6c53e9b6cca 100644 --- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi @@ -1765,33 +1765,20 @@ variables: by putting them in a special file, or by defining a @dfn{project class} for that directory. @defvr Constant dir-locals-file -This constant is a wildcard pattern matching the name of files where -Emacs expects to find directory-local variables. Its value is -@file{.dir-locals*.el}@footnote{ -The MS-DOS version of Emacs uses @file{_dir-locals*.el} instead, due to +This constant is the name of the file where Emacs expects to find the +directory-local variables. The name of the file is +@file{.dir-locals.el}@footnote{ +The MS-DOS version of Emacs uses @file{_dir-locals.el} instead, due to limitations of the DOS filesystems. -}, and the most common file name to use is @file{.dir-locals.el}. - -Any file matching this name pattern in a directory causes Emacs to -apply its settings when visiting files in that directory or any of its -subdirectories (optionally, you can exclude subdirectories; see -below). -If some of the subdirectories have their own file matching -@file{.dir-locals*.el}, Emacs uses the settings from the deepest file -it finds starting from the file's directory and moving up the -directory tree. The file specifies local variables as a specially -formatted list; see @ref{Directory Variables, , Per-directory Local -Variables, emacs, The GNU Emacs Manual}, for more details. - -If the same directory contains multiple such files (for instance, -@file{.dir-locals.el} and @file{.dir-locals2.el}), then all of them -are used in @code{string<} order. This means that, if two files -specify different values for the same variable, the file sorted after -will override the value of the previous file (for instance, values in -@file{.dir-locals2.el} override those in @file{.dir-locals.el}). Note -that, because of how lexicographic order works, values in -@file{.dir-locals10.el} are overridden by values in @file{.dir-locals2.el}. -This can be avoided by using @file{.dir-locals02.el} instead. +}. A file by that name in a directory causes Emacs to apply its +settings to any file in that directory or any of its subdirectories +(optionally, you can exclude subdirectories; see below). +If some of the subdirectories have their own @file{.dir-locals.el} +files, Emacs uses the settings from the deepest file it finds starting +from the file's directory and moving up the directory tree. The file +specifies local variables as a specially formatted list; see +@ref{Directory Variables, , Per-directory Local Variables, emacs, The +GNU Emacs Manual}, for more details. @end defvr @defun hack-dir-local-variables diff --git a/etc/NEWS b/etc/NEWS index 7c4824c7a0d..09bced4b000 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -179,9 +179,8 @@ by default, and must be enabled by using the `--with-modules' option at configure time. +++ -** Any file of the form .dir-locals*.el is now considered a dir-local -file, and multiple such files can be used in the same directory. See -the variable `dir-locals-file' for more information. +** A second dir-local file (.dir-locals-2.el) is now accepted. +See the variable `dir-locals-file-2' for more information. +++ ** Network security (TLS/SSL certificate validity and the like) is diff --git a/lisp/files.el b/lisp/files.el index 91558aa52c4..92ae4344e1c 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -3713,37 +3713,43 @@ VARIABLES list of the class. The list is processed in order. applied by recursively following these rules." (setf (alist-get class dir-locals-class-alist) variables)) -(defconst dir-locals-file ".dir-locals" - "Pattern for files that contain directory-local variables. +(defconst dir-locals-file ".dir-locals.el" + "File that contains directory-local variables. It has to be constant to enforce uniform values across different environments and users. - -Multiple dir-locals files in the same directory are loaded in -`string<' order. +See also `dir-locals-file-2', whose values override this one's. See Info node `(elisp)Directory Local Variables' for details.") -(defun dir-locals--all-files (file-or-dir) - "Return a list of all readable dir-locals files matching FILE-OR-DIR. -If FILE-OR-DIR is a file pattern, expand wildcards in it and -return a sorted list of the results. If it is a directory name, -return a sorted list of all files matching `dir-locals-file' in -this directory. -The returned list is sorted by `string<' order." - (require 'seq) - (let ((dir (if (file-directory-p file-or-dir) - file-or-dir - (or (file-name-directory file-or-dir) - default-directory))) - (file (cond ((not (file-directory-p file-or-dir)) (file-name-nondirectory file-or-dir)) - ((eq system-type 'ms-dos) (dosified-file-name dir-locals-file)) - (t dir-locals-file)))) - (seq-filter (lambda (f) (and (file-readable-p f) - (file-regular-p f) - (not (file-directory-p f)))) - (mapcar (lambda (f) (expand-file-name f dir)) - (nreverse - (let ((completion-regexp-list '("\\.el\\'"))) - (file-name-all-completions file dir))))))) +(defconst dir-locals-file-2 ".dir-locals-2.el" + "File that contains directory-local variables. +This essentially a second file that can be used like +`dir-locals-file', so that users can have specify their personal +dir-local variables even if the current directory already has a +`dir-locals-file' that is shared with other users (such as in a +git repository). +See Info node `(elisp)Directory Local Variables' for details.") + +(defun dir-locals--all-files (directory) + "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)) + (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)) + (when (and f + (file-readable-p f) + (file-regular-p f) + (not (file-directory-p f))) + (push f out))) + out))) (defun dir-locals-find-file (file) "Find the directory-local variables for FILE.