aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorAlan Mackenzie2016-05-05 11:05:49 +0000
committerAlan Mackenzie2016-05-05 11:05:49 +0000
commit25f455815bfaa868dc470d445413df9a7a546c46 (patch)
treeb0c56ba886eda0dfe5b0e200d59051dafd644488 /lisp
parent6aad36ace9953b9672b13be68416d205532d5e59 (diff)
downloademacs-25f455815bfaa868dc470d445413df9a7a546c46.tar.gz
emacs-25f455815bfaa868dc470d445413df9a7a546c46.zip
Call hack-local-variables from major modes rather than from file visiting
This prevents file/directory local variables from being lost when the major mode is set or changed. This fixes bug #15577 and bug #23407. * lisp/files.el (normal-mode): Call `hack-local-variables' when the major mode function hasn't already done so. (hack-local-variables): Rename parameter `mode-only' to `handle-mode', make its previous non-nil setting be t, and introduce the following action for a non-nil non-t value: apply all settings apart from `mode'. * lisp/subr.el (run-mode-hooks): call `hack-local-variables' for buffers which are visiting files. * doc/emacs/custom.texi (File Variables): Note that setting a major mode also sets file variables. (Directory Variables): Note that `mode', `eval', and `unibyte' can be set as dir local variables, but `coding' can't. * doc/lispref/modes.texi (Major Mode Conventions): Say that `run-mode-hooks' also calls `hack-local-variables'. (Auto Major Mode): Say that `find-file' no longer runs `hack-local-variables', as from 25.2. Remove vagueness from `normal-mode' and `set-auto-mode' by saying that the mode IS SET, not merely "selected" or "chosen". (Mode Hooks): Document change to `run-mode-hooks'. * doc/lispref/variables.texi (File Local Variables): Document change to `hack-local-variables'.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/files.el38
-rw-r--r--lisp/subr.el11
2 files changed, 33 insertions, 16 deletions
diff --git a/lisp/files.el b/lisp/files.el
index 132ebced1c0..d89b2f52582 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -2322,8 +2322,12 @@ in that case, this function acts as if `enable-local-variables' were t."
2322 ;; s-a-m and h-l-v may parse the same regions, looking for "mode:". 2322 ;; s-a-m and h-l-v may parse the same regions, looking for "mode:".
2323 (with-demoted-errors "File mode specification error: %s" 2323 (with-demoted-errors "File mode specification error: %s"
2324 (set-auto-mode)) 2324 (set-auto-mode))
2325 (with-demoted-errors "File local-variables error: %s" 2325 ;; `delay-mode-hooks' being non-nil will have prevented the major
2326 (hack-local-variables))) 2326 ;; mode's call to `run-mode-hooks' from calling
2327 ;; `hack-local-variables'. In that case, call it now.
2328 (when delay-mode-hooks
2329 (with-demoted-errors "File local-variables error: %s"
2330 (hack-local-variables 'no-mode))))
2327 ;; Turn font lock off and on, to make sure it takes account of 2331 ;; Turn font lock off and on, to make sure it takes account of
2328 ;; whatever file local variables are relevant to it. 2332 ;; whatever file local variables are relevant to it.
2329 (when (and font-lock-mode 2333 (when (and font-lock-mode
@@ -3297,11 +3301,15 @@ DIR-NAME is the name of the associated directory. Otherwise it is nil."
3297;; TODO? Warn once per file rather than once per session? 3301;; TODO? Warn once per file rather than once per session?
3298(defvar hack-local-variables--warned-lexical nil) 3302(defvar hack-local-variables--warned-lexical nil)
3299 3303
3300(defun hack-local-variables (&optional mode-only) 3304(defun hack-local-variables (&optional handle-mode)
3301 "Parse and put into effect this buffer's local variables spec. 3305 "Parse and put into effect this buffer's local variables spec.
3302Uses `hack-local-variables-apply' to apply the variables. 3306Uses `hack-local-variables-apply' to apply the variables.
3303 3307
3304If MODE-ONLY is non-nil, all we do is check whether a \"mode:\" 3308If HANDLE-MODE is nil, we apply all the specified local
3309variables. If HANDLE-MODE is neither nil nor t, we do the same,
3310except that any settings of `mode' are ignored.
3311
3312If HANDLE-MODE is t, all we do is check whether a \"mode:\"
3305is specified, and return the corresponding mode symbol, or nil. 3313is specified, and return the corresponding mode symbol, or nil.
3306In this case, we try to ignore minor-modes, and only return a 3314In this case, we try to ignore minor-modes, and only return a
3307major-mode. 3315major-mode.
@@ -3319,7 +3327,7 @@ local variables, but directory-local variables may still be applied."
3319 (let ((enable-local-variables 3327 (let ((enable-local-variables
3320 (and local-enable-local-variables enable-local-variables)) 3328 (and local-enable-local-variables enable-local-variables))
3321 result) 3329 result)
3322 (unless mode-only 3330 (unless (eq handle-mode t)
3323 (setq file-local-variables-alist nil) 3331 (setq file-local-variables-alist nil)
3324 (with-demoted-errors "Directory-local variables error: %s" 3332 (with-demoted-errors "Directory-local variables error: %s"
3325 ;; Note this is a no-op if enable-local-variables is nil. 3333 ;; Note this is a no-op if enable-local-variables is nil.
@@ -3327,18 +3335,19 @@ local variables, but directory-local variables may still be applied."
3327 ;; This entire function is basically a no-op if enable-local-variables 3335 ;; This entire function is basically a no-op if enable-local-variables
3328 ;; is nil. All it does is set file-local-variables-alist to nil. 3336 ;; is nil. All it does is set file-local-variables-alist to nil.
3329 (when enable-local-variables 3337 (when enable-local-variables
3330 ;; This part used to ignore enable-local-variables when mode-only 3338 ;; This part used to ignore enable-local-variables when handle-mode
3331 ;; was non-nil. That was inappropriate, eg consider the 3339 ;; was t. That was inappropriate, eg consider the
3332 ;; (artificial) example of: 3340 ;; (artificial) example of:
3333 ;; (setq local-enable-local-variables nil) 3341 ;; (setq local-enable-local-variables nil)
3334 ;; Open a file foo.txt that contains "mode: sh". 3342 ;; Open a file foo.txt that contains "mode: sh".
3335 ;; It correctly opens in text-mode. 3343 ;; It correctly opens in text-mode.
3336 ;; M-x set-visited-file name foo.c, and it incorrectly stays in text-mode. 3344 ;; M-x set-visited-file name foo.c, and it incorrectly stays in text-mode.
3337 (unless (or (inhibit-local-variables-p) 3345 (unless (or (inhibit-local-variables-p)
3338 ;; If MODE-ONLY is non-nil, and the prop line specifies a 3346 ;; If HANDLE-MODE is t, and the prop line specifies a
3339 ;; mode, then we're done, and have no need to scan further. 3347 ;; mode, then we're done, and have no need to scan further.
3340 (and (setq result (hack-local-variables-prop-line mode-only)) 3348 (and (setq result (hack-local-variables-prop-line
3341 mode-only)) 3349 (eq handle-mode t)))
3350 (eq handle-mode t)))
3342 ;; Look for "Local variables:" line in last page. 3351 ;; Look for "Local variables:" line in last page.
3343 (save-excursion 3352 (save-excursion
3344 (goto-char (point-max)) 3353 (goto-char (point-max))
@@ -3393,7 +3402,7 @@ local variables, but directory-local variables may still be applied."
3393 (goto-char (point-min)) 3402 (goto-char (point-min))
3394 3403
3395 (while (not (or (eobp) 3404 (while (not (or (eobp)
3396 (and mode-only result))) 3405 (and (eq handle-mode t) result)))
3397 ;; Find the variable name; 3406 ;; Find the variable name;
3398 (unless (looking-at hack-local-variable-regexp) 3407 (unless (looking-at hack-local-variable-regexp)
3399 (error "Malformed local variable line: %S" 3408 (error "Malformed local variable line: %S"
@@ -3410,7 +3419,7 @@ local variables, but directory-local variables may still be applied."
3410 (forward-char 1) 3419 (forward-char 1)
3411 (let ((read-circle nil)) 3420 (let ((read-circle nil))
3412 (setq val (read (current-buffer)))) 3421 (setq val (read (current-buffer))))
3413 (if mode-only 3422 (if (eq handle-mode t)
3414 (and (eq var 'mode) 3423 (and (eq var 'mode)
3415 ;; Specifying minor-modes via mode: is 3424 ;; Specifying minor-modes via mode: is
3416 ;; deprecated, but try to reject them anyway. 3425 ;; deprecated, but try to reject them anyway.
@@ -3432,6 +3441,7 @@ local variables, but directory-local variables may still be applied."
3432 ;; to use 'thisbuf's name in the 3441 ;; to use 'thisbuf's name in the
3433 ;; warning message. 3442 ;; warning message.
3434 (or (buffer-file-name thisbuf) "")))))) 3443 (or (buffer-file-name thisbuf) ""))))))
3444 ((and (eq var 'mode) handle-mode))
3435 (t 3445 (t
3436 (ignore-errors 3446 (ignore-errors
3437 (push (cons (if (eq var 'eval) 3447 (push (cons (if (eq var 'eval)
@@ -3440,8 +3450,8 @@ local variables, but directory-local variables may still be applied."
3440 val) result)))))) 3450 val) result))))))
3441 (forward-line 1)))))))) 3451 (forward-line 1))))))))
3442 ;; Now we've read all the local variables. 3452 ;; Now we've read all the local variables.
3443 ;; If MODE-ONLY is non-nil, return whether the mode was specified. 3453 ;; If HANDLE-MODE is t, return whether the mode was specified.
3444 (if mode-only result 3454 (if (eq handle-mode t) result
3445 ;; Otherwise, set the variables. 3455 ;; Otherwise, set the variables.
3446 (hack-local-variables-filter result nil) 3456 (hack-local-variables-filter result nil)
3447 (hack-local-variables-apply))))) 3457 (hack-local-variables-apply)))))
diff --git a/lisp/subr.el b/lisp/subr.el
index afc86a77f8d..f67f70f85c9 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -1737,10 +1737,14 @@ if it is empty or a duplicate."
1737 1737
1738(defun run-mode-hooks (&rest hooks) 1738(defun run-mode-hooks (&rest hooks)
1739 "Run mode hooks `delayed-mode-hooks' and HOOKS, or delay HOOKS. 1739 "Run mode hooks `delayed-mode-hooks' and HOOKS, or delay HOOKS.
1740If the variable `delay-mode-hooks' is non-nil, does not run any hooks, 1740Call `hack-local-variables' to set up file local and directory local
1741variables.
1742
1743If the variable `delay-mode-hooks' is non-nil, does not do anything,
1741just adds the HOOKS to the list `delayed-mode-hooks'. 1744just adds the HOOKS to the list `delayed-mode-hooks'.
1742Otherwise, runs hooks in the sequence: `change-major-mode-after-body-hook', 1745Otherwise, runs hooks in the sequence: `change-major-mode-after-body-hook',
1743`delayed-mode-hooks' (in reverse order), HOOKS, and finally 1746`delayed-mode-hooks' (in reverse order), HOOKS, then runs
1747`hack-local-variables' and finally runs the hook
1744`after-change-major-mode-hook'. Major mode functions should use 1748`after-change-major-mode-hook'. Major mode functions should use
1745this instead of `run-hooks' when running their FOO-mode-hook." 1749this instead of `run-hooks' when running their FOO-mode-hook."
1746 (if delay-mode-hooks 1750 (if delay-mode-hooks
@@ -1751,6 +1755,9 @@ this instead of `run-hooks' when running their FOO-mode-hook."
1751 (setq hooks (nconc (nreverse delayed-mode-hooks) hooks)) 1755 (setq hooks (nconc (nreverse delayed-mode-hooks) hooks))
1752 (setq delayed-mode-hooks nil) 1756 (setq delayed-mode-hooks nil)
1753 (apply 'run-hooks (cons 'change-major-mode-after-body-hook hooks)) 1757 (apply 'run-hooks (cons 'change-major-mode-after-body-hook hooks))
1758 (if (buffer-file-name)
1759 (with-demoted-errors "File local-variables error: %s"
1760 (hack-local-variables 'no-mode)))
1754 (run-hooks 'after-change-major-mode-hook))) 1761 (run-hooks 'after-change-major-mode-hook)))
1755 1762
1756(defmacro delay-mode-hooks (&rest body) 1763(defmacro delay-mode-hooks (&rest body)