]> git.eshelyaron.com Git - emacs.git/commitdiff
subr.el: Provide a functional API around `derived-mode-parent`
authorStefan Monnier <monnier@iro.umontreal.ca>
Wed, 8 Nov 2023 16:32:27 +0000 (11:32 -0500)
committerStefan Monnier <monnier@iro.umontreal.ca>
Thu, 9 Nov 2023 03:42:16 +0000 (22:42 -0500)
The `derived-mode-parent` property should be an implementation detail,
so we can change it more easily.  To that end, add functions to set and
query it.

* lisp/subr.el (derived-mode-all-parents): New function.
(provided-mode-derived-p): Use it.
(derived-mode-set-parent): New function.

lisp/subr.el

index d4173b4dabaecd8e1f8260e29410a074ecdbb4bb..6a4c1abfb6216ccff9bf04c02a174eb240e2a650 100644 (file)
@@ -2678,20 +2678,27 @@ The variable list SPEC is the same as in `if-let*'."
 
 ;; PUBLIC: find if the current mode derives from another.
 
+(defun derived-mode-all-parents (mode &optional known-children)
+  "Return all the parents of MODE, starting with MODE.
+The returned list is not fresh, don't modify it.
+\n(fn MODE)"               ;`known-children' is for internal use only.
+  (if (memq mode known-children)
+      (error "Cycle in the major mode hierarchy: %S" mode)
+    (push mode known-children))
+  (let* ((parent (or (get mode 'derived-mode-parent)
+                     ;; If MODE is an alias, then follow the alias.
+                     (let ((alias (symbol-function mode)))
+                       (and (symbolp alias) alias)))))
+    (cons mode (if parent (derived-mode-all-parents parent known-children)))))
+
 (defun provided-mode-derived-p (mode &rest modes)
   "Non-nil if MODE is derived from one of MODES.
-Uses the `derived-mode-parent' property of the symbol to trace backwards.
 If you just want to check `major-mode', use `derived-mode-p'."
   (declare (side-effect-free t))
-  (while
-      (and
-       (not (memq mode modes))
-       (let* ((parent (get mode 'derived-mode-parent)))
-        (setq mode (or parent
-                       ;; If MODE is an alias, then follow the alias.
-                       (let ((alias (symbol-function mode)))
-                         (and (symbolp alias) alias)))))))
-  mode)
+  (let ((ps (derived-mode-all-parents mode)))
+    (while (and ps (not (memq (car ps) modes)))
+      (setq ps (cdr ps)))
+    (car ps)))
 
 (defun derived-mode-p (&rest modes)
   "Non-nil if the current major mode is derived from one of MODES.
@@ -2699,6 +2706,10 @@ Uses the `derived-mode-parent' property of the symbol to trace backwards."
   (declare (side-effect-free t))
   (apply #'provided-mode-derived-p major-mode modes))
 
+(defun derived-mode-set-parent (mode parent)
+  "Declare PARENT to be the parent of MODE."
+  (put mode 'derived-mode-parent parent))
+
 (defvar-local major-mode--suspended nil)
 (put 'major-mode--suspended 'permanent-local t)