Subject: 30.0.50; Outline mode for describe-mode

From: Juri Linkov <[email-masked]>
Date: Mon, 17 Jul 2023 20:46:25 +0300

>> I tried to enable outline-minor-mode in the output buffer of 'C-h m',
>> and it has some problems:
>>
>> 1. outline-regexp of 'C-h b' is not suitable for 'C-h m', because the
>> output of 'C-h b' is more uniform, but the output of 'C-h m' includes
>> free-form text that causes false positives for the regexp ".*:$".
>>
>> 2. heading lines of 'C-h m' are beginning with a link, so the link faces
>> are copied to the outline indicator.
>>
>> Both these problems could be fixed by adding an asterisk to the beginning
>> of headings in 'C-h m', for example:
>>
>>   * Font-Lock minor mode (no indicator):
>>
>> Does this look nice?  Or should we try to find a regexp for existing output?
>
> I don't know.  We also have ^L that separate sections; can we use that
> for Outline, or maybe add some heading after ^L?

Here is a new option 'describe-mode-outline' that doesn't require
changing the current formatting in 'C-h m':

diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index b9388b45397..e8c019c0a92 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -2110,6 +2110,12 @@ describe-keymap
     (when used-gentemp
       (makunbound keymap))))
 
+(defcustom describe-mode-outline t
+  "Non-nil enables outlines in the output buffer of `describe-mode'."
+  :type 'boolean
+  :group 'help
+  :version "30.1")
+
 ;;;###autoload
 (defun describe-mode (&optional buffer)
   "Display documentation of current major mode and minor modes.
@@ -2135,7 +2141,7 @@ describe-mode
     (with-help-window (help-buffer)
       (with-current-buffer (help-buffer)
         ;; Add the local minor modes at the start.
-        (when local-minors
+        (when (and local-minors (not describe-mode-outline))
           (insert (format "Minor mode%s enabled in this buffer:"
                           (if (length> local-minors 1)
                               "s" "")))
@@ -2162,6 +2168,10 @@ describe-mode
           (insert (help-split-fundoc (documentation major) nil 'doc)
                   (with-current-buffer buffer
                     (help-fns--list-local-commands)))
+          (when describe-mode-outline
+            (save-excursion
+              (goto-char (point-min))
+              (put-text-property (pos-bol) (pos-eol) 'outline-level 1)))
           (ensure-empty-lines 1)
 
           ;; Insert the global minor modes after the major mode.
@@ -2173,6 +2183,23 @@ describe-mode
             (when (re-search-forward "^\f")
               (beginning-of-line)
               (ensure-empty-lines 1)))
+
+          (when describe-mode-outline
+            (setq-local outline-search-function #'outline-search-level)
+            (setq-local outline-level (lambda () 1))
+            (setq-local outline-minor-mode-cycle t
+                        outline-minor-mode-highlight t
+                        outline-minor-mode-use-buttons 'insert
+                        outline--cycle-buffer-state 'show-all)
+            (outline-minor-mode 1)
+            (save-excursion
+              (goto-char (point-min))
+              (let ((inhibit-read-only t))
+                ;; Hide ^Ls.
+                (while (search-forward "\n\f\n" nil t)
+		  (put-text-property (1+ (match-beginning 0)) (1- (match-end 0))
+                                     'invisible t)))))
+
           ;; For the sake of IELM and maybe others
           nil)))))
 
@@ -2208,6 +2235,10 @@ describe-mode--minor-modes
 			      "no indicator"
 			    (format "indicator%s"
 				    indicator)))))
+        (when describe-mode-outline
+          (save-excursion
+            (forward-line -1)
+            (put-text-property (pos-bol) (pos-eol) 'outline-level 1)))
 	(insert (or (help-split-fundoc (documentation mode) nil 'doc)
 	            "No docstring")))))
   (forward-line -1)