diff options
| author | Alan Mackenzie | 2016-05-05 11:05:49 +0000 |
|---|---|---|
| committer | Alan Mackenzie | 2016-05-05 11:05:49 +0000 |
| commit | 25f455815bfaa868dc470d445413df9a7a546c46 (patch) | |
| tree | b0c56ba886eda0dfe5b0e200d59051dafd644488 /lisp | |
| parent | 6aad36ace9953b9672b13be68416d205532d5e59 (diff) | |
| download | emacs-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.el | 38 | ||||
| -rw-r--r-- | lisp/subr.el | 11 |
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. |
| 3302 | Uses `hack-local-variables-apply' to apply the variables. | 3306 | Uses `hack-local-variables-apply' to apply the variables. |
| 3303 | 3307 | ||
| 3304 | If MODE-ONLY is non-nil, all we do is check whether a \"mode:\" | 3308 | If HANDLE-MODE is nil, we apply all the specified local |
| 3309 | variables. If HANDLE-MODE is neither nil nor t, we do the same, | ||
| 3310 | except that any settings of `mode' are ignored. | ||
| 3311 | |||
| 3312 | If HANDLE-MODE is t, all we do is check whether a \"mode:\" | ||
| 3305 | is specified, and return the corresponding mode symbol, or nil. | 3313 | is specified, and return the corresponding mode symbol, or nil. |
| 3306 | In this case, we try to ignore minor-modes, and only return a | 3314 | In this case, we try to ignore minor-modes, and only return a |
| 3307 | major-mode. | 3315 | major-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. |
| 1740 | If the variable `delay-mode-hooks' is non-nil, does not run any hooks, | 1740 | Call `hack-local-variables' to set up file local and directory local |
| 1741 | variables. | ||
| 1742 | |||
| 1743 | If the variable `delay-mode-hooks' is non-nil, does not do anything, | ||
| 1741 | just adds the HOOKS to the list `delayed-mode-hooks'. | 1744 | just adds the HOOKS to the list `delayed-mode-hooks'. |
| 1742 | Otherwise, runs hooks in the sequence: `change-major-mode-after-body-hook', | 1745 | Otherwise, 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 |
| 1745 | this instead of `run-hooks' when running their FOO-mode-hook." | 1749 | this 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) |