diff options
| author | Alan Mackenzie | 2016-05-08 13:24:20 +0000 |
|---|---|---|
| committer | Alan Mackenzie | 2016-05-08 13:24:20 +0000 |
| commit | 2eb6817ba971184cc109f8530f4b3b38f65650ea (patch) | |
| tree | b23258db9a4d1720583784fd1b90824a45835f91 /lisp | |
| parent | 344eb61ab3607827930354589174bb8d270241b9 (diff) | |
| download | emacs-2eb6817ba971184cc109f8530f4b3b38f65650ea.tar.gz emacs-2eb6817ba971184cc109f8530f4b3b38f65650ea.zip | |
Add :after-hook facility to define-derived-mode.
This allow a form to be evaluated _after_ a major mode's hooks have been run.
It is needed to solve some problems in CC Mode, including bug #16759 and
bug #23476.
* lisp/emacs-lisp/derived.el (define-derived-mode): introduce the new argument
`:after-hook', and generate the requisite code for it.
(derived-mode-make-docstring): Take account of the possibility of :after-hook.
* lisp/subr.el (delayed-after-hook-forms): New variable.
(run-mode-hooks): As the last thing evaluate the forms in
delayed-after-hook-forms.
* doc/lispref/modes.texi (Derived Modes): Document :after-hook.
(Mode Hooks): Document the new feature in run-mode-hooks.
* etc/NEWS: Note the new feature.
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/emacs-lisp/derived.el | 15 | ||||
| -rw-r--r-- | lisp/subr.el | 19 |
2 files changed, 27 insertions, 7 deletions
diff --git a/lisp/emacs-lisp/derived.el b/lisp/emacs-lisp/derived.el index a615f9a5854..0f7691af0f4 100644 --- a/lisp/emacs-lisp/derived.el +++ b/lisp/emacs-lisp/derived.el | |||
| @@ -137,6 +137,9 @@ BODY can start with a bunch of keyword arguments. The following keyword | |||
| 137 | :abbrev-table TABLE | 137 | :abbrev-table TABLE |
| 138 | Use TABLE instead of the default (CHILD-abbrev-table). | 138 | Use TABLE instead of the default (CHILD-abbrev-table). |
| 139 | A nil value means to simply use the same abbrev-table as the parent. | 139 | A nil value means to simply use the same abbrev-table as the parent. |
| 140 | :after-hook FORM | ||
| 141 | A single lisp form which is evaluated after the mode hooks have been | ||
| 142 | run. It should not be quoted. | ||
| 140 | 143 | ||
| 141 | Here is how you could define LaTeX-Thesis mode as a variant of LaTeX mode: | 144 | Here is how you could define LaTeX-Thesis mode as a variant of LaTeX mode: |
| 142 | 145 | ||
| @@ -184,7 +187,8 @@ See Info node `(elisp)Derived Modes' for more details." | |||
| 184 | (declare-abbrev t) | 187 | (declare-abbrev t) |
| 185 | (declare-syntax t) | 188 | (declare-syntax t) |
| 186 | (hook (derived-mode-hook-name child)) | 189 | (hook (derived-mode-hook-name child)) |
| 187 | (group nil)) | 190 | (group nil) |
| 191 | (after-hook nil)) | ||
| 188 | 192 | ||
| 189 | ;; Process the keyword args. | 193 | ;; Process the keyword args. |
| 190 | (while (keywordp (car body)) | 194 | (while (keywordp (car body)) |
| @@ -192,6 +196,7 @@ See Info node `(elisp)Derived Modes' for more details." | |||
| 192 | (`:group (setq group (pop body))) | 196 | (`:group (setq group (pop body))) |
| 193 | (`:abbrev-table (setq abbrev (pop body)) (setq declare-abbrev nil)) | 197 | (`:abbrev-table (setq abbrev (pop body)) (setq declare-abbrev nil)) |
| 194 | (`:syntax-table (setq syntax (pop body)) (setq declare-syntax nil)) | 198 | (`:syntax-table (setq syntax (pop body)) (setq declare-syntax nil)) |
| 199 | (`:after-hook (setq after-hook (pop body))) | ||
| 195 | (_ (pop body)))) | 200 | (_ (pop body)))) |
| 196 | 201 | ||
| 197 | (setq docstring (derived-mode-make-docstring | 202 | (setq docstring (derived-mode-make-docstring |
| @@ -272,7 +277,11 @@ No problems result if this variable is not bound. | |||
| 272 | ,@body | 277 | ,@body |
| 273 | ) | 278 | ) |
| 274 | ;; Run the hooks, if any. | 279 | ;; Run the hooks, if any. |
| 275 | (run-mode-hooks ',hook))))) | 280 | (run-mode-hooks ',hook) |
| 281 | ,@(when after-hook | ||
| 282 | `((if delay-mode-hooks | ||
| 283 | (push ',after-hook delayed-after-hook-forms) | ||
| 284 | ,after-hook))))))) | ||
| 276 | 285 | ||
| 277 | ;; PUBLIC: find the ultimate class of a derived mode. | 286 | ;; PUBLIC: find the ultimate class of a derived mode. |
| 278 | 287 | ||
| @@ -344,7 +353,7 @@ which more-or-less shadow%s %s's corresponding table%s." | |||
| 344 | (format "`%s' " parent)) | 353 | (format "`%s' " parent)) |
| 345 | "might have run,\nthis mode ")) | 354 | "might have run,\nthis mode ")) |
| 346 | (format "runs the hook `%s'" hook) | 355 | (format "runs the hook `%s'" hook) |
| 347 | ", as the final step\nduring initialization."))) | 356 | ", as the final or penultimate step\nduring initialization."))) |
| 348 | 357 | ||
| 349 | (unless (string-match "\\\\[{[]" docstring) | 358 | (unless (string-match "\\\\[{[]" docstring) |
| 350 | ;; And don't forget to put the mode's keymap. | 359 | ;; And don't forget to put the mode's keymap. |
diff --git a/lisp/subr.el b/lisp/subr.el index 094710b026c..0fa6404d37d 100644 --- a/lisp/subr.el +++ b/lisp/subr.el | |||
| @@ -1736,6 +1736,11 @@ if it is empty or a duplicate." | |||
| 1736 | (make-variable-buffer-local 'delayed-mode-hooks) | 1736 | (make-variable-buffer-local 'delayed-mode-hooks) |
| 1737 | (put 'delay-mode-hooks 'permanent-local t) | 1737 | (put 'delay-mode-hooks 'permanent-local t) |
| 1738 | 1738 | ||
| 1739 | (defvar delayed-after-hook-forms nil | ||
| 1740 | "List of delayed :after-hook forms waiting to be run. | ||
| 1741 | These forms come from `define-derived-mode'.") | ||
| 1742 | (make-variable-buffer-local 'delayed-after-hook-forms) | ||
| 1743 | |||
| 1739 | (defvar change-major-mode-after-body-hook nil | 1744 | (defvar change-major-mode-after-body-hook nil |
| 1740 | "Normal hook run in major mode functions, before the mode hooks.") | 1745 | "Normal hook run in major mode functions, before the mode hooks.") |
| 1741 | 1746 | ||
| @@ -1751,9 +1756,12 @@ If the variable `delay-mode-hooks' is non-nil, does not do anything, | |||
| 1751 | just adds the HOOKS to the list `delayed-mode-hooks'. | 1756 | just adds the HOOKS to the list `delayed-mode-hooks'. |
| 1752 | Otherwise, runs hooks in the sequence: `change-major-mode-after-body-hook', | 1757 | Otherwise, runs hooks in the sequence: `change-major-mode-after-body-hook', |
| 1753 | `delayed-mode-hooks' (in reverse order), HOOKS, then runs | 1758 | `delayed-mode-hooks' (in reverse order), HOOKS, then runs |
| 1754 | `hack-local-variables' and finally runs the hook | 1759 | `hack-local-variables', runs the hook `after-change-major-mode-hook', and |
| 1755 | `after-change-major-mode-hook'. Major mode functions should use | 1760 | finally evaluates the forms in `delayed-after-hook-forms' (see |
| 1756 | this instead of `run-hooks' when running their FOO-mode-hook." | 1761 | `define-derived-mode'). |
| 1762 | |||
| 1763 | Major mode functions should use this instead of `run-hooks' when | ||
| 1764 | running their FOO-mode-hook." | ||
| 1757 | (if delay-mode-hooks | 1765 | (if delay-mode-hooks |
| 1758 | ;; Delaying case. | 1766 | ;; Delaying case. |
| 1759 | (dolist (hook hooks) | 1767 | (dolist (hook hooks) |
| @@ -1765,7 +1773,10 @@ this instead of `run-hooks' when running their FOO-mode-hook." | |||
| 1765 | (if (buffer-file-name) | 1773 | (if (buffer-file-name) |
| 1766 | (with-demoted-errors "File local-variables error: %s" | 1774 | (with-demoted-errors "File local-variables error: %s" |
| 1767 | (hack-local-variables 'no-mode))) | 1775 | (hack-local-variables 'no-mode))) |
| 1768 | (run-hooks 'after-change-major-mode-hook))) | 1776 | (run-hooks 'after-change-major-mode-hook) |
| 1777 | (dolist (form (nreverse delayed-after-hook-forms)) | ||
| 1778 | (eval form)) | ||
| 1779 | (setq delayed-after-hook-forms nil))) | ||
| 1769 | 1780 | ||
| 1770 | (defmacro delay-mode-hooks (&rest body) | 1781 | (defmacro delay-mode-hooks (&rest body) |
| 1771 | "Execute BODY, but delay any `run-mode-hooks'. | 1782 | "Execute BODY, but delay any `run-mode-hooks'. |