summaryrefslogtreecommitdiff
path: root/lisp/subr.el
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2019-05-29 15:56:14 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2019-05-29 15:56:14 -0400
commitfe0cb43fb80db52a79ef898f8de49560cc5cdd90 (patch)
tree4825956db223eb96d69583e707cbf13a4d280789 /lisp/subr.el
parent49cdbb4a35f8d1d2139e8469bffcf33f65679094 (diff)
downloademacs-fe0cb43fb80db52a79ef898f8de49560cc5cdd90.tar.gz
* lisp/subr.el (add-hook): Turn `append` into `depth` (bug#35508)
Make it possible to control the relative ordering of functions on hooks by specifying `depth` in the same was as was possible with `add-function`. * lisp/electric.el (electric--sort-post-self-insertion-hook): Delete function. (electric-indent-mode, electric-layout-mode, electric-quote-mode): * lisp/elec-pair.el (electric-pair-mode): Use new `depth` arg instead of electric--sort-post-self-insertion-hook. * lisp/emacs-lisp/syntax.el (syntax-propertize, syntax-ppss): Use new `depth` arg to make sure noone accidentally gets added after syntax-ppss-flush-cache. * doc/lispref/modes.texi (Setting Hooks): Document new `depth` arg. * test/lisp/subr-tests.el (subr-tests-add-hook-depth): New test.
Diffstat (limited to 'lisp/subr.el')
-rw-r--r--lisp/subr.el39
1 files changed, 32 insertions, 7 deletions
diff --git a/lisp/subr.el b/lisp/subr.el
index 05fb9fea68f..fd60ec87cca 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -1604,12 +1604,23 @@ be a list of the form returned by `event-start' and `event-end'."
;;;; Hook manipulation functions.
-(defun add-hook (hook function &optional append local)
+(defun add-hook (hook function &optional depth local)
+ ;; Note: the -100..100 depth range is arbitrary and was chosen to match the
+ ;; range used in add-function.
"Add to the value of HOOK the function FUNCTION.
FUNCTION is not added if already present.
-FUNCTION is added (if necessary) at the beginning of the hook list
-unless the optional argument APPEND is non-nil, in which case
-FUNCTION is added at the end.
+
+The place where the function is added depends on the DEPTH
+parameter. DEPTH defaults to 0. By convention, it should be
+a number between -100 and 100 where 100 means that the function
+should be at the very end of the list, whereas -100 means that
+the function should always come first.
+Since nothing is \"always\" true, don't use 100 nor -100.
+When two functions have the same depth, the new one gets added after the
+old one if depth is strictly positive and before otherwise.
+
+For backward compatibility reasons, a symbol other than nil is
+interpreted as a DEPTH of 90.
The optional fourth argument, LOCAL, if non-nil, says to modify
the hook's buffer-local value rather than its global value.
@@ -1622,6 +1633,7 @@ HOOK is void, it is first set to nil. If HOOK's value is a single
function, it is changed to a list of functions."
(or (boundp hook) (set hook nil))
(or (default-boundp hook) (set-default hook nil))
+ (unless (numberp depth) (setq depth (if depth 90 0)))
(if local (unless (local-variable-if-set-p hook)
(set (make-local-variable hook) (list t)))
;; Detect the case where make-local-variable was used on a hook
@@ -1634,12 +1646,25 @@ function, it is changed to a list of functions."
(setq hook-value (list hook-value)))
;; Do the actual addition if necessary
(unless (member function hook-value)
- (when (stringp function)
+ (when (stringp function) ;FIXME: Why?
(setq function (purecopy function)))
+ (when (or (get hook 'hook--depth-alist) (not (zerop depth)))
+ ;; Note: The main purpose of the above `when' test is to avoid running
+ ;; this `setf' before `gv' is loaded during bootstrap.
+ (setf (alist-get function (get hook 'hook--depth-alist)
+ 0 'remove #'equal)
+ depth))
(setq hook-value
- (if append
+ (if (< 0 depth)
(append hook-value (list function))
- (cons function hook-value))))
+ (cons function hook-value)))
+ (let ((depth-alist (get hook 'hook--depth-alist)))
+ (when depth-alist
+ (setq hook-value
+ (sort (if (< 0 depth) hook-value (copy-sequence hook-value))
+ (lambda (f1 f2)
+ (< (alist-get f1 depth-alist 0 nil #'equal)
+ (alist-get f2 depth-alist 0 nil #'equal))))))))
;; Set the actual variable
(if local
(progn