unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
@ 2022-02-13 22:39 Daniel Mendler
  2022-02-14 11:06 ` Lars Ingebrigtsen
  2022-11-08 19:12 ` Juri Linkov
  0 siblings, 2 replies; 25+ messages in thread
From: Daniel Mendler @ 2022-02-13 22:39 UTC (permalink / raw)
  To: 53981

The shortdoc buffer currently lacks support for the outline-minor-mode.
By setting the two variables outline-regexp and outline-level, we can
unlock this feature. Does it make sense to provide this by default?

(defun shortdoc--outline-level () (if (eq (char-after) ?\() 2 1)))
(add-hook 'shortdoc-mode-hook
          (lambda ()
            (setq-local outline-level #'shortdoc--outline-level
                        outline-regexp "[A-Z(]")))

In GNU Emacs 28.0.91 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.5,
cairo version 1.16.0)
 of 2022-02-09 built on projects
Repository revision: 82e74e4559b8becd44f3e7ac0134e2baddd69921
Repository branch: emacs-28
Windowing system distributor 'The X.Org Foundation', version 11.0.12004000
System Description: Debian GNU/Linux 10 (buster)





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-13 22:39 bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode Daniel Mendler
@ 2022-02-14 11:06 ` Lars Ingebrigtsen
  2022-02-14 12:23   ` Daniel Mendler
  2022-02-15  7:32   ` Kévin Le Gouguec
  2022-11-08 19:12 ` Juri Linkov
  1 sibling, 2 replies; 25+ messages in thread
From: Lars Ingebrigtsen @ 2022-02-14 11:06 UTC (permalink / raw)
  To: Daniel Mendler; +Cc: 53981

