diff options
Diffstat (limited to 'lisp/files.el')
| -rw-r--r-- | lisp/files.el | 76 |
1 files changed, 60 insertions, 16 deletions
diff --git a/lisp/files.el b/lisp/files.el index 210cd0fa7ad..a36ac6b1318 100644 --- a/lisp/files.el +++ b/lisp/files.el | |||
| @@ -3494,6 +3494,8 @@ we don't actually set it to the same mode the buffer already has." | |||
| 3494 | ;; Check for auto-mode-alist entry in dir-locals. | 3494 | ;; Check for auto-mode-alist entry in dir-locals. |
| 3495 | (with-demoted-errors "Directory-local variables error: %s" | 3495 | (with-demoted-errors "Directory-local variables error: %s" |
| 3496 | ;; Note this is a no-op if enable-local-variables is nil. | 3496 | ;; Note this is a no-op if enable-local-variables is nil. |
| 3497 | ;; We don't use `hack-dir-local-get-variables-functions' here, because | ||
| 3498 | ;; modes are specific to Emacs. | ||
| 3497 | (let* ((mode-alist (cdr (hack-dir-local--get-variables | 3499 | (let* ((mode-alist (cdr (hack-dir-local--get-variables |
| 3498 | (lambda (key) (eq key 'auto-mode-alist)))))) | 3500 | (lambda (key) (eq key 'auto-mode-alist)))))) |
| 3499 | (set-auto-mode--apply-alist mode-alist keep-mode-if-same t))) | 3501 | (set-auto-mode--apply-alist mode-alist keep-mode-if-same t))) |
| @@ -4769,7 +4771,7 @@ Return the new class name, which is a symbol named DIR." | |||
| 4769 | 4771 | ||
| 4770 | (defvar hack-dir-local-variables--warned-coding nil) | 4772 | (defvar hack-dir-local-variables--warned-coding nil) |
| 4771 | 4773 | ||
| 4772 | (defun hack-dir-local--get-variables (predicate) | 4774 | (defun hack-dir-local--get-variables (&optional predicate) |
| 4773 | "Read per-directory local variables for the current buffer. | 4775 | "Read per-directory local variables for the current buffer. |
| 4774 | Return a cons of the form (DIR . ALIST), where DIR is the | 4776 | Return a cons of the form (DIR . ALIST), where DIR is the |
| 4775 | directory name (maybe nil) and ALIST is an alist of all variables | 4777 | directory name (maybe nil) and ALIST is an alist of all variables |
| @@ -4799,6 +4801,16 @@ PREDICATE is passed to `dir-locals-collect-variables'." | |||
| 4799 | (dir-locals-get-class-variables class) | 4801 | (dir-locals-get-class-variables class) |
| 4800 | dir-name nil predicate)))))) | 4802 | dir-name nil predicate)))))) |
| 4801 | 4803 | ||
| 4804 | (defvar hack-dir-local-get-variables-functions | ||
| 4805 | (list #'hack-dir-local--get-variables) | ||
| 4806 | "Special hook to compute the set of dir-local variables. | ||
| 4807 | Every function is called without arguments and should return either | ||
| 4808 | a cons of the form (DIR . ALIST) or a (possibly empty) list of such conses, | ||
| 4809 | where ALIST is an alist of (VAR . VAL) settings. | ||
| 4810 | DIR should be a string (a directory name) and is used to obey | ||
| 4811 | `safe-local-variable-directories'. | ||
| 4812 | This hook is run after the major mode has been setup.") | ||
| 4813 | |||
| 4802 | (defun hack-dir-local-variables () | 4814 | (defun hack-dir-local-variables () |
| 4803 | "Read per-directory local variables for the current buffer. | 4815 | "Read per-directory local variables for the current buffer. |
| 4804 | Store the directory-local variables in `dir-local-variables-alist' | 4816 | Store the directory-local variables in `dir-local-variables-alist' |
| @@ -4806,21 +4818,53 @@ and `file-local-variables-alist', without applying them. | |||
| 4806 | 4818 | ||
| 4807 | This does nothing if either `enable-local-variables' or | 4819 | This does nothing if either `enable-local-variables' or |
| 4808 | `enable-dir-local-variables' are nil." | 4820 | `enable-dir-local-variables' are nil." |
| 4809 | (let* ((items (hack-dir-local--get-variables nil)) | 4821 | (let (items) |
| 4810 | (dir-name (car items)) | 4822 | (when (and enable-local-variables |
| 4811 | (variables (cdr items))) | 4823 | enable-dir-local-variables |
| 4812 | (when variables | 4824 | (or enable-remote-dir-locals |
| 4813 | (dolist (elt variables) | 4825 | (not (file-remote-p (or (buffer-file-name) |
| 4814 | (if (eq (car elt) 'coding) | 4826 | default-directory))))) |
| 4815 | (unless hack-dir-local-variables--warned-coding | 4827 | (run-hook-wrapped 'hack-dir-local-get-variables-functions |
| 4816 | (setq hack-dir-local-variables--warned-coding t) | 4828 | (lambda (fun) |
| 4817 | (display-warning 'files | 4829 | (let ((res (funcall fun))) |
| 4818 | "Coding cannot be specified by dir-locals")) | 4830 | (cond |
| 4819 | (unless (memq (car elt) '(eval mode)) | 4831 | ((null res)) |
| 4820 | (setq dir-local-variables-alist | 4832 | ((consp (car-safe res)) |
| 4821 | (assq-delete-all (car elt) dir-local-variables-alist))) | 4833 | (setq items (append res items))) |
| 4822 | (push elt dir-local-variables-alist))) | 4834 | (t (push res items))))))) |
| 4823 | (hack-local-variables-filter variables dir-name)))) | 4835 | ;; Sort the entries from nearest dir to furthest dir. |
| 4836 | (setq items (sort (nreverse items) | ||
| 4837 | :key (lambda (x) (length (car-safe x))) :reverse t)) | ||
| 4838 | ;; Filter out duplicates, preferring the settings from the nearest dir | ||
| 4839 | ;; and from the first hook function. | ||
| 4840 | (let ((seen nil)) | ||
| 4841 | (dolist (item items) | ||
| 4842 | (when seen ;; Special case seen=nil since it's the most common case. | ||
| 4843 | (setcdr item (seq-filter (lambda (vv) (not (memq (car-safe vv) seen))) | ||
| 4844 | (cdr item)))) | ||
| 4845 | (setq seen (nconc (seq-difference (mapcar #'car (cdr item)) | ||
| 4846 | '(eval mode)) | ||
| 4847 | seen)))) | ||
| 4848 | ;; Rather than a loop, maybe we should handle all the dirs | ||
| 4849 | ;; "together", e.g. prompting the user only once. But if so, we'd | ||
| 4850 | ;; probably want to also merge the prompt for file-local vars, | ||
| 4851 | ;; which comes from the call to `hack-local-variables-filter' in | ||
| 4852 | ;; `hack-local-variables'. | ||
| 4853 | (dolist (item items) | ||
| 4854 | (let ((dir-name (car items)) | ||
| 4855 | (variables (cdr items))) | ||
| 4856 | (when variables | ||
| 4857 | (dolist (elt variables) | ||
| 4858 | (if (eq (car elt) 'coding) | ||
| 4859 | (unless hack-dir-local-variables--warned-coding | ||
| 4860 | (setq hack-dir-local-variables--warned-coding t) | ||
| 4861 | (display-warning 'files | ||
| 4862 | "Coding cannot be specified by dir-locals")) | ||
| 4863 | (unless (memq (car elt) '(eval mode)) | ||
| 4864 | (setq dir-local-variables-alist | ||
| 4865 | (assq-delete-all (car elt) dir-local-variables-alist))) | ||
| 4866 | (push elt dir-local-variables-alist))) | ||
| 4867 | (hack-local-variables-filter variables dir-name)))))) | ||
| 4824 | 4868 | ||
| 4825 | (defun hack-dir-local-variables-non-file-buffer () | 4869 | (defun hack-dir-local-variables-non-file-buffer () |
| 4826 | "Apply directory-local variables to a non-file buffer. | 4870 | "Apply directory-local variables to a non-file buffer. |