From 2b8ac025af5794d65cfe47d37f164a7f278dfc66 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Thu, 31 Jul 2008 01:22:54 +0000 Subject: [PATCH] (normal-mode): Move call to hack-project-variables into hack-local-variables. (file-local-variables-alist, before-hack-local-variables-hook): New vars. (ignored-local-variables): Add file-local-variables-alist. (hack-local-variables-filter): Renamed from hack-local-variables-apply. Add the result to file-local-variables-alist, without applying them. (hack-local-variables): Set file-local-variables-alist to nil. Call hack-project-variables and before-hack-local-variables-hook. Apply variables here, instead of hack-local-variables-apply. Based on a patch by Alan Mackenzie. --- lisp/files.el | 111 +++++++++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 41 deletions(-) diff --git a/lisp/files.el b/lisp/files.el index 06d00446eb2..a26e5cb83cd 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -1984,8 +1984,6 @@ in that case, this function acts as if `enable-local-variables' were t." (let ((enable-local-variables (or (not find-file) enable-local-variables))) (report-errors "File mode specification error: %s" (set-auto-mode)) - (report-errors "Project local-variables error: %s" - (hack-project-variables)) (report-errors "File local-variables error: %s" (hack-local-variables))) ;; Turn font lock off and on, to make sure it takes account of @@ -2521,7 +2519,8 @@ Otherwise, return nil; point may be changed." ;;; Handling file local variables (defvar ignored-local-variables - '(ignored-local-variables safe-local-variable-values) + '(ignored-local-variables safe-local-variable-values + file-local-variables-alist) "Variables to be ignored in a file's local variable spec.") (defvar hack-local-variables-hook nil @@ -2636,13 +2635,31 @@ asking you for confirmation." (put 'c-set-style 'safe-local-eval-function t) +(defvar file-local-variables-alist nil + "Alist of file-local variable settings in the current buffer. +Each element in this list has the form (VAR . VALUE), where VAR +is a file-local variable (a symbol) and VALUE is the value +specified. The actual value in the buffer may differ from VALUE, +if it is changed by the major or minor modes, or by the user.") +(make-variable-buffer-local 'file-local-variables-alist) + +(defvar before-hack-local-variables-hook nil + "Normal hook run before setting file-local variables. +It is called after checking for unsafe/risky variables and +setting `file-local-variables-alist', and before applying the +variables stored in `file-local-variables-alist'. A hook +function is allowed to change the contents of this alist. + +This hook is called only if there is at least one file-local +variable to set.") + (defun hack-local-variables-confirm (all-vars unsafe-vars risky-vars project) "Get confirmation before setting up local variable values. ALL-VARS is the list of all variables to be set up. UNSAFE-VARS is the list of those that aren't marked as safe or risky. RISKY-VARS is the list of those that are marked as risky. PROJECT is a directory name if these settings come from directory-local -settings; nil otherwise." +settings, or nil otherwise." (if noninteractive nil (let ((name (if buffer-file-name @@ -2787,20 +2804,27 @@ and VAL is the specified value." mode-specified result)))) -(defun hack-local-variables-apply (result project) - "Apply an alist of local variable settings. -RESULT is the alist. -Will query the user when necessary." +(defun hack-local-variables-filter (variables project) + "Filter local variable settings, querying the user if necessary. +VARIABLES is the alist of variable-value settings. This alist is + filtered based on the values of `ignored-local-variables', + `enable-local-eval', `enable-local-variables', and (if necessary) + user interaction. The results are added to + `file-local-variables-alist', without applying them. +PROJECT is a directory name if these settings come from + directory-local settings, or nil otherwise." + ;; Strip any variables that are in `ignored-local-variables'. (dolist (ignored ignored-local-variables) - (setq result (assq-delete-all ignored result))) + (setq variables (assq-delete-all ignored variables))) + ;; If `enable-local-eval' is nil, strip eval "variables". (if (null enable-local-eval) - (setq result (assq-delete-all 'eval result))) - (when result - (setq result (nreverse result)) + (setq variables (assq-delete-all 'eval variables))) + (setq variables (nreverse variables)) + (when variables ;; Find those variables that we may want to save to ;; `safe-local-variable-values'. (let (risky-vars unsafe-vars) - (dolist (elt result) + (dolist (elt variables) (let ((var (car elt)) (val (cdr elt))) ;; Don't query about the fake variables. @@ -2814,22 +2838,21 @@ Will query the user when necessary." (push elt risky-vars)) (push elt unsafe-vars)))) (if (eq enable-local-variables :safe) - ;; If caller wants only the safe variables, - ;; install only them. - (dolist (elt result) + ;; If caller wants only safe variables, store only these. + (dolist (elt variables) (unless (or (member elt unsafe-vars) (member elt risky-vars)) - (hack-one-local-variable (car elt) (cdr elt)))) - ;; Query, except in the case where all are known safe - ;; if the user wants no query in that case. + (push elt file-local-variables-alist))) + ;; Query, unless all are known safe or the user wants no + ;; querying. (if (or (and (eq enable-local-variables t) (null unsafe-vars) (null risky-vars)) (eq enable-local-variables :all) (hack-local-variables-confirm - result unsafe-vars risky-vars project)) - (dolist (elt result) - (hack-one-local-variable (car elt) (cdr elt)))))))) + variables unsafe-vars risky-vars project)) + (dolist (elt variables) + (push elt file-local-variables-alist))))))) (defun hack-local-variables (&optional mode-only) "Parse and put into effect this buffer's local variables spec. @@ -2838,6 +2861,10 @@ is specified, returning t if it is specified." (let ((enable-local-variables (and local-enable-local-variables enable-local-variables)) result) + (unless mode-only + (setq file-local-variables-alist nil) + (report-errors "Project local-variables error: %s" + (hack-project-variables))) (when (or mode-only enable-local-variables) (setq result (hack-local-variables-prop-line mode-only)) ;; Look for "Local variables:" line in last page. @@ -2918,15 +2945,20 @@ is specified, returning t if it is specified." (indirect-variable var)) val) result) (error nil))))) - (forward-line 1))))))) - - ;; We've read all the local variables. Now, return whether the - ;; mode is specified (if MODE-ONLY is non-nil), or set the - ;; variables (if MODE-ONLY is nil.) - (if mode-only - result - (hack-local-variables-apply result nil) - (run-hooks 'hack-local-variables-hook))))) + (forward-line 1)))))))) + ;; Now we've read all the local variables. + ;; If MODE-ONLY is non-nil, return whether the mode was specified. + (cond (mode-only result) + ;; Otherwise, set the variables. + (enable-local-variables + (hack-local-variables-filter result nil) + (when file-local-variables-alist + (setq file-local-variables-alist + (nreverse file-local-variables-alist)) + (run-hooks 'before-hack-local-variables-hook) + (dolist (elt file-local-variables-alist) + (hack-one-local-variable (car elt) (cdr elt)))) + (run-hooks 'hack-local-variables-hook))))) (defun safe-local-variable-p (sym val) "Non-nil if SYM is safe as a file-local variable with value VAL. @@ -3168,8 +3200,12 @@ is found. Returns the new class name." (declare-function c-postprocess-file-styles "cc-mode" ()) (defun hack-project-variables () - "Set local variables in a buffer based on project settings." - (when (and (buffer-file-name) (not (file-remote-p (buffer-file-name)))) + "Read local variables for the current buffer based on project settings. +Store the project variables in `file-local-variables-alist', +without applying them." + (when (and enable-local-variables + (buffer-file-name) + (not (file-remote-p (buffer-file-name)))) ;; Find the settings file. (let ((settings (project-find-settings-file (buffer-file-name))) (class nil) @@ -3186,14 +3222,7 @@ is found. Returns the new class name." (project-collect-binding-list (project-get-alist class) root-dir nil))) (when bindings - (hack-local-variables-apply bindings root-dir) - ;; Special case C and derived modes. Note that CC-based - ;; modes don't work with derived-mode-p. In general I - ;; think modes could use an auxiliary method which is - ;; called after local variables are hacked. - (and (boundp 'c-buffer-is-cc-mode) - c-buffer-is-cc-mode - (c-postprocess-file-styles)))))))) + (hack-local-variables-filter bindings root-dir))))))) (defcustom change-major-mode-with-file-name t -- 2.39.2