diff options
| author | Artur Malabarba | 2015-11-07 13:54:56 +0000 |
|---|---|---|
| committer | Artur Malabarba | 2015-11-07 13:55:16 +0000 |
| commit | 3d4fdb9f59731113f467b3705c8346b1ee8d2d81 (patch) | |
| tree | 0a4b971094880b5ea3f48fb275537851b9f9edf6 | |
| parent | 8af7598d9851c067176ced829d8a5902f3afcbc1 (diff) | |
| download | emacs-scratch/dir-local-wildcard.tar.gz emacs-scratch/dir-local-wildcard.zip | |
* lisp/files.el (dir-locals-file): Allow wildcardsscratch/dir-local-wildcard
(dir-locals-find-file, dir-locals-collect-variables)
(dir-locals-read-from-file): Update accordingly.
(hack-dir-local-variables): Rename a local variable.
| -rw-r--r-- | lisp/files-x.el | 27 | ||||
| -rw-r--r-- | lisp/files.el | 141 | ||||
| -rw-r--r-- | lisp/help-fns.el | 43 |
3 files changed, 123 insertions, 88 deletions
diff --git a/lisp/files-x.el b/lisp/files-x.el index a130ffcf928..dcd495db15a 100644 --- a/lisp/files-x.el +++ b/lisp/files-x.el | |||
| @@ -429,18 +429,23 @@ 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 (file-expand-wildcards 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 | (let ((default-directory (car variables-file))) | ||
| 446 | (car (last (file-expand-wildcards dir-locals-file 'full)))) | ||
| 447 | (cadr variables-file))) | ||
| 448 | (t dir-locals-file))) | ||
| 444 | ;; I can't be bothered to handle this case right now. | 449 | ;; I can't be bothered to handle this case right now. |
| 445 | ;; Dir locals were set directly from a class. You need to | 450 | ;; Dir locals were set directly from a class. You need to |
| 446 | ;; directly modify the class in dir-locals-class-alist. | 451 | ;; directly modify the class in dir-locals-class-alist. |
diff --git a/lisp/files.el b/lisp/files.el index 9de9ac09f48..3d6495f30d2 100644 --- a/lisp/files.el +++ b/lisp/files.el | |||
| @@ -28,6 +28,8 @@ | |||
| 28 | 28 | ||
| 29 | ;;; Code: | 29 | ;;; Code: |
| 30 | 30 | ||
| 31 | (require 'map) | ||
| 32 | (require 'seq) | ||
| 31 | (defvar font-lock-keywords) | 33 | (defvar font-lock-keywords) |
| 32 | 34 | ||
| 33 | (defgroup backup nil | 35 | (defgroup backup nil |
| @@ -3648,7 +3650,7 @@ Return the new variables list." | |||
| 3648 | (error | 3650 | (error |
| 3649 | ;; The file's content might be invalid (e.g. have a merge conflict), but | 3651 | ;; 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. | 3652 | ;; that shouldn't prevent the user from opening the file. |
| 3651 | (message ".dir-locals error: %s" (error-message-string err)) | 3653 | (message "%s error: %s" dir-locals-file (error-message-string err)) |
| 3652 | nil)))) | 3654 | nil)))) |
| 3653 | 3655 | ||
| 3654 | (defun dir-locals-set-directory-class (directory class &optional mtime) | 3656 | (defun dir-locals-set-directory-class (directory class &optional mtime) |
| @@ -3698,7 +3700,7 @@ VARIABLES list of the class. The list is processed in order. | |||
| 3698 | applied by recursively following these rules." | 3700 | applied by recursively following these rules." |
| 3699 | (setf (alist-get class dir-locals-class-alist) variables)) | 3701 | (setf (alist-get class dir-locals-class-alist) variables)) |
| 3700 | 3702 | ||
| 3701 | (defconst dir-locals-file ".dir-locals.el" | 3703 | (defconst dir-locals-file ".dir-locals*.el" |
| 3702 | "File that contains directory-local variables. | 3704 | "File that contains directory-local variables. |
| 3703 | It has to be constant to enforce uniform values | 3705 | It has to be constant to enforce uniform values |
| 3704 | across different environments and users.") | 3706 | across different environments and users.") |
| @@ -3719,17 +3721,23 @@ If not, the cache entry is cleared so that the file will be re-read. | |||
| 3719 | This function returns either nil (no directory local variables found), | 3721 | This function returns either nil (no directory local variables found), |
| 3720 | or the matching entry from `dir-locals-directory-cache' (a list), | 3722 | or the matching entry from `dir-locals-directory-cache' (a list), |
| 3721 | or the full path to the `dir-locals-file' (a string) in the case | 3723 | or the full path to the `dir-locals-file' (a string) in the case |
| 3722 | of no valid cache entry." | 3724 | of no valid cache entry. If `dir-locals-file' contains |
| 3723 | (setq file (expand-file-name file)) | 3725 | wildcards, then the return value is not a proper filename, it is |
| 3724 | (let* ((dir-locals-file-name | 3726 | an absolute version of `dir-locals-file' which is guaranteed to |
| 3725 | (if (eq system-type 'ms-dos) | 3727 | expand to at least one file." |
| 3726 | (dosified-file-name dir-locals-file) | 3728 | (setq file (file-name-directory (expand-file-name file))) |
| 3727 | dir-locals-file)) | 3729 | (let* ((dir-locals-file-name (if (eq system-type 'ms-dos) |
| 3728 | (locals-file (locate-dominating-file file dir-locals-file-name)) | 3730 | (dosified-file-name dir-locals-file) |
| 3729 | (dir-elt nil)) | 3731 | dir-locals-file)) |
| 3732 | (locals-dir (locate-dominating-file | ||
| 3733 | file (lambda (dir) | ||
| 3734 | (let ((default-directory dir)) | ||
| 3735 | (file-expand-wildcards dir-locals-file-name 'full))))) | ||
| 3736 | locals-file dir-elt) | ||
| 3730 | ;; `locate-dominating-file' may have abbreviated the name. | 3737 | ;; `locate-dominating-file' may have abbreviated the name. |
| 3731 | (and locals-file | 3738 | (when locals-dir |
| 3732 | (setq locals-file (expand-file-name dir-locals-file-name locals-file))) | 3739 | (setq locals-dir (expand-file-name locals-dir)) |
| 3740 | (setq locals-file (expand-file-name dir-locals-file-name locals-dir))) | ||
| 3733 | ;; Let dir-locals-read-from-file inform us via demoted-errors | 3741 | ;; Let dir-locals-read-from-file inform us via demoted-errors |
| 3734 | ;; about unreadable files, etc. | 3742 | ;; about unreadable files, etc. |
| 3735 | ;; Maybe we'd want to keep searching though - that is | 3743 | ;; Maybe we'd want to keep searching though - that is |
| @@ -3740,54 +3748,69 @@ of no valid cache entry." | |||
| 3740 | ;; Find the best cached value in `dir-locals-directory-cache'. | 3748 | ;; Find the best cached value in `dir-locals-directory-cache'. |
| 3741 | (dolist (elt dir-locals-directory-cache) | 3749 | (dolist (elt dir-locals-directory-cache) |
| 3742 | (when (and (string-prefix-p (car elt) file | 3750 | (when (and (string-prefix-p (car elt) file |
| 3743 | (memq system-type | 3751 | (memq system-type |
| 3744 | '(windows-nt cygwin ms-dos))) | 3752 | '(windows-nt cygwin ms-dos))) |
| 3745 | (> (length (car elt)) (length (car dir-elt)))) | 3753 | (> (length (car elt)) (length (car dir-elt)))) |
| 3746 | (setq dir-elt elt))) | 3754 | (setq dir-elt elt))) |
| 3747 | (if (and dir-elt | 3755 | (if (and dir-elt |
| 3748 | (or (null locals-file) | 3756 | (or (null locals-dir) |
| 3749 | (<= (length (file-name-directory locals-file)) | 3757 | (<= (length locals-dir) |
| 3750 | (length (car dir-elt))))) | 3758 | (length (car dir-elt))))) |
| 3751 | ;; Found a potential cache entry. Check validity. | 3759 | ;; Found a potential cache entry. Check validity. |
| 3752 | ;; A cache entry with no MTIME is assumed to always be valid | 3760 | ;; A cache entry with no MTIME is assumed to always be valid |
| 3753 | ;; (ie, set directly, not from a dir-locals file). | 3761 | ;; (ie, set directly, not from a dir-locals file). |
| 3754 | ;; Note, we don't bother to check that there is a matching class | 3762 | ;; 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 | 3763 | ;; element in dir-locals-class-alist, since that's done by |
| 3756 | ;; dir-locals-set-directory-class. | 3764 | ;; dir-locals-set-directory-class. |
| 3757 | (if (or (null (nth 2 dir-elt)) | 3765 | (if (or (null (nth 2 dir-elt)) |
| 3758 | (let ((cached-file (expand-file-name dir-locals-file-name | 3766 | (let* ((default-directory (car dir-elt)) |
| 3759 | (car dir-elt)))) | 3767 | (cached-files (seq-filter #'file-readable-p |
| 3760 | (and (file-readable-p cached-file) | 3768 | (file-expand-wildcards dir-locals-file)))) |
| 3761 | (equal (nth 2 dir-elt) | 3769 | ;; The entry MTIME should match the most recent |
| 3762 | (nth 5 (file-attributes cached-file)))))) | 3770 | ;; MTIME among matching files. |
| 3763 | ;; This cache entry is OK. | 3771 | (and cached-files |
| 3764 | dir-elt | 3772 | (= (time-to-seconds (nth 2 dir-elt)) |
| 3765 | ;; This cache entry is invalid; clear it. | 3773 | (apply #'max (mapcar (lambda (f) (time-to-seconds (nth 5 (file-attributes f)))) |
| 3766 | (setq dir-locals-directory-cache | 3774 | cached-files)))))) |
| 3767 | (delq dir-elt dir-locals-directory-cache)) | 3775 | ;; This cache entry is OK. |
| 3768 | ;; Return the first existing dir-locals file. Might be the same | 3776 | dir-elt |
| 3769 | ;; as dir-elt's, might not (eg latter might have been deleted). | 3777 | ;; This cache entry is invalid; clear it. |
| 3770 | locals-file) | 3778 | (setq dir-locals-directory-cache |
| 3779 | (delq dir-elt dir-locals-directory-cache)) | ||
| 3780 | ;; Return the first existing dir-locals file. Might be the same | ||
| 3781 | ;; as dir-elt's, might not (eg latter might have been deleted). | ||
| 3782 | locals-file) | ||
| 3771 | ;; No cache entry. | 3783 | ;; No cache entry. |
| 3772 | locals-file))) | 3784 | locals-file))) |
| 3773 | 3785 | ||
| 3774 | (defun dir-locals-read-from-file (file) | 3786 | (defun dir-locals-read-from-file (file) |
| 3775 | "Load a variables FILE and register a new class and instance. | 3787 | "Load a variables FILE and register a new class and instance. |
| 3776 | FILE is the name of the file holding the variables to apply. | 3788 | FILE is the absolute name of the file holding the variables to |
| 3789 | apply. It may contain wildcards. | ||
| 3777 | The new class name is the same as the directory in which FILE | 3790 | The new class name is the same as the directory in which FILE |
| 3778 | is found. Returns the new class name." | 3791 | is found. Returns the new class name." |
| 3779 | (with-temp-buffer | 3792 | (let* ((dir-name (file-name-directory file)) |
| 3793 | (class-name (intern dir-name)) | ||
| 3794 | (files (sort (file-expand-wildcards "/home/artur/Git/emacs/.dir-locals*.el") #'string<)) | ||
| 3795 | (read-circle nil) | ||
| 3796 | (variables)) | ||
| 3780 | (with-demoted-errors "Error reading dir-locals: %S" | 3797 | (with-demoted-errors "Error reading dir-locals: %S" |
| 3781 | (insert-file-contents file) | 3798 | (dolist (file files) |
| 3782 | (unless (zerop (buffer-size)) | 3799 | (with-temp-buffer |
| 3783 | (let* ((dir-name (file-name-directory file)) | 3800 | (insert-file-contents file) |
| 3784 | (class-name (intern dir-name)) | 3801 | (condition-case-unless-debug nil |
| 3785 | (variables (let ((read-circle nil)) | 3802 | (setq variables |
| 3786 | (read (current-buffer))))) | 3803 | (map-merge-with 'list (lambda (a b) (map-merge 'list a b)) |
| 3787 | (dir-locals-set-class-variables class-name variables) | 3804 | variables |
| 3788 | (dir-locals-set-directory-class dir-name class-name | 3805 | (read (current-buffer)))) |
| 3789 | (nth 5 (file-attributes file))) | 3806 | (end-of-file nil))))) |
| 3790 | class-name))))) | 3807 | (dir-locals-set-class-variables class-name variables) |
| 3808 | (dir-locals-set-directory-class | ||
| 3809 | dir-name class-name | ||
| 3810 | (seconds-to-time (apply #'max (mapcar (lambda (file) | ||
| 3811 | (time-to-seconds (nth 5 (file-attributes file)))) | ||
| 3812 | files)))) | ||
| 3813 | class-name)) | ||
| 3791 | 3814 | ||
| 3792 | (defcustom enable-remote-dir-locals nil | 3815 | (defcustom enable-remote-dir-locals nil |
| 3793 | "Non-nil means dir-local variables will be applied to remote files." | 3816 | "Non-nil means dir-local variables will be applied to remote files." |
| @@ -3810,17 +3833,17 @@ This does nothing if either `enable-local-variables' or | |||
| 3810 | (not (file-remote-p (or (buffer-file-name) | 3833 | (not (file-remote-p (or (buffer-file-name) |
| 3811 | default-directory))))) | 3834 | default-directory))))) |
| 3812 | ;; Find the variables file. | 3835 | ;; Find the variables file. |
| 3813 | (let ((variables-file (dir-locals-find-file | 3836 | (let ((file-pattern-or-cache (dir-locals-find-file |
| 3814 | (or (buffer-file-name) default-directory))) | 3837 | (or (buffer-file-name) default-directory))) |
| 3815 | (class nil) | 3838 | (class nil) |
| 3816 | (dir-name nil)) | 3839 | (dir-name nil)) |
| 3817 | (cond | 3840 | (cond |
| 3818 | ((stringp variables-file) | 3841 | ((stringp file-pattern-or-cache) |
| 3819 | (setq dir-name (file-name-directory variables-file) | 3842 | (setq dir-name (file-name-directory file-pattern-or-cache) |
| 3820 | class (dir-locals-read-from-file variables-file))) | 3843 | class (dir-locals-read-from-file file-pattern-or-cache))) |
| 3821 | ((consp variables-file) | 3844 | ((consp file-pattern-or-cache) |
| 3822 | (setq dir-name (nth 0 variables-file)) | 3845 | (setq dir-name (nth 0 file-pattern-or-cache)) |
| 3823 | (setq class (nth 1 variables-file)))) | 3846 | (setq class (nth 1 file-pattern-or-cache)))) |
| 3824 | (when class | 3847 | (when class |
| 3825 | (let ((variables | 3848 | (let ((variables |
| 3826 | (dir-locals-collect-variables | 3849 | (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")))) |