emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 2eb6817: Add :after-hook facility to define-derived


From: Alan Mackenzie
Subject: [Emacs-diffs] master 2eb6817: Add :after-hook facility to define-derived-mode.
Date: Sun, 8 May 2016 13:27:08 +0000 (UTC)

branch: master
commit 2eb6817ba971184cc109f8530f4b3b38f65650ea
Author: Alan Mackenzie <address@hidden>
Commit: Alan Mackenzie <address@hidden>

    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.
---
 doc/lispref/modes.texi     |   26 ++++++++++++++++++++------
 etc/NEWS                   |    6 ++++++
 lisp/emacs-lisp/derived.el |   15 ++++++++++++---
 lisp/subr.el               |   19 +++++++++++++++----
 4 files changed, 53 insertions(+), 13 deletions(-)

diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index 76e5174..7b76e6a 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
 @item
 The new mode has its own mode hook, @address@hidden  It
 runs this hook, after running the hooks of its ancestor modes, with
address@hidden, as the last thing it does.  @xref{Mode Hooks}.
address@hidden, 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.
+
address@hidden :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
address@hidden immediately.  Instead, it arranges for the
-next call to @code{run-mode-hooks} to run them.
address@hidden 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 address@hidden
diff --git a/etc/NEWS b/etc/NEWS
index 92d301e..22eb2ea 100644
--- a/etc/NEWS
+++ b/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.
diff --git a/lisp/emacs-lisp/derived.el b/lisp/emacs-lisp/derived.el
index a615f9a..0f7691a 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
 :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.
diff --git a/lisp/subr.el b/lisp/subr.el
index 094710b..0fa6404 100644
--- a/lisp/subr.el
+++ b/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'.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]