aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorAlan Mackenzie2016-05-08 13:24:20 +0000
committerAlan Mackenzie2016-05-08 13:24:20 +0000
commit2eb6817ba971184cc109f8530f4b3b38f65650ea (patch)
treeb23258db9a4d1720583784fd1b90824a45835f91 /lisp
parent344eb61ab3607827930354589174bb8d270241b9 (diff)
downloademacs-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.el15
-rw-r--r--lisp/subr.el19
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
141Here is how you could define LaTeX-Thesis mode as a variant of LaTeX mode: 144Here 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.
1741These 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,
1751just adds the HOOKS to the list `delayed-mode-hooks'. 1756just adds the HOOKS to the list `delayed-mode-hooks'.
1752Otherwise, runs hooks in the sequence: `change-major-mode-after-body-hook', 1757Otherwise, 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 1760finally evaluates the forms in `delayed-after-hook-forms' (see
1756this instead of `run-hooks' when running their FOO-mode-hook." 1761`define-derived-mode').
1762
1763Major mode functions should use this instead of `run-hooks' when
1764running 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'.