[-- Attachment #1: Type: text/plain, Size: 1164 bytes --]

Daniel Mendler <mail@daniel-mendler.de> writes:

> The shortdoc buffer currently lacks support for the outline-minor-mode.
> By setting the two variables outline-regexp and outline-level, we can
> unlock this feature. Does it make sense to provide this by default?
>
> (defun shortdoc--outline-level () (if (eq (char-after) ?\() 2 1)))
> (add-hook 'shortdoc-mode-hook
>           (lambda ()
>             (setq-local outline-level #'shortdoc--outline-level
>                         outline-regexp "[A-Z(]")))

I tried the following:

diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index 658edd6752..fd79cf5116 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -1435,7 +1435,10 @@ shortdoc-mode-map
 
 (define-derived-mode shortdoc-mode special-mode "shortdoc"
   "Mode for shortdoc."
-  :interactive nil)
+  :interactive nil
+  (setq-local outline-level (lambda ()
+                              (if (eq (char-after) ?\() 2 1))
+              outline-regexp "[A-Z(]"))
 
 (defun shortdoc--goto-section (arg sym &optional reverse)
   (unless (natnump arg)

But then hiding levels made the display pretty weird:


[-- Attachment #2: Type: image/png, Size: 39747 bytes --]

[-- Attachment #3: Type: text/plain, Size: 145 bytes --]


So if we want that, it needs more work.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-14 11:06 ` Lars Ingebrigtsen
@ 2022-02-14 12:23   ` Daniel Mendler
  2022-02-14 14:18     ` Lars Ingebrigtsen
  2022-02-15  7:32   ` Kévin Le Gouguec
  1 sibling, 1 reply; 25+ messages in thread
From: Daniel Mendler @ 2022-02-14 12:23 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 53981

On 2/14/22 12:06, Lars Ingebrigtsen wrote:
> I tried the following:
> ...> But then hiding levels made the display pretty weird:
>
> So if we want that, it needs more work.

I see. This looks indeed not that good due to the newly introduced
`separator-line` face. I use a different setting for the
`separator-line` in my configuration, which has only a height of a
single pixel by using the `:underline` face attribute:

(set-face-attribute 'separator-line nil
  :inherit 'shadow :background nil :underline t :height 1)

With this setting, the separator line generally looks better and less
obtrusive. So we may want to consider using no background and
`:underline t` instead? With outline mode folding the separator line is
still visible, but doesn't disturb the visuals so severely.

Daniel





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-14 12:23   ` Daniel Mendler
@ 2022-02-14 14:18     ` Lars Ingebrigtsen
  2022-02-14 14:29       ` Daniel Mendler
  0 siblings, 1 reply; 25+ messages in thread
From: Lars Ingebrigtsen @ 2022-02-14 14:18 UTC (permalink / raw)
  To: Daniel Mendler; +Cc: 53981

Daniel Mendler <mail@daniel-mendler.de> writes:

> With this setting, the separator line generally looks better and less
> obtrusive. So we may want to consider using no background and
> `:underline t` instead? With outline mode folding the separator line is
> still visible, but doesn't disturb the visuals so severely.

I think the separator line looks fine the way it is, so if we're to
enable outline-minor-mode in that buffer, the outlining will have to be
adjusted to take that into account.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-14 14:18     ` Lars Ingebrigtsen
@ 2022-02-14 14:29       ` Daniel Mendler
  0 siblings, 0 replies; 25+ messages in thread
From: Daniel Mendler @ 2022-02-14 14:29 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 53981

On 2/14/22 15:18, Lars Ingebrigtsen wrote:
>> With this setting, the separator line generally looks better and less
>> obtrusive. So we may want to consider using no background and
>> `:underline t` instead? With outline mode folding the separator line is
>> still visible, but doesn't disturb the visuals so severely.
> 
> I think the separator line looks fine the way it is, so if we're to
> enable outline-minor-mode in that buffer, the outlining will have to be
> adjusted to take that into account.

If you want to keep the separator as is, I am not sure if we can solve
the outline display issue, since it is an artifact of the current
separator face. Maybe it would help to introduce an additional line of
small height after the separator line, such that an outline-folded block
will not end with the separator line?

I like to have good outline support since it also helps with commands
like my `consult-outline` and `counsel-outline`, which can be used to
browse and export a TOC. For me, there is more to outlines than folding
only.

But overall I don't feel strongly about this - it is a minor feature. I
can just keep outline support in my user config in combination with the
single pixel separator lines, which looks better. ;)

Daniel





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-14 11:06 ` Lars Ingebrigtsen
  2022-02-14 12:23   ` Daniel Mendler
@ 2022-02-15  7:32   ` Kévin Le Gouguec
  2022-02-15  9:29     ` Lars Ingebrigtsen
  1 sibling, 1 reply; 25+ messages in thread
From: Kévin Le Gouguec @ 2022-02-15  7:32 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: Daniel Mendler, 53981

Lars Ingebrigtsen <larsi@gnus.org> writes:

> But then hiding levels made the display pretty weird:

Looking at your screenshot, this reminds me of the discussion we're
having on bug#52587?  See in particular the three screenshots in

<https://debbugs.gnu.org/cgi/bugreport.cgi?bug=52587#19>
<<87fsqnvl98.fsf@gmail.com>>

I.e. given this outline buffer:

<https://debbugs.gnu.org/cgi/bugreport.cgi?att=1;filename=unfolded.png;msg=19;bug=52587>

The current folding causes this:

<https://debbugs.gnu.org/cgi/bugreport.cgi?bug=52587;msg=19;filename=folded-current.png;att=3>

Whereas it looks like this would be more useful:

<https://debbugs.gnu.org/cgi/bugreport.cgi?att=5;msg=19;filename=folded-requested.png;bug=52587>

IOW, instead of eliding everything from the heading's end-of-line
(included) to the section's last end-of-line (*excluded*, so its
font-locking clashes with the heading line), we would like to elide
everything *after* the heading's end-of-line (*including* the section's
last end-of-line).

I have not found the time to dig into outline.el to understand how this
could be pulled off yet.  FWIW though, issues such as the one we're
seeing now with shortdoc comfort me in the idea that this is a
fundamental problem with outline.el (although a mostly aesthetic one,
granted).

<tangent>

  I'm also reminded of bug#51016, where we debated whether FORM FEEDs
  belonged in outline-regexp; I'm seeing a pattern with shortdoc's
  separator lines, and I wonder if outline.el should grow a concept of
  "section separators".

  That would allow us to stop conflating FORM FEEDs with level-1
  headings, letting outline-forward-same-level do DTRT, yet keeping the
  ^L displayed even when folding all top-level headings, which IIRC was
  a contentious issue in that bug report

</tangent>





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-15  7:32   ` Kévin Le Gouguec
@ 2022-02-15  9:29     ` Lars Ingebrigtsen
  2022-02-15  9:36       ` Daniel Mendler
  2022-02-16 18:18       ` Juri Linkov
  0 siblings, 2 replies; 25+ messages in thread
From: Lars Ingebrigtsen @ 2022-02-15  9:29 UTC (permalink / raw)
  To: Kévin Le Gouguec; +Cc: Daniel Mendler, 53981

Kévin Le Gouguec <kevin.legouguec@gmail.com> writes:

> I have not found the time to dig into outline.el to understand how this
> could be pulled off yet.  FWIW though, issues such as the one we're
> seeing now with shortdoc comfort me in the idea that this is a
> fundamental problem with outline.el (although a mostly aesthetic one,
> granted).

Yeah, I think it's an issue in outline (that should be fixed).

>   I'm also reminded of bug#51016, where we debated whether FORM FEEDs
>   belonged in outline-regexp; I'm seeing a pattern with shortdoc's
>   separator lines, and I wonder if outline.el should grow a concept of
>   "section separators".
>
>   That would allow us to stop conflating FORM FEEDs with level-1
>   headings, letting outline-forward-same-level do DTRT, yet keeping the
>   ^L displayed even when folding all top-level headings, which IIRC was
>   a contentious issue in that bug report

As previously discussed in some other bug report *vague hand wave*, it
makes no sense to use regexps for outline in generated buffers.  The
functions that generate the buffers knows what's a heading, and should
mark the headings properly (with text properties), and
outline-minor-mode should just react to these text properties in these
buffers.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-15  9:29     ` Lars Ingebrigtsen
@ 2022-02-15  9:36       ` Daniel Mendler
  2022-02-16 18:18       ` Juri Linkov
  1 sibling, 0 replies; 25+ messages in thread
From: Daniel Mendler @ 2022-02-15  9:36 UTC (permalink / raw)
  To: Lars Ingebrigtsen, Kévin Le Gouguec; +Cc: 53981

On 2/15/22 10:29, Lars Ingebrigtsen wrote:
> As previously discussed in some other bug report *vague hand wave*, it
> makes no sense to use regexps for outline in generated buffers.  The
> functions that generate the buffers knows what's a heading, and should
> mark the headings properly (with text properties), and
> outline-minor-mode should just react to these text properties in these
> buffers.

That's a good idea, but only tangentially related to the aesthetic
outline issue with the face. I wanted to have something like this
before, when I attached text properties to headlines. If outline-mode
could automatically find headlines by a text property that would be great!

Daniel





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-15  9:29     ` Lars Ingebrigtsen
  2022-02-15  9:36       ` Daniel Mendler
@ 2022-02-16 18:18       ` Juri Linkov
  2022-02-17 11:43         ` Lars Ingebrigtsen
  1 sibling, 1 reply; 25+ messages in thread
From: Juri Linkov @ 2022-02-16 18:18 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: Daniel Mendler, 53981, Kévin Le Gouguec

[-- Attachment #1: Type: text/plain, Size: 437 bytes --]

> As previously discussed in some other bug report *vague hand wave*, it
> makes no sense to use regexps for outline in generated buffers.  The
> functions that generate the buffers knows what's a heading, and should
> mark the headings properly (with text properties), and
> outline-minor-mode should just react to these text properties in these
> buffers.

That was in https://debbugs.gnu.org/31094#40

Is this a promising direction?


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: outline-search-function.patch --]
[-- Type: text/x-diff, Size: 3086 bytes --]

diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index 658edd6752..63e799a2be 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -1435,7 +1435,19 @@ shortdoc-mode-map
 
 (define-derived-mode shortdoc-mode special-mode "shortdoc"
   "Mode for shortdoc."
-  :interactive nil)
+  :interactive nil
+  (setq-local outline-level (lambda () (if (eq (char-after) ?\() 2 1)))
+  (setq-local outline-search-function
+              (lambda (&optional looking-at)
+                (save-excursion
+                  (let* ((prop-at (if looking-at
+                                      (get-text-property (point) 'shortdoc-section)
+                                    t))
+                         (prop-match (and prop-at (text-property-search-forward 'shortdoc-section))))
+                    (when prop-match
+                      (set-match-data (list (prop-match-beginning prop-match)
+                                            (prop-match-end prop-match)))
+                      t))))))
 
 (defun shortdoc--goto-section (arg sym &optional reverse)
   (unless (natnump arg)
diff --git a/lisp/outline.el b/lisp/outline.el
index 012e219fc3..a282237696 100644
--- a/lisp/outline.el
+++ b/lisp/outline.el
@@ -301,7 +303,9 @@ outline-font-lock-face
   "Return one of `outline-font-lock-faces' for current level."
   (save-excursion
     (goto-char (match-beginning 0))
-    (looking-at outline-regexp)
+    (if outline-search-function
+        (funcall outline-search-function t)
+      (looking-at outline-regexp))
     (aref outline-font-lock-faces
           (% (1- (funcall outline-level))
              (length outline-font-lock-faces)))))
@@ -393,14 +397,19 @@ outline-minor-mode-highlight
   :safe #'symbolp
   :version "28.1")
 
+(defvar outline-search-function nil
+  "Function to search the next outline.
+It should be like `re-search-forward' and `looking-at'.")
+
 (defun outline-minor-mode-highlight-buffer ()
   ;; Fallback to overlays when font-lock is unsupported.
   (save-excursion
     (goto-char (point-min))
     (let ((regexp (concat "^\\(?:" outline-regexp "\\).*$")))
-      (while (re-search-forward regexp nil t)
-        (let ((overlay (make-overlay (match-beginning 0)
-                                     (match-end 0))))
+      (while (if outline-search-function
+                 (funcall outline-search-function)
+               (re-search-forward regexp nil t))
+        (let ((overlay (make-overlay (match-beginning 0) (match-end 0))))
           (overlay-put overlay 'outline-overlay t)
           (when (or (eq outline-minor-mode-highlight 'override)
                     (and (eq outline-minor-mode-highlight t)
@@ -535,7 +544,9 @@ outline-on-heading-p
   (save-excursion
     (beginning-of-line)
     (and (bolp) (or invisible-ok (not (outline-invisible-p)))
-	 (looking-at outline-regexp))))
+	 (if outline-search-function
+             (funcall outline-search-function t)
+           (looking-at outline-regexp)))))
 
 (defun outline-insert-heading ()
   "Insert a new heading at same depth at point."

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-16 18:18       ` Juri Linkov
@ 2022-02-17 11:43         ` Lars Ingebrigtsen
  2022-02-17 13:44           ` Daniel Mendler
  2022-02-17 17:45           ` Juri Linkov
  0 siblings, 2 replies; 25+ messages in thread
From: Lars Ingebrigtsen @ 2022-02-17 11:43 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Daniel Mendler, 53981, Kévin Le Gouguec

Juri Linkov <juri@linkov.net> writes:

> Is this a promising direction?

[...]

> +  (setq-local outline-level (lambda () (if (eq (char-after) ?\() 2 1)))
> +  (setq-local outline-search-function
> +              (lambda (&optional looking-at)
> +                (save-excursion
> +                  (let* ((prop-at (if looking-at
> +                                      (get-text-property (point) 'shortdoc-section)
> +                                    t))
> +                         (prop-match (and prop-at (text-property-search-forward 'shortdoc-section))))
> +                    (when prop-match
> +                      (set-match-data (list (prop-match-beginning prop-match)
> +                                            (prop-match-end prop-match)))
> +                      t))))))

No, I was thinking that modes like this would just put a text property
like `outline-heading' (or even just `heading') on the heading, and then
outline-minor-mode would use that.

I.e., we make modes that generate buffers provide semantics for the data
it's inserted, and then outline-minor-mode reacts to those semantics.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-17 11:43         ` Lars Ingebrigtsen
@ 2022-02-17 13:44           ` Daniel Mendler
  2022-02-17 15:02             ` Lars Ingebrigtsen
  2022-02-17 17:45           ` Juri Linkov
  1 sibling, 1 reply; 25+ messages in thread
From: Daniel Mendler @ 2022-02-17 13:44 UTC (permalink / raw)
  To: Lars Ingebrigtsen, Juri Linkov; +Cc: 53981, Kévin Le Gouguec



On 2/17/22 12:43, Lars Ingebrigtsen wrote:
> Juri Linkov <juri@linkov.net> writes:
> 
>> Is this a promising direction?
> 
> [...]
> 
>> +  (setq-local outline-level (lambda () (if (eq (char-after) ?\() 2 1)))
>> +  (setq-local outline-search-function
>> +              (lambda (&optional looking-at)
>> +                (save-excursion
>> +                  (let* ((prop-at (if looking-at
>> +                                      (get-text-property (point) 'shortdoc-section)
>> +                                    t))
>> +                         (prop-match (and prop-at (text-property-search-forward 'shortdoc-section))))
>> +                    (when prop-match
>> +                      (set-match-data (list (prop-match-beginning prop-match)
>> +                                            (prop-match-end prop-match)))
>> +                      t))))))
> 
> No, I was thinking that modes like this would just put a text property
> like `outline-heading' (or even just `heading') on the heading, and then
> outline-minor-mode would use that.
> 
> I.e., we make modes that generate buffers provide semantics for the data
> it's inserted, and then outline-minor-mode reacts to those semantics.

I think Juri's approach to provide a search function is better, since it
gives more flexibility. At least please don't hard code the
`outline-heading` property. Then one could use different properties and
retroactively enable outline minor mode for modes which don't come with
the outline-heading property. Maybe support a list of properties which
indicate headlines? But at that point a function may just be simpler...

Daniel






^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-17 13:44           ` Daniel Mendler
@ 2022-02-17 15:02             ` Lars Ingebrigtsen
  0 siblings, 0 replies; 25+ messages in thread
From: Lars Ingebrigtsen @ 2022-02-17 15:02 UTC (permalink / raw)
  To: Daniel Mendler; +Cc: Juri Linkov, 53981, Kévin Le Gouguec

Daniel Mendler <mail@daniel-mendler.de> writes:

> I think Juri's approach to provide a search function is better, since it
> gives more flexibility. At least please don't hard code the
> `outline-heading` property. Then one could use different properties and
> retroactively enable outline minor mode for modes which don't come with
> the outline-heading property. Maybe support a list of properties which
> indicate headlines? But at that point a function may just be simpler...

I don't see the point.  We're marking up buffers with semantic
information -- there isn't much point in trying to retrofit a machinery
like that for older packages.

I don't think it's necessary to create a whole machinery around this --
we should design with the future, not the past, in mind.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-17 11:43         ` Lars Ingebrigtsen
  2022-02-17 13:44           ` Daniel Mendler
@ 2022-02-17 17:45           ` Juri Linkov
  2022-02-19 12:49             ` Lars Ingebrigtsen
  1 sibling, 1 reply; 25+ messages in thread
From: Juri Linkov @ 2022-02-17 17:45 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: Daniel Mendler, 53981, Kévin Le Gouguec

> No, I was thinking that modes like this would just put a text property
> like `outline-heading' (or even just `heading') on the heading, and then
> outline-minor-mode would use that.

Should these modes also put the text property `outline-level'?

Then maybe instead of two text properties `outline-heading'=t and
`outline-level'=N, it should be enough to put just `outline-level':

diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index 658edd6752..7bcf331eb9 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -1284,7 +1284,12 @@ shortdoc-display-group
          (unless (bobp)
            (insert "\n"))
          (insert (propertize
-                  (concat (substitute-command-keys data) "\n\n")
+                  (substitute-command-keys data)
+                  'face 'shortdoc-heading
+                  'shortdoc-section t
+                  'outline-level 1))
+         (insert (propertize
+                  "\n\n"
                   'face 'shortdoc-heading
                   'shortdoc-section t)))
         ;; There may be functions not yet defined in the data.
@@ -1307,7 +1312,7 @@ shortdoc--display-function
         (start-section (point))
         arglist-start)
     ;; Function calling convention.
-    (insert (propertize "(" 'shortdoc-function function))
+    (insert (propertize "(" 'shortdoc-function function 'outline-level 2))
     (if (plist-get data :no-manual)
         (insert-text-button
          (symbol-name function)






^ permalink raw reply related	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-17 17:45           ` Juri Linkov
@ 2022-02-19 12:49             ` Lars Ingebrigtsen
  0 siblings, 0 replies; 25+ messages in thread
From: Lars Ingebrigtsen @ 2022-02-19 12:49 UTC (permalink / raw)
  To: Juri Linkov; +Cc: Daniel Mendler, 53981, Kévin Le Gouguec

Juri Linkov <juri@linkov.net> writes:

> Then maybe instead of two text properties `outline-heading'=t and
> `outline-level'=N, it should be enough to put just `outline-level':

Yes, sounds like a good idea to me.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-02-13 22:39 bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode Daniel Mendler
  2022-02-14 11:06 ` Lars Ingebrigtsen
@ 2022-11-08 19:12 ` Juri Linkov
  2022-11-08 19:32   ` Eli Zaretskii
  1 sibling, 1 reply; 25+ messages in thread
From: Juri Linkov @ 2022-11-08 19:12 UTC (permalink / raw)
  To: Daniel Mendler; +Cc: 53981

[-- Attachment #1: Type: text/plain, Size: 761 bytes --]

> The shortdoc buffer currently lacks support for the outline-minor-mode.
> By setting the two variables outline-regexp and outline-level, we can
> unlock this feature. Does it make sense to provide this by default?
>
> (defun shortdoc--outline-level () (if (eq (char-after) ?\() 2 1)))
> (add-hook 'shortdoc-mode-hook
>           (lambda ()
>             (setq-local outline-level #'shortdoc--outline-level
>                         outline-regexp "[A-Z(]")))

Unfortunately, outline-regexp is not a reliable way to find
outline headings.  For this reason currently outlines in apropos
are broken: outline-regexp in apropos-mode is set to "^[^ \n]+",
that matches too many false positives, all blue lines below
are incorrectly identified as outline headings:


[-- Attachment #2: apropos-outline-1.png --]
[-- Type: image/png, Size: 65521 bytes --]

[-- Attachment #3: Type: text/plain, Size: 162 bytes --]


As previously discussed, we need to introduce a new function
to search outline headings.  Using such function, the outlines
are identified with 100% precision:


[-- Attachment #4: apropos-outline-2.png --]
[-- Type: image/png, Size: 31109 bytes --]

[-- Attachment #5: Type: text/plain, Size: 782 bytes --]


Here is a patch that adds 'outline-search-function'.  However,
the requirements for this function arguments are quite non-standard:
its first argument should be a limit that is used in
outline-font-lock-keywords where MATCHER has the argument LIMIT.
Also the same function should be able to search in both directions:
forward and backward.  And the third requirement is that it should be
able also to be used as looking-at without moving point.  In this patch
the second argument HOW supports two values: 'backward' and 'looking-at'.
But this could be split to two separate boolean arguments,
this is not the final patch.  Also another optional argument
could be added to define an arbitrary property to search.

Then here the same function is used for apropos-mode and shortdoc:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: outline-search-function.patch --]
[-- Type: text/x-diff, Size: 12488 bytes --]

diff --git a/lisp/apropos.el b/lisp/apropos.el
index 624c29cb410..5b7fe4cb23a 100644
--- a/lisp/apropos.el
+++ b/lisp/apropos.el
@@ -493,7 +493,7 @@ apropos-mode
 \\{apropos-mode-map}"
   (make-local-variable 'apropos--current)
   (setq-local revert-buffer-function #'apropos--revert-buffer)
-  (setq-local outline-regexp "^[^ \n]+"
+  (setq-local outline-search-function #'outline-search-level-prop
               outline-level (lambda () 1)
               outline-minor-mode-cycle t
               outline-minor-mode-highlight t
@@ -1188,7 +1188,8 @@ apropos-print
 	  (insert-text-button (symbol-name symbol)
 			      'type 'apropos-symbol
 			      'skip apropos-multi-type
-			      'face 'apropos-symbol)
+			      'face 'apropos-symbol
+			      'outline-level 1)
 	  (setq button-end (point))
 	  (if (and (eq apropos-sort-by-scores 'verbose)
 		   (cadr apropos-item))
diff --git a/lisp/outline.el b/lisp/outline.el
index a646f71db8b..442d51b71bc 100644
--- a/lisp/outline.el
+++ b/lisp/outline.el
@@ -59,6 +59,14 @@ outline-heading-end-regexp
 in the file it applies to.")
 ;;;###autoload(put 'outline-heading-end-regexp 'safe-local-variable 'stringp)
 
+(defvar outline-search-function nil
+  "Function to search the next outline heading.
+The function is called with two arguments: the limit of the search
+and the optional argument for the backward search; it should return
+non-nil, move point (to the end of the buffer when search fails),
+and set match-data appropriately if it succeeds;
+like re-search-forward with `outline-regexp' would.")
+
 (defvar outline-mode-prefix-map
   (let ((map (make-sparse-keymap)))
     (define-key map "@" 'outline-mark-subtree)
@@ -233,7 +241,8 @@ outline-mode-map
 (defvar outline-font-lock-keywords
   '(
     ;; Highlight headings according to the level.
-    (eval . (list (concat "^\\(?:" outline-regexp "\\).*")
+    (eval . (list (or outline-search-function
+                      (concat "^\\(?:" outline-regexp "\\).*"))
                   0 '(if outline-minor-mode
                          (if outline-minor-mode-highlight
                              (list 'face (outline-font-lock-face)))
@@ -366,7 +375,9 @@ outline-font-lock-face
   "Return one of `outline-font-lock-faces' for current level."
   (save-excursion
     (goto-char (match-beginning 0))
-    (looking-at outline-regexp)
+    (if outline-search-function
+        (funcall outline-search-function nil 'looking-at)
+      (looking-at outline-regexp))
     (aref outline-font-lock-faces
           (% (1- (funcall outline-level))
              (length outline-font-lock-faces)))))
@@ -474,16 +485,17 @@ outline-minor-mode-highlight-buffer
   ;; Fallback to overlays when font-lock is unsupported.
   (save-excursion
     (goto-char (point-min))
-    (let ((regexp (concat "^\\(?:" outline-regexp "\\).*$")))
-      (while (re-search-forward regexp nil t)
-        (let ((overlay (make-overlay (match-beginning 0) (match-end 0))))
-          (overlay-put overlay 'outline-highlight t)
-          ;; FIXME: Is it possible to override all underlying face attributes?
-          (when (or (memq outline-minor-mode-highlight '(append override))
-                    (and (eq outline-minor-mode-highlight t)
-                         (not (get-text-property (match-beginning 0) 'face))))
-            (overlay-put overlay 'face (outline-font-lock-face))))
-        (goto-char (match-end 0))))))
+    (while (if outline-search-function
+               (funcall outline-search-function)
+             (re-search-forward outline-regexp nil t))
+      (let ((overlay (make-overlay (match-beginning 0) (pos-eol))))
+        (overlay-put overlay 'outline-highlight t)
+        ;; FIXME: Is it possible to override all underlying face attributes?
+        (when (or (memq outline-minor-mode-highlight '(append override))
+                  (and (eq outline-minor-mode-highlight t)
+                       (not (get-text-property (match-beginning 0) 'face))))
+          (overlay-put overlay 'face (outline-font-lock-face))))
+      (move-end-of-line 1))))
 
 ;;;###autoload
 (define-minor-mode outline-minor-mode
@@ -592,26 +604,32 @@ outline-next-preface
   "Skip forward to just before the next heading line.
 If there's no following heading line, stop before the newline
 at the end of the buffer."
-  (if (re-search-forward (concat "\n\\(?:" outline-regexp "\\)")
-			 nil 'move)
-      (goto-char (match-beginning 0)))
-  (if (and (bolp) (or outline-blank-line (eobp)) (not (bobp)))
-      (forward-char -1)))
+  (when (if outline-search-function
+            (funcall outline-search-function)
+          (re-search-forward (concat "\n\\(?:" outline-regexp "\\)")
+			     nil 'move))
+    (goto-char (match-beginning 0)))
+  (when (and (bolp) (or outline-blank-line (eobp)) (not (bobp)))
+    (forward-char -1)))
 
 (defun outline-next-heading ()
   "Move to the next (possibly invisible) heading line."
   (interactive)
   ;; Make sure we don't match the heading we're at.
-  (if (and (bolp) (not (eobp))) (forward-char 1))
-  (if (re-search-forward (concat "^\\(?:" outline-regexp "\\)")
-			 nil 'move)
-      (goto-char (match-beginning 0))))
+  (when (and (bolp) (not (eobp))) (forward-char 1))
+  (when (if outline-search-function
+            (funcall outline-search-function)
+          (re-search-forward (concat "^\\(?:" outline-regexp "\\)")
+			     nil 'move))
+    (goto-char (match-beginning 0))))
 
 (defun outline-previous-heading ()
   "Move to the previous (possibly invisible) heading line."
   (interactive)
-  (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
-		      nil 'move))
+  (if outline-search-function
+      (funcall outline-search-function nil 'backward)
+    (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
+		        nil 'move)))
 
 (defsubst outline-invisible-p (&optional pos)
   "Non-nil if the character after POS has outline invisible property.
@@ -628,8 +646,10 @@ outline-back-to-heading
       (let (found)
 	(save-excursion
 	  (while (not found)
-	    (or (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
-				    nil t)
+	    (or (if outline-search-function
+                    (funcall outline-search-function nil 'backward)
+                  (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
+				      nil t))
                 (signal 'outline-before-first-heading nil))
 	    (setq found (and (or invisible-ok (not (outline-invisible-p)))
 			     (point)))))
@@ -642,7 +662,9 @@ outline-on-heading-p
   (save-excursion
     (beginning-of-line)
     (and (bolp) (or invisible-ok (not (outline-invisible-p)))
-	 (looking-at outline-regexp))))
+	 (if outline-search-function
+             (funcall outline-search-function nil 'looking-at)
+           (looking-at outline-regexp)))))
 
 (defun outline-insert-heading ()
   "Insert a new heading at same depth at point."
@@ -754,7 +776,9 @@ outline-demote
 		      (while (and (progn (outline-next-heading) (not (eobp)))
 				  (<= (funcall outline-level) level))))
 		    (unless (eobp)
-		      (looking-at outline-regexp)
+		      (if outline-search-function
+                          (funcall outline-search-function nil 'looking-at)
+                        (looking-at outline-regexp))
 		      (match-string-no-properties 0))))
                 ;; Bummer!! There is no higher-level heading in the buffer.
                 (outline-invent-heading head nil))))
@@ -805,7 +829,9 @@ outline-map-region
   (save-excursion
     (setq end (copy-marker end))
     (goto-char beg)
-    (when (re-search-forward (concat "^\\(?:" outline-regexp "\\)") end t)
+    (when (if outline-search-function
+              (funcall outline-search-function)
+            (re-search-forward (concat "^\\(?:" outline-regexp "\\)") end t))
       (goto-char (match-beginning 0))
       (funcall fun)
       (while (and (progn
@@ -877,17 +903,21 @@ outline-next-visible-heading
     (while (and (not (bobp)) (< arg 0))
       (while (and (not (bobp))
 		  (setq found-heading-p
-			(re-search-backward
-			 (concat "^\\(?:" outline-regexp "\\)")
-			 nil 'move))
+			(if outline-search-function
+                            (funcall outline-search-function nil 'backward)
+                          (re-search-backward
+			   (concat "^\\(?:" outline-regexp "\\)")
+			   nil 'move)))
 		  (outline-invisible-p)))
       (setq arg (1+ arg)))
     (while (and (not (eobp)) (> arg 0))
       (while (and (not (eobp))
 		  (setq found-heading-p
-			(re-search-forward
-			 (concat "^\\(?:" outline-regexp "\\)")
-			 nil 'move))
+			(if outline-search-function
+                            (funcall outline-search-function)
+                          (re-search-forward
+			   (concat "^\\(?:" outline-regexp "\\)")
+			   nil 'move)))
 		  (outline-invisible-p (match-beginning 0))))
       (setq arg (1- arg)))
     (if found-heading-p (beginning-of-line))))
@@ -1108,7 +1138,9 @@ outline-hide-sublevels
 		(cond
 		 (current-prefix-arg (prefix-numeric-value current-prefix-arg))
 		 ((save-excursion (beginning-of-line)
-				  (looking-at outline-regexp))
+				  (if outline-search-function
+                                      (funcall outline-search-function nil 'looking-at)
+                                    (looking-at outline-regexp)))
 		  (funcall outline-level))
 		 (t 1))))
   (if (< levels 1)
@@ -1255,7 +1287,9 @@ outline-up-heading
 	  (setq level (funcall outline-level)))
 	(setq start-level level))
       (setq arg (- arg 1))))
-  (looking-at outline-regexp))
+  (if outline-search-function
+      (funcall outline-search-function nil 'looking-at)
+    (looking-at outline-regexp)))
 
 (defun outline-forward-same-level (arg)
   "Move forward to the ARG'th subheading at same level as this one.
@@ -1346,6 +1380,35 @@ outline-headers-as-kill
                     (insert "\n\n"))))))
           (kill-new (buffer-string)))))))
 
+\f
+;;; Search text-property for outline headings
+
+(defun outline-search-level-prop (&optional limit how)
+  (let* ((prop 'outline-level)
+         (prop-at
+          (if (eq how 'looking-at)
+              (get-text-property (point) prop)
+            (when (get-text-property (point) prop)
+              ;; Go to the end of the current heading
+              (if (eq how 'backward)
+                  (text-property-search-backward prop)
+                (text-property-search-forward prop)))
+            t))
+         (prop-match
+          (when prop-at
+            (if (eq how 'backward)
+                (text-property-search-backward prop)
+              (text-property-search-forward prop)))))
+    (if prop-match
+        (let ((beg (prop-match-beginning prop-match))
+              (end (prop-match-end prop-match)))
+          (if (or (null limit) (< end limit))
+              (set-match-data (list beg end))
+            (goto-char (or limit (point-max))))
+          t)
+      (goto-char (point-max))
+      nil)))
+
 \f
 ;;; Initial visibility
 
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index dbac03432c1..d3c824a4e93 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -1374,7 +1374,12 @@ shortdoc-display-group
          (unless (bobp)
            (insert "\n"))
          (insert (propertize
-                  (concat (substitute-command-keys data) "\n\n")
+                  (substitute-command-keys data)
+                  'face 'shortdoc-heading
+                  'shortdoc-section t
+                  'outline-level 1))
+         (insert (propertize
+                  "\n\n"
                   'face 'shortdoc-heading
                   'shortdoc-section t)))
         ;; There may be functions not yet defined in the data.
@@ -1397,7 +1402,7 @@ shortdoc--display-function
         (start-section (point))
         arglist-start)
     ;; Function calling convention.
-    (insert (propertize "(" 'shortdoc-function function))
+    (insert (propertize "(" 'shortdoc-function function 'outline-level 2))
     (if (plist-get data :no-manual)
         (insert-text-button
          (symbol-name function)
@@ -1531,7 +1536,9 @@ shortdoc-mode-map
 
 (define-derived-mode shortdoc-mode special-mode "shortdoc"
   "Mode for shortdoc."
-  :interactive nil)
+  :interactive nil
+  (setq-local outline-search-function #'outline-search-level-prop)
+  (setq-local outline-level (lambda () (get-text-property (point) 'outline-level))))
 
 (defun shortdoc--goto-section (arg sym &optional reverse)
   (unless (natnump arg)

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-11-08 19:12 ` Juri Linkov
@ 2022-11-08 19:32   ` Eli Zaretskii
  2022-11-09 17:17     ` Juri Linkov
  2022-11-09 17:24     ` Juri Linkov
  0 siblings, 2 replies; 25+ messages in thread
From: Eli Zaretskii @ 2022-11-08 19:32 UTC (permalink / raw)
  To: Juri Linkov; +Cc: mail, 53981

> Cc: 53981@debbugs.gnu.org
> From: Juri Linkov <juri@linkov.net>
> Date: Tue, 08 Nov 2022 21:12:45 +0200
> 
> @@ -474,16 +485,17 @@ outline-minor-mode-highlight-buffer
>    ;; Fallback to overlays when font-lock is unsupported.
>    (save-excursion
>      (goto-char (point-min))
> -    (let ((regexp (concat "^\\(?:" outline-regexp "\\).*$")))
> -      (while (re-search-forward regexp nil t)
> -        (let ((overlay (make-overlay (match-beginning 0) (match-end 0))))
> -          (overlay-put overlay 'outline-highlight t)
> -          ;; FIXME: Is it possible to override all underlying face attributes?
> -          (when (or (memq outline-minor-mode-highlight '(append override))
> -                    (and (eq outline-minor-mode-highlight t)
> -                         (not (get-text-property (match-beginning 0) 'face))))
> -            (overlay-put overlay 'face (outline-font-lock-face))))
> -        (goto-char (match-end 0))))))
> +    (while (if outline-search-function
> +               (funcall outline-search-function)
> +             (re-search-forward outline-regexp nil t))

This changes the effect of the code because the new code searches for
a different regexp.

> @@ -877,17 +903,21 @@ outline-next-visible-heading
>      (while (and (not (bobp)) (< arg 0))
>        (while (and (not (bobp))
>  		  (setq found-heading-p
> -			(re-search-backward
> -			 (concat "^\\(?:" outline-regexp "\\)")
> -			 nil 'move))
> +			(if outline-search-function
> +                            (funcall outline-search-function nil 'backward)
> +                          (re-search-backward
> +			   (concat "^\\(?:" outline-regexp "\\)")
> +			   nil 'move)))
>  		  (outline-invisible-p)))
>        (setq arg (1+ arg)))
>      (while (and (not (eobp)) (> arg 0))
>        (while (and (not (eobp))
>  		  (setq found-heading-p
> -			(re-search-forward
> -			 (concat "^\\(?:" outline-regexp "\\)")
> -			 nil 'move))
> +			(if outline-search-function
> +                            (funcall outline-search-function)
> +                          (re-search-forward
> +			   (concat "^\\(?:" outline-regexp "\\)")
> +			   nil 'move)))
>  		  (outline-invisible-p (match-beginning 0))))

These two loops cons a new string each iteration.  (So did the
original code, but if we are touching this, might as well fix that.)





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-11-08 19:32   ` Eli Zaretskii
@ 2022-11-09 17:17     ` Juri Linkov
  2022-11-16 19:14       ` Juri Linkov
  2022-11-09 17:24     ` Juri Linkov
  1 sibling, 1 reply; 25+ messages in thread
From: Juri Linkov @ 2022-11-09 17:17 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: mail, 53981

[-- Attachment #1: Type: text/plain, Size: 746 bytes --]

>> +    (while (if outline-search-function
>> +               (funcall outline-search-function)
>> +             (re-search-forward outline-regexp nil t))
>
> This changes the effect of the code because the new code searches for
> a different regexp.

Sorry, this was an attempt to unify code branches,
but this change remained untested.  Now fixed below.

>> +			(if outline-search-function
>> +                            (funcall outline-search-function)
>> +                          (re-search-forward
>> +			   (concat "^\\(?:" outline-regexp "\\)")
>> +			   nil 'move)))
>
> These two loops cons a new string each iteration.  (So did the
> original code, but if we are touching this, might as well fix that.)

This is optimized as well:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: outline-search-level.patch --]
[-- Type: text/x-diff, Size: 11904 bytes --]

diff --git a/lisp/apropos.el b/lisp/apropos.el
index 624c29cb410..02a32a2e7ce 100644
--- a/lisp/apropos.el
+++ b/lisp/apropos.el
@@ -493,7 +493,7 @@ apropos-mode
 \\{apropos-mode-map}"
   (make-local-variable 'apropos--current)
   (setq-local revert-buffer-function #'apropos--revert-buffer)
-  (setq-local outline-regexp "^[^ \n]+"
+  (setq-local outline-search-function #'outline-search-level
               outline-level (lambda () 1)
               outline-minor-mode-cycle t
               outline-minor-mode-highlight t
@@ -1188,7 +1188,8 @@ apropos-print
 	  (insert-text-button (symbol-name symbol)
 			      'type 'apropos-symbol
 			      'skip apropos-multi-type
-			      'face 'apropos-symbol)
+			      'face 'apropos-symbol
+			      'outline-level 1)
 	  (setq button-end (point))
 	  (if (and (eq apropos-sort-by-scores 'verbose)
 		   (cadr apropos-item))
diff --git a/lisp/outline.el b/lisp/outline.el
index a646f71db8b..fcac9d1950b 100644
--- a/lisp/outline.el
+++ b/lisp/outline.el
@@ -59,6 +59,14 @@ outline-heading-end-regexp
 in the file it applies to.")
 ;;;###autoload(put 'outline-heading-end-regexp 'safe-local-variable 'stringp)
 
+(defvar outline-search-function nil
+  "Function to search the next outline heading.
+The function is called with two arguments: the limit of the search
+and the optional argument for the backward search; it should return
+non-nil, move point (to the end of the buffer when search fails),
+and set match-data appropriately if it succeeds;
+like re-search-forward with `outline-regexp' would.")
+
 (defvar outline-mode-prefix-map
   (let ((map (make-sparse-keymap)))
     (define-key map "@" 'outline-mark-subtree)
@@ -233,7 +241,8 @@ outline-mode-map
 (defvar outline-font-lock-keywords
   '(
     ;; Highlight headings according to the level.
-    (eval . (list (concat "^\\(?:" outline-regexp "\\).*")
+    (eval . (list (or outline-search-function
+                      (concat "^\\(?:" outline-regexp "\\).*"))
                   0 '(if outline-minor-mode
                          (if outline-minor-mode-highlight
                              (list 'face (outline-font-lock-face)))
@@ -366,7 +375,9 @@ outline-font-lock-face
   "Return one of `outline-font-lock-faces' for current level."
   (save-excursion
     (goto-char (match-beginning 0))
-    (looking-at outline-regexp)
+    (if outline-search-function
+        (funcall outline-search-function nil nil t)
+      (looking-at outline-regexp))
     (aref outline-font-lock-faces
           (% (1- (funcall outline-level))
              (length outline-font-lock-faces)))))
@@ -474,8 +485,11 @@ outline-minor-mode-highlight-buffer
   ;; Fallback to overlays when font-lock is unsupported.
   (save-excursion
     (goto-char (point-min))
-    (let ((regexp (concat "^\\(?:" outline-regexp "\\).*$")))
-      (while (re-search-forward regexp nil t)
+    (let ((regexp (unless outline-search-function
+                    (concat "^\\(?:" outline-regexp "\\).*$"))))
+      (while (if outline-search-function
+                 (funcall outline-search-function)
+               (re-search-forward regexp nil t))
         (let ((overlay (make-overlay (match-beginning 0) (match-end 0))))
           (overlay-put overlay 'outline-highlight t)
           ;; FIXME: Is it possible to override all underlying face attributes?
@@ -592,26 +606,32 @@ outline-next-preface
   "Skip forward to just before the next heading line.
 If there's no following heading line, stop before the newline
 at the end of the buffer."
-  (if (re-search-forward (concat "\n\\(?:" outline-regexp "\\)")
-			 nil 'move)
-      (goto-char (match-beginning 0)))
-  (if (and (bolp) (or outline-blank-line (eobp)) (not (bobp)))
-      (forward-char -1)))
+  (when (if outline-search-function
+            (funcall outline-search-function)
+          (re-search-forward (concat "\n\\(?:" outline-regexp "\\)")
+			     nil 'move))
+    (goto-char (match-beginning 0)))
+  (when (and (bolp) (or outline-blank-line (eobp)) (not (bobp)))
+    (forward-char -1)))
 
 (defun outline-next-heading ()
   "Move to the next (possibly invisible) heading line."
   (interactive)
   ;; Make sure we don't match the heading we're at.
-  (if (and (bolp) (not (eobp))) (forward-char 1))
-  (if (re-search-forward (concat "^\\(?:" outline-regexp "\\)")
-			 nil 'move)
-      (goto-char (match-beginning 0))))
+  (when (and (bolp) (not (eobp))) (forward-char 1))
+  (when (if outline-search-function
+            (funcall outline-search-function)
+          (re-search-forward (concat "^\\(?:" outline-regexp "\\)")
+			     nil 'move))
+    (goto-char (match-beginning 0))))
 
 (defun outline-previous-heading ()
   "Move to the previous (possibly invisible) heading line."
   (interactive)
-  (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
-		      nil 'move))
+  (if outline-search-function
+      (funcall outline-search-function nil t)
+    (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
+		        nil 'move)))
 
 (defsubst outline-invisible-p (&optional pos)
   "Non-nil if the character after POS has outline invisible property.
@@ -628,8 +648,10 @@ outline-back-to-heading
       (let (found)
 	(save-excursion
 	  (while (not found)
-	    (or (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
-				    nil t)
+	    (or (if outline-search-function
+                    (funcall outline-search-function nil t)
+                  (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
+				      nil t))
                 (signal 'outline-before-first-heading nil))
 	    (setq found (and (or invisible-ok (not (outline-invisible-p)))
 			     (point)))))
@@ -642,7 +664,9 @@ outline-on-heading-p
   (save-excursion
     (beginning-of-line)
     (and (bolp) (or invisible-ok (not (outline-invisible-p)))
-	 (looking-at outline-regexp))))
+	 (if outline-search-function
+             (funcall outline-search-function nil nil t)
+           (looking-at outline-regexp)))))
 
 (defun outline-insert-heading ()
   "Insert a new heading at same depth at point."
@@ -754,7 +778,9 @@ outline-demote
 		      (while (and (progn (outline-next-heading) (not (eobp)))
 				  (<= (funcall outline-level) level))))
 		    (unless (eobp)
-		      (looking-at outline-regexp)
+		      (if outline-search-function
+                          (funcall outline-search-function nil nil t)
+                        (looking-at outline-regexp))
 		      (match-string-no-properties 0))))
                 ;; Bummer!! There is no higher-level heading in the buffer.
                 (outline-invent-heading head nil))))
@@ -805,7 +831,9 @@ outline-map-region
   (save-excursion
     (setq end (copy-marker end))
     (goto-char beg)
-    (when (re-search-forward (concat "^\\(?:" outline-regexp "\\)") end t)
+    (when (if outline-search-function
+              (funcall outline-search-function)
+            (re-search-forward (concat "^\\(?:" outline-regexp "\\)") end t))
       (goto-char (match-beginning 0))
       (funcall fun)
       (while (and (progn
@@ -873,21 +901,23 @@ outline-next-visible-heading
   (if (< arg 0)
       (beginning-of-line)
     (end-of-line))
-  (let (found-heading-p)
+  (let ((regexp (unless outline-search-function
+                  (concat "^\\(?:" outline-regexp "\\)")))
+        found-heading-p)
     (while (and (not (bobp)) (< arg 0))
       (while (and (not (bobp))
 		  (setq found-heading-p
-			(re-search-backward
-			 (concat "^\\(?:" outline-regexp "\\)")
-			 nil 'move))
+			(if outline-search-function
+                            (funcall outline-search-function nil t)
+                          (re-search-backward regexp nil 'move)))
 		  (outline-invisible-p)))
       (setq arg (1+ arg)))
     (while (and (not (eobp)) (> arg 0))
       (while (and (not (eobp))
 		  (setq found-heading-p
-			(re-search-forward
-			 (concat "^\\(?:" outline-regexp "\\)")
-			 nil 'move))
+			(if outline-search-function
+                            (funcall outline-search-function)
+                          (re-search-forward regexp nil 'move)))
 		  (outline-invisible-p (match-beginning 0))))
       (setq arg (1- arg)))
     (if found-heading-p (beginning-of-line))))
@@ -1108,7 +1138,9 @@ outline-hide-sublevels
 		(cond
 		 (current-prefix-arg (prefix-numeric-value current-prefix-arg))
 		 ((save-excursion (beginning-of-line)
-				  (looking-at outline-regexp))
+				  (if outline-search-function
+                                      (funcall outline-search-function nil nil t)
+                                    (looking-at outline-regexp)))
 		  (funcall outline-level))
 		 (t 1))))
   (if (< levels 1)
@@ -1255,7 +1287,9 @@ outline-up-heading
 	  (setq level (funcall outline-level)))
 	(setq start-level level))
       (setq arg (- arg 1))))
-  (looking-at outline-regexp))
+  (if outline-search-function
+      (funcall outline-search-function nil nil t)
+    (looking-at outline-regexp)))
 
 (defun outline-forward-same-level (arg)
   "Move forward to the ARG'th subheading at same level as this one.
@@ -1346,6 +1380,38 @@ outline-headers-as-kill
                     (insert "\n\n"))))))
           (kill-new (buffer-string)))))))
 
+\f
+;;; Search text-property for outline headings
+
+;;;###autoload
+(defun outline-search-level (&optional limit backward looking-at)
+  (outline-search-text-property 'outline-level limit backward looking-at))
+
+(defun outline-search-text-property (prop &optional limit backward looking-at)
+  (let* ((prop-at
+          (if looking-at
+              (get-text-property (point) prop)
+            (when (get-text-property (point) prop)
+              ;; Go to the end of the current heading
+              (if backward
+                  (text-property-search-backward prop)
+                (text-property-search-forward prop)))
+            t))
+         (prop-match
+          (when prop-at
+            (if backward
+                (text-property-search-backward prop)
+              (text-property-search-forward prop)))))
+    (if prop-match
+        (let ((beg (prop-match-beginning prop-match))
+              (end (prop-match-end prop-match)))
+          (if (or (null limit) (< end limit))
+              (set-match-data (list beg end))
+            (goto-char (or limit (point-max))))
+          t)
+      (goto-char (point-max))
+      nil)))
+
 \f
 ;;; Initial visibility
 
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index dbac03432c1..18b758a9ca3 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -1374,7 +1374,12 @@ shortdoc-display-group
          (unless (bobp)
            (insert "\n"))
          (insert (propertize
-                  (concat (substitute-command-keys data) "\n\n")
+                  (substitute-command-keys data)
+                  'face 'shortdoc-heading
+                  'shortdoc-section t
+                  'outline-level 1))
+         (insert (propertize
+                  "\n\n"
                   'face 'shortdoc-heading
                   'shortdoc-section t)))
         ;; There may be functions not yet defined in the data.
@@ -1397,7 +1402,7 @@ shortdoc--display-function
         (start-section (point))
         arglist-start)
     ;; Function calling convention.
-    (insert (propertize "(" 'shortdoc-function function))
+    (insert (propertize "(" 'shortdoc-function function 'outline-level 2))
     (if (plist-get data :no-manual)
         (insert-text-button
          (symbol-name function)
@@ -1531,7 +1536,9 @@ shortdoc-mode-map
 
 (define-derived-mode shortdoc-mode special-mode "shortdoc"
   "Mode for shortdoc."
-  :interactive nil)
+  :interactive nil
+  (setq-local outline-search-function #'outline-search-level)
+  (setq-local outline-level (lambda () (get-text-property (point) 'outline-level))))
 
 (defun shortdoc--goto-section (arg sym &optional reverse)
   (unless (natnump arg)

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-11-08 19:32   ` Eli Zaretskii
  2022-11-09 17:17     ` Juri Linkov
@ 2022-11-09 17:24     ` Juri Linkov
  2022-11-09 17:34       ` Eli Zaretskii
  1 sibling, 1 reply; 25+ messages in thread
From: Juri Linkov @ 2022-11-09 17:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: mail, 53981

[-- Attachment #1: Type: text/plain, Size: 287 bytes --]

> These two loops cons a new string each iteration.  (So did the
> original code, but if we are touching this, might as well fix that.)

BTW, the patch uses functions from text-property-search.el.
But these useful functions are still not autoloaded.
Here is the patch to autoload them:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: text-property-search-autoload.patch --]
[-- Type: text/x-diff, Size: 2131 bytes --]

diff --git a/lisp/emacs-lisp/text-property-search.el b/lisp/emacs-lisp/text-property-search.el
index d41222bdbf1..7e78fdfe7d6 100644
--- a/lisp/emacs-lisp/text-property-search.el
+++ b/lisp/emacs-lisp/text-property-search.el
@@ -26,9 +26,12 @@
 
 (eval-when-compile (require 'cl-lib))
 
+;;;###autoload (autoload 'prop-match-beginning "text-property-search")
+;;;###autoload (autoload 'prop-match-end "text-property-search")
 (cl-defstruct (prop-match)
   beginning end value)
 
+;;;###autoload
 (defun text-property-search-forward (property &optional value predicate
                                               not-current)
   "Search for the next region of text where PREDICATE is true.
@@ -131,7 +134,7 @@ text-property--find-end-forward
                      :end end
                      :value (get-text-property start property))))
 
-
+;;;###autoload
 (defun text-property-search-backward (property &optional value predicate
                                                not-current)
   "Search for the previous region of text whose PROPERTY matches VALUE.
diff --git a/lisp/international/mule-cmds.el b/lisp/international/mule-cmds.el
index 61a26b504c8..5a27dcd4c27 100644
--- a/lisp/international/mule-cmds.el
+++ b/lisp/international/mule-cmds.el
@@ -3284,10 +3284,6 @@ reorder-starters
 (defvar reorder-enders "[\u202C\u2069]+\\|\n"
   "Regular expression for characters that end forced-reordered text.")
 
-(autoload 'text-property-search-forward "text-property-search")
-(autoload 'prop-match-beginning "text-property-search")
-(autoload 'prop-match-end "text-property-search")
-
 (defun highlight-confusing-reorderings (beg end &optional remove)
   "Highlight text in region that might be bidi-reordered in suspicious ways.
 This command find and highlights segments of buffer text that could have
diff --git a/lisp/bookmark.el b/lisp/bookmark.el
index b57ad12986d..d0a14b0cebf 100644
--- a/lisp/bookmark.el
+++ b/lisp/bookmark.el
@@ -34,7 +34,6 @@
 
 (require 'pp)
 (require 'tabulated-list)
-(require 'text-property-search)
 (require 'fringe) ; for builds --without-x
 (eval-when-compile (require 'cl-lib))
 

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-11-09 17:24     ` Juri Linkov
@ 2022-11-09 17:34       ` Eli Zaretskii
  2022-11-09 19:47         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  0 siblings, 1 reply; 25+ messages in thread
From: Eli Zaretskii @ 2022-11-09 17:34 UTC (permalink / raw)
  To: Juri Linkov, Stefan Monnier; +Cc: mail, 53981

> From: Juri Linkov <juri@linkov.net>
> Cc: mail@daniel-mendler.de,  53981@debbugs.gnu.org
> Date: Wed, 09 Nov 2022 19:24:32 +0200
> 
> BTW, the patch uses functions from text-property-search.el.
> But these useful functions are still not autoloaded.
> Here is the patch to autoload them:

I don't necessarily disagree, but do we have any policies or
guidelines regarding when to autoload a function?  It saves us a
'require', but what we "gain" instead is a (small) inflation of the
base memory footprint of the Emacs process.  So it isn't free.

Lars, Stefan, any comments?





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-11-09 17:34       ` Eli Zaretskii
@ 2022-11-09 19:47         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-11-09 20:09           ` Eli Zaretskii
  0 siblings, 1 reply; 25+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-11-09 19:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: mail, 53981, Juri Linkov

>> BTW, the patch uses functions from text-property-search.el.
>> But these useful functions are still not autoloaded.
>> Here is the patch to autoload them:
>
> I don't necessarily disagree, but do we have any policies or
> guidelines regarding when to autoload a function?  It saves us a
> 'require', but what we "gain" instead is a (small) inflation of the
> base memory footprint of the Emacs process.  So it isn't free.
>
> Lars, Stefan, any comments?

For interactive functions, it's usually decided by whether the command
can be useful before the package is loaded (i,e,. usually an entry
point to the package).

For functions (i.e. exported from what is basically a library), the same
kind of tradeoff applies:

- is it likely that this one autoload will let other packages use this
  library without a `require` at all (e.g. `define-inline`), or will we
  end up needing N autoloads anyway?
- how commonly is this library used (i.e. is it worth carrying the
  N autoloads in every Emacs session, compared to having to write
  `require` in a handful of files).


        Stefan






^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-11-09 19:47         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-11-09 20:09           ` Eli Zaretskii
  2022-11-09 20:14             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-11-10  7:42             ` Juri Linkov
  0 siblings, 2 replies; 25+ messages in thread
From: Eli Zaretskii @ 2022-11-09 20:09 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: mail, 53981, juri

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Juri Linkov <juri@linkov.net>,  mail@daniel-mendler.de,
>   53981@debbugs.gnu.org
> Date: Wed, 09 Nov 2022 14:47:56 -0500
> 
> - is it likely that this one autoload will let other packages use this
>   library without a `require` at all (e.g. `define-inline`), or will we
>   end up needing N autoloads anyway?

I don't understand this.

> - how commonly is this library used (i.e. is it worth carrying the
>   N autoloads in every Emacs session, compared to having to write
>   `require` in a handful of files).

The answer to this one is that we currently have just 2 packages that
require this library.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-11-09 20:09           ` Eli Zaretskii
@ 2022-11-09 20:14             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2022-11-10  7:42             ` Juri Linkov
  1 sibling, 0 replies; 25+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2022-11-09 20:14 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: mail, 53981, juri

>> - is it likely that this one autoload will let other packages use this
>>   library without a `require` at all (e.g. `define-inline`), or will we
>>   end up needing N autoloads anyway?
> I don't understand this.

If the library defines N functions and we'd end up needing to autoload
almost all of them because none of them is more of an "entry point" to
the library than any other, then `require` is usually preferable.

In contrast, if most of the functions in the library are only used
internally, or only after some other function in the library has been
called, then we just need a small number of autoloads for the rare few
entry points, making it more worthwhile.

>> - how commonly is this library used (i.e. is it worth carrying the
>>   N autoloads in every Emacs session, compared to having to write
>>   `require` in a handful of files).
>
> The answer to this one is that we currently have just 2 packages that
> require this library.

Then I'd go with `require`.


        Stefan






^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-11-09 20:09           ` Eli Zaretskii
  2022-11-09 20:14             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2022-11-10  7:42             ` Juri Linkov
  1 sibling, 0 replies; 25+ messages in thread
From: Juri Linkov @ 2022-11-10  7:42 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: mail, 53981, Stefan Monnier

>> - how commonly is this library used (i.e. is it worth carrying the
>>   N autoloads in every Emacs session, compared to having to write
>>   `require` in a handful of files).
>
> The answer to this one is that we currently have just 2 packages that
> require this library.

I counted more:

- lisp/emacs-lisp/multisession.el
- lisp/emacs-lisp/shortdoc.el
- lisp/emacs-lisp/vtable.el
- lisp/gnus/gnus-util.el
- lisp/help.el
- lisp/image/image-crop.el
- lisp/international/mule-cmds.el
- lisp/net/eww.el
- lisp/net/shr.el
- lisp/net/tramp-crypt.el
- lisp/progmodes/compile.el
- lisp/textmodes/enriched.el
- lisp/textmodes/string-edit.el

All they use text-property-search-forward and text-property-search-backward
as entry points.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-11-09 17:17     ` Juri Linkov
@ 2022-11-16 19:14       ` Juri Linkov
  2022-11-21  7:57         ` Juri Linkov
  0 siblings, 1 reply; 25+ messages in thread
From: Juri Linkov @ 2022-11-16 19:14 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: mail, 53981

[-- Attachment #1: Type: text/plain, Size: 1483 bytes --]

>>> +                          (re-search-forward
>>> +			   (concat "^\\(?:" outline-regexp "\\)")
>>> +			   nil 'move)))
>>
>> These two loops cons a new string each iteration.  (So did the
>> original code, but if we are touching this, might as well fix that.)
>
> This is optimized as well:

Here is a more tested patch that works in apropos and shortdoc.

Also tested for group outlines in the Completions buffer with:

```
(setq-local
 outline-search-function
 (lambda (&optional bound move backward looking-at)
   (outline-search-text-property
    'face 'completions-group-separator
    bound move backward looking-at))
 outline-level (lambda () 1))
```

It even works when using the search function that searches for
outline-regexp.  This better shows the meaning of its arguments:

```
(setq-default
 outline-search-function
 (lambda (&optional bound move backward looking-at)
   (cond
    (looking-at (looking-at outline-regexp))
    (backward
     (re-search-backward
      (concat "^\\(?:" outline-regexp "\\).*")
      bound (if move 'move t)))
    (t
     (re-search-forward
      (concat "^\\(?:" outline-regexp "\\).*")
      bound (if move 'move t)))))
 outline-level
 (lambda () (looking-at outline-regexp) (outline-level)))
```

As can be seen, the default outline-level function can't be used,
because the search function is expected to match to the end
of the heading line, but the default outline-level expects
to match only beginning of the outline heading.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: outline-search-function.patch --]
[-- Type: text/x-diff, Size: 13752 bytes --]

diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index dbac03432c1..494e5c4123b 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -1374,13 +1374,19 @@ shortdoc-display-group
          (unless (bobp)
            (insert "\n"))
          (insert (propertize
-                  (concat (substitute-command-keys data) "\n\n")
+                  (substitute-command-keys data)
+                  'face 'shortdoc-heading
+                  'shortdoc-section t
+                  'outline-level 1))
+         (insert (propertize
+                  "\n\n"
                   'face 'shortdoc-heading
                   'shortdoc-section t)))
         ;; There may be functions not yet defined in the data.
         ((fboundp (car data))
          (when prev
-           (insert (make-separator-line)))
+           (insert (make-separator-line)
+                   (propertize "\n" 'face '(:height 0))))
          (setq prev t)
          (shortdoc--display-function data))))
      (cdr (assq group shortdoc--groups))))
@@ -1397,7 +1403,7 @@ shortdoc--display-function
         (start-section (point))
         arglist-start)
     ;; Function calling convention.
-    (insert (propertize "(" 'shortdoc-function function))
+    (insert (propertize "(" 'shortdoc-function function 'outline-level 2))
     (if (plist-get data :no-manual)
         (insert-text-button
          (symbol-name function)
@@ -1531,7 +1537,9 @@ shortdoc-mode-map
 
 (define-derived-mode shortdoc-mode special-mode "shortdoc"
   "Mode for shortdoc."
-  :interactive nil)
+  :interactive nil
+  (setq-local outline-search-function #'outline-search-level
+              outline-level (lambda () (get-text-property (point) 'outline-level))))
 
 (defun shortdoc--goto-section (arg sym &optional reverse)
   (unless (natnump arg)
diff --git a/lisp/apropos.el b/lisp/apropos.el
index 62a37df8207..e5c998ee77d 100644
--- a/lisp/apropos.el
+++ b/lisp/apropos.el
@@ -492,7 +492,7 @@ apropos-mode
 \\{apropos-mode-map}"
   (make-local-variable 'apropos--current)
   (setq-local revert-buffer-function #'apropos--revert-buffer)
-  (setq-local outline-regexp "^[^ \n]+"
+  (setq-local outline-search-function #'outline-search-level
               outline-level (lambda () 1)
               outline-minor-mode-cycle t
               outline-minor-mode-highlight t
@@ -1187,7 +1187,8 @@ apropos-print
 	  (insert-text-button (symbol-name symbol)
 			      'type 'apropos-symbol
 			      'skip apropos-multi-type
-			      'face 'apropos-symbol)
+			      'face 'apropos-symbol
+			      'outline-level 1)
 	  (setq button-end (point))
 	  (if (and (eq apropos-sort-by-scores 'verbose)
 		   (cadr apropos-item))
diff --git a/lisp/outline.el b/lisp/outline.el
index a646f71db8b..fbc3a57ee91 100644
--- a/lisp/outline.el
+++ b/lisp/outline.el
@@ -59,6 +59,18 @@ outline-heading-end-regexp
 in the file it applies to.")
 ;;;###autoload(put 'outline-heading-end-regexp 'safe-local-variable 'stringp)
 
+(defvar outline-search-function nil
+  "Function to search the next outline heading.
+The function is called with four optional arguments: BOUND, MOVE, BACKWARD,
+LOOKING-AT.  The first two arguments BOUND and MOVE are almost the same as
+the BOUND and NOERROR arguments of `re-search-forward', with the difference
+that MOVE accepts only a boolean, either nil or non-nil.  When the argument
+BACKWARD is non-nil, the search should search backward like
+`re-search-backward' does.  When the argument LOOKING-AT is non-nil,
+it should imitate the function `looking-at'.  In case of a successful
+search, the function should return non-nil, move point, and set
+match-data appropriately.")
+
 (defvar outline-mode-prefix-map
   (let ((map (make-sparse-keymap)))
     (define-key map "@" 'outline-mark-subtree)
@@ -233,7 +245,8 @@ outline-mode-map
 (defvar outline-font-lock-keywords
   '(
     ;; Highlight headings according to the level.
-    (eval . (list (concat "^\\(?:" outline-regexp "\\).*")
+    (eval . (list (or outline-search-function
+                      (concat "^\\(?:" outline-regexp "\\).*"))
                   0 '(if outline-minor-mode
                          (if outline-minor-mode-highlight
                              (list 'face (outline-font-lock-face)))
@@ -366,7 +379,9 @@ outline-font-lock-face
   "Return one of `outline-font-lock-faces' for current level."
   (save-excursion
     (goto-char (match-beginning 0))
-    (looking-at outline-regexp)
+    (if outline-search-function
+        (funcall outline-search-function nil nil nil t)
+      (looking-at outline-regexp))
     (aref outline-font-lock-faces
           (% (1- (funcall outline-level))
              (length outline-font-lock-faces)))))
@@ -474,8 +489,11 @@ outline-minor-mode-highlight-buffer
   ;; Fallback to overlays when font-lock is unsupported.
   (save-excursion
     (goto-char (point-min))
-    (let ((regexp (concat "^\\(?:" outline-regexp "\\).*$")))
-      (while (re-search-forward regexp nil t)
+    (let ((regexp (unless outline-search-function
+                    (concat "^\\(?:" outline-regexp "\\).*$"))))
+      (while (if outline-search-function
+                 (funcall outline-search-function)
+               (re-search-forward regexp nil t))
         (let ((overlay (make-overlay (match-beginning 0) (match-end 0))))
           (overlay-put overlay 'outline-highlight t)
           ;; FIXME: Is it possible to override all underlying face attributes?
@@ -592,26 +610,34 @@ outline-next-preface
   "Skip forward to just before the next heading line.
 If there's no following heading line, stop before the newline
 at the end of the buffer."
-  (if (re-search-forward (concat "\n\\(?:" outline-regexp "\\)")
-			 nil 'move)
-      (goto-char (match-beginning 0)))
-  (if (and (bolp) (or outline-blank-line (eobp)) (not (bobp)))
-      (forward-char -1)))
+  (when (if outline-search-function
+            (funcall outline-search-function nil t)
+          (re-search-forward (concat "\n\\(?:" outline-regexp "\\)")
+			     nil 'move))
+    (goto-char (match-beginning 0))
+    ;; Compensate "\n" from the beginning of regexp
+    (when (and outline-search-function (not (bobp))) (forward-char -1)))
+  (when (and (bolp) (or outline-blank-line (eobp)) (not (bobp)))
+    (forward-char -1)))
 
 (defun outline-next-heading ()
   "Move to the next (possibly invisible) heading line."
   (interactive)
   ;; Make sure we don't match the heading we're at.
-  (if (and (bolp) (not (eobp))) (forward-char 1))
-  (if (re-search-forward (concat "^\\(?:" outline-regexp "\\)")
-			 nil 'move)
-      (goto-char (match-beginning 0))))
+  (when (and (bolp) (not (eobp))) (forward-char 1))
+  (when (if outline-search-function
+            (funcall outline-search-function nil t)
+          (re-search-forward (concat "^\\(?:" outline-regexp "\\)")
+			     nil 'move))
+    (goto-char (match-beginning 0))))
 
 (defun outline-previous-heading ()
   "Move to the previous (possibly invisible) heading line."
   (interactive)
-  (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
-		      nil 'move))
+  (if outline-search-function
+      (funcall outline-search-function nil t t)
+    (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
+		        nil 'move)))
 
 (defsubst outline-invisible-p (&optional pos)
   "Non-nil if the character after POS has outline invisible property.
@@ -628,8 +654,10 @@ outline-back-to-heading
       (let (found)
 	(save-excursion
 	  (while (not found)
-	    (or (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
-				    nil t)
+	    (or (if outline-search-function
+                    (funcall outline-search-function nil nil t)
+                  (re-search-backward (concat "^\\(?:" outline-regexp "\\)")
+				      nil t))
                 (signal 'outline-before-first-heading nil))
 	    (setq found (and (or invisible-ok (not (outline-invisible-p)))
 			     (point)))))
@@ -642,7 +670,9 @@ outline-on-heading-p
   (save-excursion
     (beginning-of-line)
     (and (bolp) (or invisible-ok (not (outline-invisible-p)))
-	 (looking-at outline-regexp))))
+	 (if outline-search-function
+             (funcall outline-search-function nil nil nil t)
+           (looking-at outline-regexp)))))
 
 (defun outline-insert-heading ()
   "Insert a new heading at same depth at point."
@@ -754,7 +784,9 @@ outline-demote
 		      (while (and (progn (outline-next-heading) (not (eobp)))
 				  (<= (funcall outline-level) level))))
 		    (unless (eobp)
-		      (looking-at outline-regexp)
+		      (if outline-search-function
+                          (funcall outline-search-function nil nil nil t)
+                        (looking-at outline-regexp))
 		      (match-string-no-properties 0))))
                 ;; Bummer!! There is no higher-level heading in the buffer.
                 (outline-invent-heading head nil))))
@@ -805,7 +837,9 @@ outline-map-region
   (save-excursion
     (setq end (copy-marker end))
     (goto-char beg)
-    (when (re-search-forward (concat "^\\(?:" outline-regexp "\\)") end t)
+    (when (if outline-search-function
+              (funcall outline-search-function end)
+            (re-search-forward (concat "^\\(?:" outline-regexp "\\)") end t))
       (goto-char (match-beginning 0))
       (funcall fun)
       (while (and (progn
@@ -873,21 +907,23 @@ outline-next-visible-heading
   (if (< arg 0)
       (beginning-of-line)
     (end-of-line))
-  (let (found-heading-p)
+  (let ((regexp (unless outline-search-function
+                  (concat "^\\(?:" outline-regexp "\\)")))
+        found-heading-p)
     (while (and (not (bobp)) (< arg 0))
       (while (and (not (bobp))
 		  (setq found-heading-p
-			(re-search-backward
-			 (concat "^\\(?:" outline-regexp "\\)")
-			 nil 'move))
+			(if outline-search-function
+                            (funcall outline-search-function nil t t)
+                          (re-search-backward regexp nil 'move)))
 		  (outline-invisible-p)))
       (setq arg (1+ arg)))
     (while (and (not (eobp)) (> arg 0))
       (while (and (not (eobp))
 		  (setq found-heading-p
-			(re-search-forward
-			 (concat "^\\(?:" outline-regexp "\\)")
-			 nil 'move))
+			(if outline-search-function
+                            (funcall outline-search-function nil t)
+                          (re-search-forward regexp nil 'move)))
 		  (outline-invisible-p (match-beginning 0))))
       (setq arg (1- arg)))
     (if found-heading-p (beginning-of-line))))
@@ -1107,8 +1143,11 @@ outline-hide-sublevels
   (interactive (list
 		(cond
 		 (current-prefix-arg (prefix-numeric-value current-prefix-arg))
-		 ((save-excursion (beginning-of-line)
-				  (looking-at outline-regexp))
+		 ((save-excursion
+                    (beginning-of-line)
+		    (if outline-search-function
+                        (funcall outline-search-function nil nil nil t)
+                      (looking-at outline-regexp)))
 		  (funcall outline-level))
 		 (t 1))))
   (if (< levels 1)
@@ -1255,7 +1294,9 @@ outline-up-heading
 	  (setq level (funcall outline-level)))
 	(setq start-level level))
       (setq arg (- arg 1))))
-  (looking-at outline-regexp))
+  (if outline-search-function
+      (funcall outline-search-function nil nil nil t)
+    (looking-at outline-regexp)))
 
 (defun outline-forward-same-level (arg)
   "Move forward to the ARG'th subheading at same level as this one.
@@ -1313,6 +1354,51 @@ outline-get-last-sibling
       (if (< (funcall outline-level) level)
 	  nil
         (point)))))
+
+\f
+;;; Search text-property for outline headings
+
+;;;###autoload
+(defun outline-search-level (&optional bound move backward looking-at)
+  "Search for the next text property `outline-level'.
+The arguments are the same as in `outline-search-text-property',
+except the hard-coded property name `outline-level'.
+This function is intended to be used in `outline-search-function'."
+  (outline-search-text-property 'outline-level nil bound move backward looking-at))
+
+(defun outline-search-text-property (property &optional value bound move backward looking-at)
+  "Search for the next text property PROPERTY with VALUE.
+The rest of arguments are described in `outline-search-function'."
+  (if looking-at
+      (when (if value (eq (get-text-property (point) property) value)
+              (get-text-property (point) property))
+        (set-match-data (list (pos-bol) (pos-eol)))
+        t)
+    ;; Go to the end when in the middle of heading
+    (when (and (not backward)
+               (if value (eq (get-text-property (point) property) value)
+                 (get-text-property (point) property))
+               (not (or (bobp)
+                        (not (if value
+                                 (eq (get-text-property (1- (point)) property) value)
+                               (get-text-property (1- (point)) property))))))
+      (goto-char (pos-eol)))
+    (let ((prop-match (if backward
+                          (text-property-search-backward property value (and value t))
+                        (text-property-search-forward property value (and value t)))))
+      (if prop-match
+          (let ((beg (prop-match-beginning prop-match))
+                (end (prop-match-end prop-match)))
+            (if (or (null bound) (<= end bound))
+                (progn (goto-char end)
+                       (goto-char (pos-eol))
+                       (set-match-data (list beg (point)))
+                       t)
+              (when move (goto-char bound))
+              nil))
+        (when move (goto-char (or bound (point-max))))
+        nil))))
+
 \f
 (defun outline-headers-as-kill (beg end)
   "Save the visible outline headers between BEG and END to the kill ring.

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode
  2022-11-16 19:14       ` Juri Linkov
@ 2022-11-21  7:57         ` Juri Linkov
  0 siblings, 0 replies; 25+ messages in thread
From: Juri Linkov @ 2022-11-21  7:57 UTC (permalink / raw)
  To: 53981; +Cc: mail, Eli Zaretskii

close 53981 29.0.50
thanks

> Here is a more tested patch that works in apropos and shortdoc.
>
> Also tested for group outlines in the Completions buffer with:
>
> ```
> (add-hook 'completion-list-mode-hook
>           (lambda ()
>             (setq-local
>              outline-search-function
>              (lambda (&optional bound move backward looking-at)
>                (outline-search-text-property
>                 'face 'completions-group-separator
>                 bound move backward looking-at))
>              outline-level (lambda () 1))
> ```

Now pushed to master and closed.





^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2022-11-21  7:57 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-13 22:39 bug#53981: 28.0.91; shortdoc: Add support for outline-minor-mode Daniel Mendler
2022-02-14 11:06 ` Lars Ingebrigtsen
2022-02-14 12:23   ` Daniel Mendler
2022-02-14 14:18     ` Lars Ingebrigtsen
2022-02-14 14:29       ` Daniel Mendler
2022-02-15  7:32   ` Kévin Le Gouguec
2022-02-15  9:29     ` Lars Ingebrigtsen
2022-02-15  9:36       ` Daniel Mendler
2022-02-16 18:18       ` Juri Linkov
2022-02-17 11:43         ` Lars Ingebrigtsen
2022-02-17 13:44           ` Daniel Mendler
2022-02-17 15:02             ` Lars Ingebrigtsen
2022-02-17 17:45           ` Juri Linkov
2022-02-19 12:49             ` Lars Ingebrigtsen
2022-11-08 19:12 ` Juri Linkov
2022-11-08 19:32   ` Eli Zaretskii
2022-11-09 17:17     ` Juri Linkov
2022-11-16 19:14       ` Juri Linkov
2022-11-21  7:57         ` Juri Linkov
2022-11-09 17:24     ` Juri Linkov
2022-11-09 17:34       ` Eli Zaretskii
2022-11-09 19:47         ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-11-09 20:09           ` Eli Zaretskii
2022-11-09 20:14             ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-11-10  7:42             ` Juri Linkov

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).