aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtur Malabarba2015-11-07 13:54:56 +0000
committerArtur Malabarba2015-11-10 13:04:31 +0000
commit2e8488858c7b8df40610c1cd3038348fdc9bf3ed (patch)
tree071562f68f773d55bd40a4f861a0d90c5f4c9ddf
parentcbaa04014e0c9efdfc6393bccde0e6579b5d7051 (diff)
downloademacs-2e8488858c7b8df40610c1cd3038348fdc9bf3ed.tar.gz
emacs-2e8488858c7b8df40610c1cd3038348fdc9bf3ed.zip
* lisp/files.el (dir-locals-file): Allow wildcards
(dir-locals-find-file, dir-locals-collect-variables) (dir-locals-read-from-file): Update accordingly. (hack-dir-local-variables): Rename a local variable. * lisp/files-x.el (modify-dir-local-variable): Update accordingly * lisp/help-fns.el (describe-variable): Update accordingly * .gitignore: Add .dir-locals?.el
-rw-r--r--.gitignore1
-rw-r--r--lisp/files-x.el29
-rw-r--r--lisp/files.el172
-rw-r--r--lisp/help-fns.el43
4 files changed, 154 insertions, 91 deletions
diff --git a/.gitignore b/.gitignore
index 7f023b70254..fda50e9df77 100644
--- a/.gitignore
+++ b/.gitignore
@@ -255,6 +255,7 @@ gnustmp*
255ChangeLog 255ChangeLog
256[0-9]*.patch 256[0-9]*.patch
257[0-9]*.txt 257[0-9]*.txt
258.dir-locals?.el
258/vc-dwim-log-* 259/vc-dwim-log-*
259 260
260# Built by 'make install'. 261# Built by 'make install'.
diff --git a/lisp/files-x.el b/lisp/files-x.el
index a130ffcf928..cf9fe914ed4 100644
--- a/lisp/files-x.el
+++ b/lisp/files-x.el
@@ -429,18 +429,25 @@ from the MODE alist ignoring the input argument VALUE."
429 (catch 'exit 429 (catch 'exit
430 (unless enable-local-variables 430 (unless enable-local-variables
431 (throw 'exit (message "Directory-local variables are disabled"))) 431 (throw 'exit (message "Directory-local variables are disabled")))
432 (let ((variables-file (or (and (buffer-file-name) 432 (let ((variables-file (and (buffer-file-name)
433 (not (file-remote-p (buffer-file-name))) 433 (not (file-remote-p (buffer-file-name)))
434 (dir-locals-find-file (buffer-file-name))) 434 (dir-locals-find-file (buffer-file-name))))
435 dir-locals-file))
436 variables) 435 variables)
437 (if (consp variables-file) ; result from cache 436 (setq variables-file
438 ;; If cache element has an mtime, assume it came from a file. 437 ;; If there are several .dir-locals, the user probably
439 ;; Otherwise, assume it was set directly. 438 ;; wants to edit the last one (the highest priority).
440 (setq variables-file (if (nth 2 variables-file) 439 (cond ((stringp variables-file)
441 (expand-file-name dir-locals-file 440 (car (last (dir-locals--all-files variables-file))))
442 (car variables-file)) 441 ((consp variables-file) ; result from cache
443 (cadr variables-file)))) 442 ;; If cache element has an mtime, assume it came from a file.
443 ;; Otherwise, assume it was set directly.
444 (if (nth 2 variables-file)
445 (car (last (dir-locals--all-files (car variables-file))))
446 (cadr variables-file)))
447 ;; Try to make a proper file-name. This doesn't cover all
448 ;; wildcards, but it covers the default value of `dir-locals-file'.
449 (t (replace-regexp-in-string
450 "\\*" "" (replace-regexp-in-string "\\?" "-" dir-locals-file)))))
444 ;; I can't be bothered to handle this case right now. 451 ;; I can't be bothered to handle this case right now.
445 ;; Dir locals were set directly from a class. You need to 452 ;; Dir locals were set directly from a class. You need to
446 ;; directly modify the class in dir-locals-class-alist. 453 ;; directly modify the class in dir-locals-class-alist.
diff --git a/lisp/files.el b/lisp/files.el
index 9de9ac09f48..e8ee9490d33 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -3648,7 +3648,7 @@ Return the new variables list."
3648 (error 3648 (error
3649 ;; The file's content might be invalid (e.g. have a merge conflict), but 3649 ;; The file's content might be invalid (e.g. have a merge conflict), but
3650 ;; that shouldn't prevent the user from opening the file. 3650 ;; that shouldn't prevent the user from opening the file.
3651 (message ".dir-locals error: %s" (error-message-string err)) 3651 (message "%s error: %s" dir-locals-file (error-message-string err))
3652 nil)))) 3652 nil))))
3653 3653
3654(defun dir-locals-set-directory-class (directory class &optional mtime) 3654(defun dir-locals-set-directory-class (directory class &optional mtime)
@@ -3698,11 +3698,38 @@ VARIABLES list of the class. The list is processed in order.
3698 applied by recursively following these rules." 3698 applied by recursively following these rules."
3699 (setf (alist-get class dir-locals-class-alist) variables)) 3699 (setf (alist-get class dir-locals-class-alist) variables))
3700 3700
3701(defconst dir-locals-file ".dir-locals.el" 3701(defconst dir-locals-file ".dir-locals*.el"
3702 "File that contains directory-local variables. 3702 "File that contains directory-local variables.
3703It has to be constant to enforce uniform values 3703It has to be constant to enforce uniform values
3704across different environments and users.") 3704across different environments and users.")
3705 3705
3706(defcustom dir-locals-sort-predicate #'string<
3707 "Predicate used to sort dir-locals files before loading them.
3708The function should take two arguments (file names) and return
3709non-nil if the first argument should be loaded first (which means
3710the values in the second file will override those in the first)."
3711 :group 'files
3712 :type 'function)
3713
3714(defun dir-locals--all-files (file-or-dir)
3715 "Return a list of all readable dir-locals files matching FILE-OR-DIR.
3716If FILE-OR-DIR is a file pattern, expand wildcards in it and
3717return a sorted list of the results. If it is a directory name,
3718return a sorted list of all files matching `dir-locals-file' in
3719this directory."
3720 (require 'seq)
3721 (let ((default-directory (if (file-directory-p file-or-dir)
3722 file-or-dir
3723 default-directory)))
3724 (sort (seq-filter (lambda (f) (and (file-readable-p f)
3725 (file-regular-p f)))
3726 (file-expand-wildcards
3727 (cond ((not (file-directory-p file-or-dir)) file-or-dir)
3728 ((eq system-type 'ms-dos) (dosified-file-name dir-locals-file))
3729 (t dir-locals-file))
3730 'full))
3731 dir-locals-sort-predicate)))
3732
3706(defun dir-locals-find-file (file) 3733(defun dir-locals-find-file (file)
3707 "Find the directory-local variables for FILE. 3734 "Find the directory-local variables for FILE.
3708This searches upward in the directory tree from FILE. 3735This searches upward in the directory tree from FILE.
@@ -3719,75 +3746,96 @@ If not, the cache entry is cleared so that the file will be re-read.
3719This function returns either nil (no directory local variables found), 3746This function returns either nil (no directory local variables found),
3720or the matching entry from `dir-locals-directory-cache' (a list), 3747or the matching entry from `dir-locals-directory-cache' (a list),
3721or the full path to the `dir-locals-file' (a string) in the case 3748or the full path to the `dir-locals-file' (a string) in the case
3722of no valid cache entry." 3749of no valid cache entry. If `dir-locals-file' contains
3750wildcards, then the return value is not a proper filename, it is
3751an absolute version of `dir-locals-file' which is guaranteed to
3752expand to at least one file."
3723 (setq file (expand-file-name file)) 3753 (setq file (expand-file-name file))
3724 (let* ((dir-locals-file-name 3754 (let* ((dir-locals-file-name (if (eq system-type 'ms-dos)
3725 (if (eq system-type 'ms-dos) 3755 (dosified-file-name dir-locals-file)
3726 (dosified-file-name dir-locals-file) 3756 dir-locals-file))
3727 dir-locals-file)) 3757 (locals-dir (locate-dominating-file
3728 (locals-file (locate-dominating-file file dir-locals-file-name)) 3758 (file-name-directory file)
3729 (dir-elt nil)) 3759 (lambda (dir)
3760 (let ((default-directory dir))
3761 (file-expand-wildcards dir-locals-file-name 'full)))))
3762 locals-file dir-elt)
3730 ;; `locate-dominating-file' may have abbreviated the name. 3763 ;; `locate-dominating-file' may have abbreviated the name.
3731 (and locals-file 3764 (when locals-dir
3732 (setq locals-file (expand-file-name dir-locals-file-name locals-file))) 3765 (setq locals-dir (expand-file-name locals-dir))
3733 ;; Let dir-locals-read-from-file inform us via demoted-errors 3766 (setq locals-file (expand-file-name dir-locals-file-name locals-dir)))
3734 ;; about unreadable files, etc. 3767 ;; Let dir-locals-read-from-file inform us via demoted-errors
3735 ;; Maybe we'd want to keep searching though - that is 3768 ;; about unreadable files, etc.
3736 ;; a locate-dominating-file issue. 3769 ;; Maybe we'd want to keep searching though - that is
3770 ;; a locate-dominating-file issue.
3737;;; (or (not (file-readable-p locals-file)) 3771;;; (or (not (file-readable-p locals-file))
3738;;; (not (file-regular-p locals-file))) 3772;;; (not (file-regular-p locals-file)))
3739;;; (setq locals-file nil)) 3773;;; (setq locals-file nil))
3740 ;; Find the best cached value in `dir-locals-directory-cache'. 3774 ;; Find the best cached value in `dir-locals-directory-cache'.
3741 (dolist (elt dir-locals-directory-cache) 3775 (dolist (elt dir-locals-directory-cache)
3742 (when (and (string-prefix-p (car elt) file 3776 (when (and (string-prefix-p (car elt) file
3743 (memq system-type 3777 (memq system-type
3744 '(windows-nt cygwin ms-dos))) 3778 '(windows-nt cygwin ms-dos)))
3745 (> (length (car elt)) (length (car dir-elt)))) 3779 (> (length (car elt)) (length (car dir-elt))))
3746 (setq dir-elt elt))) 3780 (setq dir-elt elt)))
3747 (if (and dir-elt 3781 (if (and dir-elt
3748 (or (null locals-file) 3782 (or (null locals-dir)
3749 (<= (length (file-name-directory locals-file)) 3783 (<= (length locals-dir)
3750 (length (car dir-elt))))) 3784 (length (car dir-elt)))))
3751 ;; Found a potential cache entry. Check validity. 3785 ;; Found a potential cache entry. Check validity.
3752 ;; A cache entry with no MTIME is assumed to always be valid 3786 ;; A cache entry with no MTIME is assumed to always be valid
3753 ;; (ie, set directly, not from a dir-locals file). 3787 ;; (ie, set directly, not from a dir-locals file).
3754 ;; Note, we don't bother to check that there is a matching class 3788 ;; Note, we don't bother to check that there is a matching class
3755 ;; element in dir-locals-class-alist, since that's done by 3789 ;; element in dir-locals-class-alist, since that's done by
3756 ;; dir-locals-set-directory-class. 3790 ;; dir-locals-set-directory-class.
3757 (if (or (null (nth 2 dir-elt)) 3791 (if (or (null (nth 2 dir-elt))
3758 (let ((cached-file (expand-file-name dir-locals-file-name 3792 (let ((cached-files (dir-locals--all-files (car dir-elt))))
3759 (car dir-elt)))) 3793 ;; The entry MTIME should match the most recent
3760 (and (file-readable-p cached-file) 3794 ;; MTIME among matching files.
3761 (equal (nth 2 dir-elt) 3795 (and cached-files
3762 (nth 5 (file-attributes cached-file)))))) 3796 (= (time-to-seconds (nth 2 dir-elt))
3763 ;; This cache entry is OK. 3797 (apply #'max (mapcar (lambda (f) (time-to-seconds (nth 5 (file-attributes f))))
3764 dir-elt 3798 cached-files))))))
3765 ;; This cache entry is invalid; clear it. 3799 ;; This cache entry is OK.
3766 (setq dir-locals-directory-cache 3800 dir-elt
3767 (delq dir-elt dir-locals-directory-cache)) 3801 ;; This cache entry is invalid; clear it.
3768 ;; Return the first existing dir-locals file. Might be the same 3802 (setq dir-locals-directory-cache
3769 ;; as dir-elt's, might not (eg latter might have been deleted). 3803 (delq dir-elt dir-locals-directory-cache))
3770 locals-file) 3804 ;; Return the first existing dir-locals file. Might be the same
3805 ;; as dir-elt's, might not (eg latter might have been deleted).
3806 locals-file)
3771 ;; No cache entry. 3807 ;; No cache entry.
3772 locals-file))) 3808 locals-file)))
3773 3809
3774(defun dir-locals-read-from-file (file) 3810(defun dir-locals-read-from-file (file)
3775 "Load a variables FILE and register a new class and instance. 3811 "Load a variables FILE and register a new class and instance.
3776FILE is the name of the file holding the variables to apply. 3812FILE is the absolute name of the file holding the variables to
3813apply. It may contain wildcards.
3777The new class name is the same as the directory in which FILE 3814The new class name is the same as the directory in which FILE
3778is found. Returns the new class name." 3815is found. Returns the new class name."
3779 (with-temp-buffer 3816 (require 'map)
3817 (let* ((dir-name (file-name-directory file))
3818 (class-name (intern dir-name))
3819 (files (dir-locals--all-files file))
3820 (read-circle nil)
3821 (variables))
3780 (with-demoted-errors "Error reading dir-locals: %S" 3822 (with-demoted-errors "Error reading dir-locals: %S"
3781 (insert-file-contents file) 3823 (dolist (file files)
3782 (unless (zerop (buffer-size)) 3824 (with-temp-buffer
3783 (let* ((dir-name (file-name-directory file)) 3825 (insert-file-contents file)
3784 (class-name (intern dir-name)) 3826 (condition-case-unless-debug nil
3785 (variables (let ((read-circle nil)) 3827 (setq variables
3786 (read (current-buffer))))) 3828 (map-merge-with 'list (lambda (a b) (map-merge 'list a b))
3787 (dir-locals-set-class-variables class-name variables) 3829 variables
3788 (dir-locals-set-directory-class dir-name class-name 3830 (read (current-buffer))))
3789 (nth 5 (file-attributes file))) 3831 (end-of-file nil)))))
3790 class-name))))) 3832 (dir-locals-set-class-variables class-name variables)
3833 (dir-locals-set-directory-class
3834 dir-name class-name
3835 (seconds-to-time (apply #'max (mapcar (lambda (file)
3836 (time-to-seconds (nth 5 (file-attributes file))))
3837 files))))
3838 class-name))
3791 3839
3792(defcustom enable-remote-dir-locals nil 3840(defcustom enable-remote-dir-locals nil
3793 "Non-nil means dir-local variables will be applied to remote files." 3841 "Non-nil means dir-local variables will be applied to remote files."
@@ -3810,17 +3858,17 @@ This does nothing if either `enable-local-variables' or
3810 (not (file-remote-p (or (buffer-file-name) 3858 (not (file-remote-p (or (buffer-file-name)
3811 default-directory))))) 3859 default-directory)))))
3812 ;; Find the variables file. 3860 ;; Find the variables file.
3813 (let ((variables-file (dir-locals-find-file 3861 (let ((file-pattern-or-cache (dir-locals-find-file
3814 (or (buffer-file-name) default-directory))) 3862 (or (buffer-file-name) default-directory)))
3815 (class nil) 3863 (class nil)
3816 (dir-name nil)) 3864 (dir-name nil))
3817 (cond 3865 (cond
3818 ((stringp variables-file) 3866 ((stringp file-pattern-or-cache)
3819 (setq dir-name (file-name-directory variables-file) 3867 (setq dir-name (file-name-directory file-pattern-or-cache)
3820 class (dir-locals-read-from-file variables-file))) 3868 class (dir-locals-read-from-file file-pattern-or-cache)))
3821 ((consp variables-file) 3869 ((consp file-pattern-or-cache)
3822 (setq dir-name (nth 0 variables-file)) 3870 (setq dir-name (nth 0 file-pattern-or-cache))
3823 (setq class (nth 1 variables-file)))) 3871 (setq class (nth 1 file-pattern-or-cache))))
3824 (when class 3872 (when class
3825 (let ((variables 3873 (let ((variables
3826 (dir-locals-collect-variables 3874 (dir-locals-collect-variables
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 958a0754946..4e0bfee5bf7 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -907,29 +907,36 @@ if it is given a local binding.\n"))))
907 (buffer-file-name buffer))) 907 (buffer-file-name buffer)))
908 (dir-locals-find-file 908 (dir-locals-find-file
909 (buffer-file-name buffer)))) 909 (buffer-file-name buffer))))
910 (dir-file t)) 910 (is-directory nil))
911 (princ (substitute-command-keys 911 (princ (substitute-command-keys
912 " This variable's value is directory-local")) 912 " This variable's value is directory-local"))
913 (if (null file) 913 (when (consp file) ; result from cache
914 (princ ".\n") 914 ;; If the cache element has an mtime, we
915 (princ ", set ") 915 ;; assume it came from a file.
916 (if (consp file) ; result from cache 916 (if (nth 2 file)
917 ;; If the cache element has an mtime, we 917 (setq file (expand-file-name
918 ;; assume it came from a file. 918 dir-locals-file (car file)))
919 (if (nth 2 file) 919 ;; Otherwise, assume it was set directly.
920 (setq file (expand-file-name 920 (setq file (car file)
921 dir-locals-file (car file))) 921 is-directory t)))
922 ;; Otherwise, assume it was set directly. 922 (if (null file)
923 (setq file (car file) 923 (princ ".\n")
924 dir-file nil))) 924 (princ ", set ")
925 (princ (substitute-command-keys 925 (let ((files (file-expand-wildcards file)))
926 (if dir-file 926 (princ (substitute-command-keys
927 "by the file\n `" 927 (cond
928 "for the directory\n `"))) 928 (is-directory "for the directory\n `")
929 ;; Many files matched.
930 ((cdr files)
931 (setq file (file-name-directory (car files)))
932 (format "by a file\n matching `%s' in the directory\n `"
933 dir-locals-file))
934 (t (setq file (car files))
935 "by the file\n `"))))
929 (with-current-buffer standard-output 936 (with-current-buffer standard-output
930 (insert-text-button 937 (insert-text-button
931 file 'type 'help-dir-local-var-def 938 file 'type 'help-dir-local-var-def
932 'help-args (list variable file))) 939 'help-args (list variable file))))
933 (princ (substitute-command-keys "'.\n")))) 940 (princ (substitute-command-keys "'.\n"))))
934 (princ (substitute-command-keys 941 (princ (substitute-command-keys
935 " This variable's value is file-local.\n")))) 942 " This variable's value is file-local.\n"))))