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.
This commit is contained in:
parent
344eb61ab3
commit
2eb6817ba9
4 changed files with 53 additions and 13 deletions
|
@ -752,7 +752,8 @@ The new mode has its own abbrev table, kept in the variable
|
|||
@item
|
||||
The new mode has its own mode hook, @code{@var{variant}-hook}. It
|
||||
runs this hook, after running the hooks of its ancestor modes, with
|
||||
@code{run-mode-hooks}, as the last thing it does. @xref{Mode Hooks}.
|
||||
@code{run-mode-hooks}, as the last thing it does, apart from running
|
||||
any @code{:after-hook} form it may have. @xref{Mode Hooks}.
|
||||
@end itemize
|
||||
|
||||
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
|
|||
documentation string. If you omit @var{docstring},
|
||||
@code{define-derived-mode} generates a documentation string.
|
||||
|
||||
The @var{keyword-args} are pairs of keywords and values. The values
|
||||
are evaluated. The following keywords are currently supported:
|
||||
The @var{keyword-args} are pairs of keywords and values. The values,
|
||||
except for @code{:after-hook}'s, are evaluated. The following
|
||||
keywords are currently supported:
|
||||
|
||||
@table @code
|
||||
@item :syntax-table
|
||||
|
@ -801,6 +803,15 @@ this mode. (Not all major modes have one.) Only the (still
|
|||
experimental and unadvertised) command @code{customize-mode} currently
|
||||
uses this. @code{define-derived-mode} does @emph{not} automatically
|
||||
define the specified customization group.
|
||||
|
||||
@item :after-hook
|
||||
This optional keyword specifies a single Lisp form to evaluate as the
|
||||
final act of the mode function, after the mode hooks have been run.
|
||||
It should not be quoted. Since the form might be evaluated after the
|
||||
mode function has terminated, it should not access any element of the
|
||||
mode function's local state. An @code{:after-hook} form is useful for
|
||||
setting up aspects of the mode which depend on the user's settings,
|
||||
which in turn may have been changed in a mode hook.
|
||||
@end table
|
||||
|
||||
Here is a hypothetical example:
|
||||
|
@ -912,12 +923,15 @@ Major modes should run their mode hook using this function. It is
|
|||
similar to @code{run-hooks} (@pxref{Hooks}), but it also runs
|
||||
@code{change-major-mode-after-body-hook}, @code{hack-local-variables}
|
||||
(when the buffer is visiting a file) (@pxref{File Local Variables}),
|
||||
and @code{after-change-major-mode-hook}.
|
||||
and @code{after-change-major-mode-hook}. The last thing it does is to
|
||||
evaluate any @code{:after-hook} forms declared by parent modes
|
||||
(@pxref{Derived Modes}).
|
||||
|
||||
When this function is called during the execution of a
|
||||
@code{delay-mode-hooks} form, it does not run the hooks or
|
||||
@code{hack-local-variables} immediately. Instead, it arranges for the
|
||||
next call to @code{run-mode-hooks} to run them.
|
||||
@code{hack-local-variables} or evaluate the forms immediately.
|
||||
Instead, it arranges for the next call to @code{run-mode-hooks} to run
|
||||
them.
|
||||
@end defun
|
||||
|
||||
@defmac delay-mode-hooks body@dots{}
|
||||
|
|
6
etc/NEWS
6
etc/NEWS
|
@ -369,6 +369,12 @@ variable.
|
|||
|
||||
** New var syntax-ppss-table to control the syntax-table used in syntax-ppss.
|
||||
|
||||
+++
|
||||
** `define-derived-mode' can now specify an :after-hook form, which
|
||||
gets evaluated after the new mode's hook has run. This can be used to
|
||||
incorporate configuration changes made in the mode hook into the
|
||||
mode's setup.
|
||||
|
||||
** Autoload files can be generated without timestamps,
|
||||
by setting 'autoload-timestamps' to nil.
|
||||
FIXME As an experiment, nil is the current default.
|
||||
|
|
|
@ -137,6 +137,9 @@ BODY can start with a bunch of keyword arguments. The following keyword
|
|||
:abbrev-table TABLE
|
||||
Use TABLE instead of the default (CHILD-abbrev-table).
|
||||
A nil value means to simply use the same abbrev-table as the parent.
|
||||
:after-hook FORM
|
||||
A single lisp form which is evaluated after the mode hooks have been
|
||||
run. It should not be quoted.
|
||||
|
||||
Here is how you could define LaTeX-Thesis mode as a variant of LaTeX mode:
|
||||
|
||||
|
@ -184,7 +187,8 @@ See Info node `(elisp)Derived Modes' for more details."
|
|||
(declare-abbrev t)
|
||||
(declare-syntax t)
|
||||
(hook (derived-mode-hook-name child))
|
||||
(group nil))
|
||||
(group nil)
|
||||
(after-hook nil))
|
||||
|
||||
;; Process the keyword args.
|
||||
(while (keywordp (car body))
|
||||
|
@ -192,6 +196,7 @@ See Info node `(elisp)Derived Modes' for more details."
|
|||
(`:group (setq group (pop body)))
|
||||
(`:abbrev-table (setq abbrev (pop body)) (setq declare-abbrev nil))
|
||||
(`:syntax-table (setq syntax (pop body)) (setq declare-syntax nil))
|
||||
(`:after-hook (setq after-hook (pop body)))
|
||||
(_ (pop body))))
|
||||
|
||||
(setq docstring (derived-mode-make-docstring
|
||||
|
@ -272,7 +277,11 @@ No problems result if this variable is not bound.
|
|||
,@body
|
||||
)
|
||||
;; Run the hooks, if any.
|
||||
(run-mode-hooks ',hook)))))
|
||||
(run-mode-hooks ',hook)
|
||||
,@(when after-hook
|
||||
`((if delay-mode-hooks
|
||||
(push ',after-hook delayed-after-hook-forms)
|
||||
,after-hook)))))))
|
||||
|
||||
;; PUBLIC: find the ultimate class of a derived mode.
|
||||
|
||||
|
@ -344,7 +353,7 @@ which more-or-less shadow%s %s's corresponding table%s."
|
|||
(format "`%s' " parent))
|
||||
"might have run,\nthis mode "))
|
||||
(format "runs the hook `%s'" hook)
|
||||
", as the final step\nduring initialization.")))
|
||||
", as the final or penultimate step\nduring initialization.")))
|
||||
|
||||
(unless (string-match "\\\\[{[]" docstring)
|
||||
;; And don't forget to put the mode's keymap.
|
||||
|
|
19
lisp/subr.el
19
lisp/subr.el
|
@ -1736,6 +1736,11 @@ if it is empty or a duplicate."
|
|||
(make-variable-buffer-local 'delayed-mode-hooks)
|
||||
(put 'delay-mode-hooks 'permanent-local t)
|
||||
|
||||
(defvar delayed-after-hook-forms nil
|
||||
"List of delayed :after-hook forms waiting to be run.
|
||||
These forms come from `define-derived-mode'.")
|
||||
(make-variable-buffer-local 'delayed-after-hook-forms)
|
||||
|
||||
(defvar change-major-mode-after-body-hook nil
|
||||
"Normal hook run in major mode functions, before the mode hooks.")
|
||||
|
||||
|
@ -1751,9 +1756,12 @@ If the variable `delay-mode-hooks' is non-nil, does not do anything,
|
|||
just adds the HOOKS to the list `delayed-mode-hooks'.
|
||||
Otherwise, runs hooks in the sequence: `change-major-mode-after-body-hook',
|
||||
`delayed-mode-hooks' (in reverse order), HOOKS, then runs
|
||||
`hack-local-variables' and finally runs the hook
|
||||
`after-change-major-mode-hook'. Major mode functions should use
|
||||
this instead of `run-hooks' when running their FOO-mode-hook."
|
||||
`hack-local-variables', runs the hook `after-change-major-mode-hook', and
|
||||
finally evaluates the forms in `delayed-after-hook-forms' (see
|
||||
`define-derived-mode').
|
||||
|
||||
Major mode functions should use this instead of `run-hooks' when
|
||||
running their FOO-mode-hook."
|
||||
(if delay-mode-hooks
|
||||
;; Delaying case.
|
||||
(dolist (hook hooks)
|
||||
|
@ -1765,7 +1773,10 @@ this instead of `run-hooks' when running their FOO-mode-hook."
|
|||
(if (buffer-file-name)
|
||||
(with-demoted-errors "File local-variables error: %s"
|
||||
(hack-local-variables 'no-mode)))
|
||||
(run-hooks 'after-change-major-mode-hook)))
|
||||
(run-hooks 'after-change-major-mode-hook)
|
||||
(dolist (form (nreverse delayed-after-hook-forms))
|
||||
(eval form))
|
||||
(setq delayed-after-hook-forms nil)))
|
||||
|
||||
(defmacro delay-mode-hooks (&rest body)
|
||||
"Execute BODY, but delay any `run-mode-hooks'.
|
||||
|
|
Loading…
Add table
Reference in a new issue