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 | |
| 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.
| -rw-r--r-- | doc/lispref/modes.texi | 26 | ||||
| -rw-r--r-- | etc/NEWS | 6 | ||||
| -rw-r--r-- | lisp/emacs-lisp/derived.el | 15 | ||||
| -rw-r--r-- | lisp/subr.el | 19 |
4 files changed, 53 insertions, 13 deletions
diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi index 76e5174bd20..7b76e6af9c3 100644 --- a/doc/lispref/modes.texi +++ b/doc/lispref/modes.texi | |||
| @@ -752,7 +752,8 @@ The new mode has its own abbrev table, kept in the variable | |||
| 752 | @item | 752 | @item |
| 753 | The new mode has its own mode hook, @code{@var{variant}-hook}. It | 753 | The new mode has its own mode hook, @code{@var{variant}-hook}. It |
| 754 | runs this hook, after running the hooks of its ancestor modes, with | 754 | runs this hook, after running the hooks of its ancestor modes, with |
| 755 | @code{run-mode-hooks}, as the last thing it does. @xref{Mode Hooks}. | 755 | @code{run-mode-hooks}, as the last thing it does, apart from running |
| 756 | any @code{:after-hook} form it may have. @xref{Mode Hooks}. | ||
| 756 | @end itemize | 757 | @end itemize |
| 757 | 758 | ||
| 758 | In addition, you can specify how to override other aspects of | 759 | In addition, you can specify how to override other aspects of |
| @@ -776,8 +777,9 @@ about the mode's hook, followed by the mode's keymap, at the end of this | |||
| 776 | documentation string. If you omit @var{docstring}, | 777 | documentation string. If you omit @var{docstring}, |
| 777 | @code{define-derived-mode} generates a documentation string. | 778 | @code{define-derived-mode} generates a documentation string. |
| 778 | 779 | ||
| 779 | The @var{keyword-args} are pairs of keywords and values. The values | 780 | The @var{keyword-args} are pairs of keywords and values. The values, |
| 780 | are evaluated. The following keywords are currently supported: | 781 | except for @code{:after-hook}'s, are evaluated. The following |
| 782 | keywords are currently supported: | ||
| 781 | 783 | ||
| 782 | @table @code | 784 | @table @code |
| 783 | @item :syntax-table | 785 | @item :syntax-table |
| @@ -801,6 +803,15 @@ this mode. (Not all major modes have one.) Only the (still | |||
| 801 | experimental and unadvertised) command @code{customize-mode} currently | 803 | experimental and unadvertised) command @code{customize-mode} currently |
| 802 | uses this. @code{define-derived-mode} does @emph{not} automatically | 804 | uses this. @code{define-derived-mode} does @emph{not} automatically |
| 803 | define the specified customization group. | 805 | define the specified customization group. |
| 806 | |||
| 807 | @item :after-hook | ||
| 808 | This optional keyword specifies a single Lisp form to evaluate as the | ||
| 809 | final act of the mode function, after the mode hooks have been run. | ||
| 810 | It should not be quoted. Since the form might be evaluated after the | ||
| 811 | mode function has terminated, it should not access any element of the | ||
| 812 | mode function's local state. An @code{:after-hook} form is useful for | ||
| 813 | setting up aspects of the mode which depend on the user's settings, | ||
| 814 | which in turn may have been changed in a mode hook. | ||
| 804 | @end table | 815 | @end table |
| 805 | 816 | ||
| 806 | Here is a hypothetical example: | 817 | Here is a hypothetical example: |
| @@ -912,12 +923,15 @@ Major modes should run their mode hook using this function. It is | |||
| 912 | similar to @code{run-hooks} (@pxref{Hooks}), but it also runs | 923 | similar to @code{run-hooks} (@pxref{Hooks}), but it also runs |
| 913 | @code{change-major-mode-after-body-hook}, @code{hack-local-variables} | 924 | @code{change-major-mode-after-body-hook}, @code{hack-local-variables} |
| 914 | (when the buffer is visiting a file) (@pxref{File Local Variables}), | 925 | (when the buffer is visiting a file) (@pxref{File Local Variables}), |
| 915 | and @code{after-change-major-mode-hook}. | 926 | and @code{after-change-major-mode-hook}. The last thing it does is to |
| 927 | evaluate any @code{:after-hook} forms declared by parent modes | ||
| 928 | (@pxref{Derived Modes}). | ||
| 916 | 929 | ||
| 917 | When this function is called during the execution of a | 930 | When this function is called during the execution of a |
| 918 | @code{delay-mode-hooks} form, it does not run the hooks or | 931 | @code{delay-mode-hooks} form, it does not run the hooks or |
| 919 | @code{hack-local-variables} immediately. Instead, it arranges for the | 932 | @code{hack-local-variables} or evaluate the forms immediately. |
| 920 | next call to @code{run-mode-hooks} to run them. | 933 | Instead, it arranges for the next call to @code{run-mode-hooks} to run |
| 934 | them. | ||
| 921 | @end defun | 935 | @end defun |
| 922 | 936 | ||
| 923 | @defmac delay-mode-hooks body@dots{} | 937 | @defmac delay-mode-hooks body@dots{} |
| @@ -369,6 +369,12 @@ variable. | |||
| 369 | 369 | ||
| 370 | ** New var syntax-ppss-table to control the syntax-table used in syntax-ppss. | 370 | ** New var syntax-ppss-table to control the syntax-table used in syntax-ppss. |
| 371 | 371 | ||
| 372 | +++ | ||
| 373 | ** `define-derived-mode' can now specify an :after-hook form, which | ||
| 374 | gets evaluated after the new mode's hook has run. This can be used to | ||
| 375 | incorporate configuration changes made in the mode hook into the | ||
| 376 | mode's setup. | ||
| 377 | |||
| 372 | ** Autoload files can be generated without timestamps, | 378 | ** Autoload files can be generated without timestamps, |
| 373 | by setting 'autoload-timestamps' to nil. | 379 | by setting 'autoload-timestamps' to nil. |
| 374 | FIXME As an experiment, nil is the current default. | 380 | FIXME As an experiment, nil is the current default. |
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'. |