branch: externals/hyperbole
commit e1483d9cff137ca7663694da1df56b31cfc7958d
Author: bw <r...@gnu.org>
Commit: bw <r...@gnu.org>

    Temp commit to save multi-mode updates to HyRolo display buffer
    
    Some tests are failing; Mats, see if you can fix them.
---
 .hypb                    | Bin 2715 -> 2599 bytes
 ChangeLog                |  88 ++++++
 HY-ABOUT                 |   2 +-
 HY-NEWS                  |   2 +-
 HY-TALK/HYPERAMP.org     |   3 +-
 Makefile                 |   6 +-
 README.md                |   2 +-
 hactypes.el              |   4 +-
 hbut.el                  |   6 +-
 hibtypes.el              |  52 ++--
 hsys-org.el              |   8 +-
 hui.el                   |   7 +-
 hversion.el              |   4 +-
 hyperbole.el             |   8 +-
 hyrolo-logic.el          |   4 +-
 hyrolo-menu.el           |  20 +-
 hyrolo.el                | 688 ++++++++++++++++++++++++++++++++++++-----------
 kotl/kotl-mode.el        | 104 +++----
 kotl/kview.el            |  10 +-
 man/hyperbole.html       |   8 +-
 man/hyperbole.info       | Bin 615914 -> 615904 bytes
 man/hyperbole.pdf        | Bin 1370428 -> 1370426 bytes
 man/hyperbole.texi       |  12 +-
 man/version.texi         |   8 +-
 test/demo-tests.el       |   4 +-
 test/hibtypes-tests.el   |   6 +-
 test/hmouse-drv-tests.el |   6 +-
 27 files changed, 777 insertions(+), 285 deletions(-)

diff --git a/.hypb b/.hypb
index c4530b271a..1d7d2c5982 100644
Binary files a/.hypb and b/.hypb differ
diff --git a/ChangeLog b/ChangeLog
index 731d93ed06..2b782e7b19 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,93 @@
+2023-12-11  Bob Weiner  <r...@gnu.org>
+
+* test/hibtypes-tests.el (ibtypes::text-toc-test): Regexp-quote * and allow
+    for preceding whitespace.
+
+* kotl/kotl-mode.el (require 'hyrolo): Add.
+
+* hyrolo.el (hyrolo-grep-file): Change 'insert-buffer-substring-no-properties'
+    to 'insert-buffer-substring' to keep properties, as need Koutline
+    'kcell properties to navigate them properly.
+
+* kotl/kview.el (kcell-view:to-label-end):
+  kotl/kotl-mode.el (kotl-mode:to-valid-position): Fix to handle file headers
+    in HyRolo display match buffer when displaying parts of Koutlines.
+
+* hyrolo.el (hyrolo-cache-set-major-mode): Move to this function the
+    addition of 'hyrolo-hdr-regexp' to both 'hyrolo-entry-regexp' and
+    'outline-regexp' within the *HyRolo* display match buffer.
+            (hyrolo-markdown-outline-level, hyrolo-cache-set-major-mode):
+    Fix markdown 'outline-level' function to always return a non-nil level.
+
+2023-12-10  Bob Weiner  <r...@gnu.org>
+
+* hyrolo.el (hyrolo-grep): Remove unused local 'hyrolo-buf'.
+            (hyrolo-outline-minor-mode): Define and enable in 'hyrolo-mode'.
+
+* hyrolo-menu.el (hyrolo-menu-common-body):
+  hyrolo.el (hyrolo-mode-map): Change to 'make-sparse-keymap', name it and 
inherit
+    from a copy of 'outline-mode-prefix-map' where its command bindings are 
overriden
+    with hyrolo- prefixed ones.
+
+* hyrolo.el (hyrolo-move-backward): Change 'outline-previous-heading' call to
+    'hyrolo-outline-previous-heading'.
+
+2023-12-09  Bob Weiner  <r...@gnu.org>
+
+* hyrolo.el (hyrolo-funcall-match, hyrolo-map-matches): Add these functions to
+    wrap function calls in the HyRolo display matches buffer that require the
+    original major mode of the location, e.g. outline commands.
+
+* hyrolo.el (hyrolo-outline-show-subtree): Add to replace usage of
+    'outline-show-subtree'.
+           (hyrolo-outline-hide-subtree): Rename from 'hyrolo-hide-subtree'.
+            (hyrolo-outline-hide-subtree, hyrolo-overview,
+             hyrolo-top-level, hyrolo-move-backward, hyrolo-move-forward):
+    Add a wrapper call to 'hyrolo-funcall-match' or 'hyrolo-map-matches'
+    which sets appropriate major mode per location in the match buffer.
+            (hyrolo-outline-*): Add new functions emulating all 
'outline-minor-mode'
+    key bindings with above wrapper calls and add to 'hyrolo-mode-map' keys.
+* hyrolo-*.el (outline): Change all (outline-*) calls to (hyrolo-outline-*) 
calls.
+    This supports different major modes within the HyRolo match display buffer.
+
+2023-12-08  Bob Weiner  <r...@gnu.org>
+
+* kotl/kotl-mode.el (kotl-mode): Update to be usable in 
`hyrolo-display-buffer'.
+
+2023-12-07  Bob Weiner  <r...@gnu.org>
+
+* hyrolo.el (hyrolo--cache-*): Add caching of each 'major-mode' to use for the 
buffer
+    from which a matching HyRolo record is drawn.
+    (hyrolo-let-file-list, hyrolo-set-file-list): Add calls to
+    `hyrolo--cache-initialize'.
+    (hyrolo-grep): Add calls to 'hyrolo--cache-initialize' and to
+       'hyrolo--cache-post-display-buffer' when not 'count-only'.
+    (hyrolo-grep-file): Add call to 'hyrolo--cache-locals'.
+    (hyrolo-grep): Remove concatenated 'outline-regexps' and 
'hyrolo-entry-regexps'.
+       They are no longer used.  Move header matching in `outline-regexp' and
+       `hyrolo-entry-regexp' to 'hyrolo--cache-matched-buffer'.
+
+2023-12-04  Bob Weiner  <r...@gnu.org>
+
+* Makefile (HY-TALK/HYPER*.org): Add Hyperbole talk slides from EmacsConf
+    presentations.
+  MANIFEST: Update with org files used in talks.
+
+* hsys-org.el (org-link): Expand this actype to open Org links that are in
+    non-Org-mode buffers.
+
 2023-12-03  Bob Weiner  <r...@gnu.org>
 
+* hibtypes.el (annot-bib): Lower priority below 'org-link-outside-org-mode'
+    as this can be mistaken for an org link outside an org buffer.
+
+* hactypes.el (link-to-regexp-match): Fix typo.
+
+* hui.el (hui:link-possible-types): Set no-default when checking if
+    at a filename; otherwise, will match at any point in a file-based
+    buffer, which is only supposed to trigger at the end of the possible
+    matches when 'buffer-file-name' is checked.
+
 * test/hyrolo-tests.el (hyrolo-sort-test): Temporarily set to known
     :failing, as is a known bug.
 
diff --git a/HY-ABOUT b/HY-ABOUT
index b2edea7688..f6d3a08c25 100644
--- a/HY-ABOUT
+++ b/HY-ABOUT
@@ -3,7 +3,7 @@
                    Designed and Written by Bob Weiner
                 Maintained by Mats Lidell and Bob Weiner
                  https://www.gnu.org/software/hyperbole/
-                            Version 8.0.1pre
+                           Version 9.0.0
 
          Say thanks or send a testimonial if you like Hyperbole:
                         Email: <r...@gnu.org>
diff --git a/HY-NEWS b/HY-NEWS
index be894f4cab..d5aceac2d9 100644
--- a/HY-NEWS
+++ b/HY-NEWS
@@ -4,7 +4,7 @@
                                 by Bob Weiner
 
 ===========================================================================
-*                                   V8.0.1pre
+*                                   V9.0.0
 ===========================================================================
 
 ** ACE WINDOW PACKAGE INTEGRATION - fast window and buffer switching
diff --git a/HY-TALK/HYPERAMP.org b/HY-TALK/HYPERAMP.org
index fb73e7915c..0eafce3b02 100644
--- a/HY-TALK/HYPERAMP.org
+++ b/HY-TALK/HYPERAMP.org
@@ -12,7 +12,8 @@ programming identifiers, Texinfo and Info cross-references, 
Org links,
 Markdown links and on and on.  All you do is load Hyperbole and then your
 text comes to life with no extra effort or complex formatting.
 
-Install Hyperbole:  (progn (add-to-list 'package-archives
+Install Hyperbole:  (progn (require 'package)
+                           (add-to-list 'package-archives
                                         '("elpa-devel" . 
"https://elpa.gnu.org/devel/";))
                            (package-install 'hyperbole))
 
diff --git a/Makefile b/Makefile
index 320b362b40..f4582528e8 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 # Author:       Bob Weiner
 #
 # Orig-Date:    15-Jun-94 at 03:42:38
-# Last-Mod:     19-Nov-23 at 14:18:10 by Bob Weiner
+# Last-Mod:      4-Dec-23 at 01:18:04 by Bob Weiner
 #
 # Copyright (C) 1994-2023  Free Software Foundation, Inc.
 # See the file HY-COPY for license information.
@@ -85,7 +85,7 @@
 
 # This ver setup won't work under any make except GNU make, so set it manually.
 #HYPB_VERSION = "`head -3 hversion.el | tail -1 | sed -e 's/.*|\(.*\)|.*/\1/'`"
-HYPB_VERSION = 8.0.1pre
+HYPB_VERSION = 9.0.0
 
 # Emacs executable used to byte-compile .el files into .elc's.
 # To override which executable is used from the commandline, do something like 
this:
@@ -199,7 +199,7 @@ ELC_COMPILE = $(EL_COMPILE:.el=.elc)
 
 ELC_KOTL = $(EL_KOTL:.el=.elc)
 
-HY-TALK  = HY-TALK/.hypb HY-TALK/HYPB HY-TALK/HY-TALK.org
+HY-TALK  = HY-TALK/.hypb HY-TALK/HYPB HY-TALK/HY-TALK.org HY-TALK/HYPERAMP.org 
HY-TALK/HYPERORG.org
 
 HYPERBOLE_FILES = dir info html $(EL_SRC) $(EL_KOTL) \
        $(ELC_COMPILE) $(HY-TALK) ChangeLog COPYING Makefile HY-ABOUT 
HY-ANNOUNCE \
diff --git a/README.md b/README.md
index 2a3d77946c..68f9955667 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# GNU Hyperbole 8.0.1pre - The Everyday Hypertextual Information Manager
+# GNU Hyperbole 9.0.0 - The Everyday Hypertextual Information Manager
 
 [We work on Hyperbole as a gift to the Emacs community and request you
  send us a thank you or a testimonial describing your usage if you like
diff --git a/hactypes.el b/hactypes.el
index db37b5fa54..ab445a2525 100644
--- a/hactypes.el
+++ b/hactypes.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    23-Sep-91 at 20:34:36
-;; Last-Mod:     25-Nov-23 at 16:36:26 by Mats Lidell
+;; Last-Mod:      3-Dec-23 at 11:37:36 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -651,7 +651,7 @@ Return t if found, signal an error if not."
       (hpath:display-buffer source)
       (widen)
       (goto-char (point-min))
-      (if (re-search-forward regexp nil t n)
+      (if (re-search-forward regexp nil t)
          (progn (beginning-of-line) (recenter 0) t)
        (hypb:error
         "(link-to-regexp-match): Pattern not found: `%s'" regexp)))))
diff --git a/hbut.el b/hbut.el
index 0833e3481e..31d2b95794 100644
--- a/hbut.el
+++ b/hbut.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    18-Sep-91 at 02:57:09
-;; Last-Mod:     30-Nov-23 at 23:23:53 by Bob Weiner
+;; Last-Mod:     11-Dec-23 at 01:02:18 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -974,7 +974,7 @@ Suitable for use as part of `write-file-functions'."
         (buf (and (stringp default-directory)
                   (get-file-buffer bd-file))))
     (if (and ebut:hattr-save buf (not (eq buf (current-buffer))))
-       (let ((ebut:hattr-save));; Prevents `write-file-functions' from looping.
+       (let ((ebut:hattr-save)) ;; Prevents `write-file-functions' from 
looping.
          (and (buffer-modified-p buf)
               (with-current-buffer buf (save-buffer)
                 ;; Unlock button attribute file; kill buffer so user is
@@ -1246,7 +1246,7 @@ is given."
                            (file-name-nondirectory buffer-file-name)))
                         ;; Handle any preceding @loc hyp-source implicit 
button location references.
                         ;; This is used in report buffers of explicit buttons, 
i.e. hui:hbut-report
-                        ;; and the *HyRolo* abd *HyNote* output buffers.
+                        ;; as well as the *HyRolo* and *HyNote* output buffers.
                         ((save-excursion
                            (save-restriction
                              (widen)
diff --git a/hibtypes.el b/hibtypes.el
index eb174fda19..5963b69da0 100644
--- a/hibtypes.el
+++ b/hibtypes.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    19-Sep-91 at 20:45:31
-;; Last-Mod:     25-Nov-23 at 17:18:25 by Mats Lidell
+;; Last-Mod:      3-Dec-23 at 23:55:11 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -337,30 +337,6 @@ in all buffers."
         (ibut:label-set address (match-beginning 1) (match-end 1))
         (hact 'mail-other-window nil address)))))
 
-;;; ========================================================================
-;;; Follows Org links that are in non-Org mode buffers
-;;; ========================================================================
-
-;; Org links in Org mode are handled at the highest priority; see the last
-;; section at the end of this file.
-
-(defib org-link-outside-org-mode ()
-  "Follow an Org link in a non-Org mode buffer.
-This should be a very low priority so other Hyperbole types
-handle any links they recognize first."
-  (when (and (eq hsys-org-enable-smart-keys t)
-            (not (funcall hsys-org-mode-function))
-            ;; Prevent infinite recursion, e.g. if called via
-            ;; `org-metareturn-hook' from `org-meta-return' invocation.
-            (not (hyperb:stack-frame '(ibtypes::debugger-source 
org-meta-return))))
-    (require 'hsys-org)
-    (declare-function hsys-org-link-at-p      "hsys-org" ())
-    (declare-function hsys-org-set-ibut-label "hsys-org" (start-end))
-    (let ((start-end (hsys-org-link-at-p)))
-      (when start-end
-        (hsys-org-set-ibut-label start-end)
-        (hact #'org-open-at-point-global)))))
-
 ;;; ========================================================================
 ;;; Handles internal references within an annotated bibliography, delimiters=[]
 ;;; ========================================================================
@@ -370,7 +346,7 @@ handle any links they recognize first."
 References must be delimited by square brackets, must begin with a word
 constituent character, not contain @ or # characters, must not be
 in buffers whose names begin with a space or asterisk character, must
-not be in a programming mode, Markdown or Org buffers and must have an
+not be in a programming mode, Markdown or Org buffer and must have an
 attached file."
   (and (not (bolp))
        buffer-file-name
@@ -388,6 +364,30 @@ attached file."
                (ibut:label-p t "[" "]" t))
               (hact 'annot-bib ref)))))
 
+;;; ========================================================================
+;;; Follows Org links that are in non-Org mode buffers
+;;; ========================================================================
+
+;; Org links in Org mode are handled at the highest priority; see the last
+;; section at the end of this file.
+
+(defib org-link-outside-org-mode ()
+  "Follow an Org link in a non-Org mode buffer.
+This should be a very low priority so other Hyperbole types
+handle any links they recognize first."
+  (when (and (eq hsys-org-enable-smart-keys t)
+            (not (funcall hsys-org-mode-function))
+            ;; Prevent infinite recursion, e.g. if called via
+            ;; `org-metareturn-hook' from `org-meta-return' invocation.
+            (not (hyperb:stack-frame '(ibtypes::debugger-source 
org-meta-return))))
+    (require 'hsys-org)
+    (declare-function hsys-org-link-at-p      "hsys-org" ())
+    (declare-function hsys-org-set-ibut-label "hsys-org" (start-end))
+    (let ((start-end (hsys-org-link-at-p)))
+      (when start-end
+        (hsys-org-set-ibut-label start-end)
+        (hact #'org-open-at-point-global)))))
+
 ;;; ========================================================================
 ;;; Displays in-file Markdown link referents.
 ;;; ========================================================================
diff --git a/hsys-org.el b/hsys-org.el
index 7bf48c4c08..5ab09a56b2 100644
--- a/hsys-org.el
+++ b/hsys-org.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:     2-Jul-16 at 14:54:14
-;; Last-Mod:     25-Nov-23 at 16:45:25 by Mats Lidell
+;; Last-Mod:      4-Dec-23 at 00:04:31 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -104,8 +104,12 @@ with different settings of this option.  For example, a 
nil value makes
   "Follow an optional Org mode LINK to its target.
 If LINK is nil, follow any link at point.  Otherwise, trigger an error."
   (if (stringp link)
+      ;; open as if in Org mode even if not
       (org-link-open-from-string link)
-    (org-open-at-point))) ;; autoloaded
+    ;; autoloaded, open link at point whether in or out of Org mode
+    (if (derived-mode-p 'org-mode)
+       (org-open-at-point)
+      (org-open-at-point-global))))
 
 (defact org-internal-target-link (&optional internal-target)
   "Follow an optional Org mode <<INTERNAL-TARGET>> back to any first link to 
it.
diff --git a/hui.el b/hui.el
index b3c6de3316..b3d4634cf0 100644
--- a/hui.el
+++ b/hui.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    19-Sep-91 at 21:42:03
-;; Last-Mod:      6-Nov-23 at 19:36:33 by Bob Weiner
+;; Last-Mod:     10-Dec-23 at 16:18:24 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -1854,7 +1854,8 @@ Buffer without File      link-to-buffer-tmp"
                             ;; and sets hbut:current button attributes.
                             (t (cond ((and (not (derived-mode-p 'dired-mode))
                                            (prog1 (setq hbut-sym (hbut:at-p))
-                                             (save-excursion 
(ibut:at-to-name-p hbut-sym)))
+                                             (when (ibut:is-p hbut-sym)
+                                               (save-excursion 
(ibut:at-to-name-p hbut-sym))))
                                            (setq lbl-key (hattr:get hbut-sym 
'lbl-key))
                                            (eq (current-buffer) 
(get-file-buffer (gbut:file))))
                                       (list 'link-to-gbut lbl-key))
@@ -1893,7 +1894,7 @@ Buffer without File      link-to-buffer-tmp"
                                             (setq val (hargs:at-p t)))
                                           (list 'link-to-directory val))
                                          ((let ((hargs:reading-type 'file))
-                                            (setq val (hargs:at-p)))
+                                            (setq val (hargs:at-p t)))
                                           (list 'link-to-file val))
                                          ((derived-mode-p #'kotl-mode)
                                           (list 'link-to-kcell 
buffer-file-name (kcell-view:idstamp)))
diff --git a/hversion.el b/hversion.el
index 8ecbafebf2..ac50591aa8 100644
--- a/hversion.el
+++ b/hversion.el
@@ -4,7 +4,7 @@
 ;; Maintainer:   Bob Weiner, Mats Lidell
 ;;
 ;; Orig-Date:     1-Jan-94
-;; Last-Mod:     30-Oct-23 at 23:49:10 by Mats Lidell
+;; Last-Mod:      3-Dec-23 at 09:43:50 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -35,7 +35,7 @@
 ;;; Public variables
 ;;; ************************************************************************
 
-(defconst hyperb:version "8.0.1pre" "GNU Hyperbole revision number.")
+(defconst hyperb:version "9.0.0" "GNU Hyperbole revision number.")
 
 (defvar hyperb:mouse-buttons
   (if (or (and hyperb:microsoft-os-p (not (memq window-system '(w32 w64 x))))
diff --git a/hyperbole.el b/hyperbole.el
index a8aee8d667..bd89ec0db4 100644
--- a/hyperbole.el
+++ b/hyperbole.el
@@ -7,12 +7,12 @@
 ;; Author:       Bob Weiner
 ;; Maintainer:   Bob Weiner <r...@gnu.org>, Mats Lidell <ma...@gnu.org>
 ;; Created:      06-Oct-92 at 11:52:51
-;; Last-Mod:     11-Nov-23 at 16:34:14 by Bob Weiner
-;; Released:     03-Dec-22
-;; Version:      8.0.1pre
+;; Last-Mod:      3-Dec-23 at 09:46:12 by Bob Weiner
+;; Released:     03-Dec-23
+;; Version:      9.0.0
 ;; Keywords:     comm, convenience, files, frames, hypermedia, languages, 
mail, matching, mouse, multimedia, outlines, tools, wp
 ;; Package:      hyperbole
-;; Package-Requires: ((emacs "27.0"))
+;; Package-Requires: ((emacs "27.1"))
 ;; URL:          http://www.gnu.org/software/hyperbole
 
 ;; See the "HY-COPY" file for license information.
diff --git a/hyrolo-logic.el b/hyrolo-logic.el
index 643fc76164..efee72e800 100644
--- a/hyrolo-logic.el
+++ b/hyrolo-logic.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    13-Jun-89 at 22:57:33
-;; Last-Mod:     11-Nov-23 at 11:27:25 by Bob Weiner
+;; Last-Mod:     10-Dec-23 at 17:24:59 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -153,7 +153,7 @@ single argument."
           (setq total-matches (hyrolo-fgrep expr))))
 
     (if (called-interactively-p 'interactive)
-       (message "%s matching entr%s found in rolo."
+       (message "%s matching entr%s found in HyRolo."
                 (if (= total-matches 0) "No" total-matches)
                 (if (= total-matches 1) "y" "ies")))
     total-matches))
diff --git a/hyrolo-menu.el b/hyrolo-menu.el
index 44f79f746e..0d988dcd61 100644
--- a/hyrolo-menu.el
+++ b/hyrolo-menu.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    28-Oct-94 at 10:59:44
-;; Last-Mod:      9-Apr-23 at 11:44:06 by Bob Weiner
+;; Last-Mod:     10-Dec-23 at 19:07:10 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -65,16 +65,16 @@
      ["To-Beginning"           beginning-of-buffer                      t]
      ["To-End"                 end-of-buffer                            t]
      "----"
-     ["To-Next-Entry"          outline-next-visible-heading             t]
-     ["To-Next-Same-Level"     outline-forward-same-level               t]
-     ["To-Previous-Entry"      outline-previous-visible-heading         t]
-     ["To-Previous-Same-Level" outline-backward-same-level              t]
-     ["Up-a-Level"             outline-up-heading                       t])
+     ["To-Next-Entry"          hyrolo-outline-next-visible-heading      t]
+     ["To-Next-Same-Level"     hyrolo-outline-forward-same-level        t]
+     ["To-Previous-Entry"      hyrolo-outline-previous-visible-heading  t]
+     ["To-Previous-Same-Level" hyrolo-outline-backward-same-level       t]
+     ["Up-a-Level"             hyrolo-outline-up-heading                t])
     ("Outline"
-     ["Hide (Collapse)"        outline-hide-subtree                     t]
-     ["Show (Expand)"          outline-show-subtree                     t]
-     ["Show-All"               outline-show-all                         t]
-     ["Show-Only-First-Line"   outline-hide-body                        t]))
+     ["Hide (Collapse)"        hyrolo-outline-hide-subtree              t]
+     ["Show (Expand)"          hyrolo-outline-show-subtree              t]
+     ["Show-All"               hyrolo-outline-show-all                  t]
+     ["Show-Only-First-Line"   hyrolo-outline-hide-body                 t]))
   "The middle menu entries common to all HyRolo menus.")
 
 (defconst id-popup-hyrolo-menu
diff --git a/hyrolo.el b/hyrolo.el
index 86ec53f7e3..cac25bc46f 100644
--- a/hyrolo.el
+++ b/hyrolo.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:     7-Jun-89 at 22:08:29
-;; Last-Mod:      2-Dec-23 at 22:00:29 by Bob Weiner
+;; Last-Mod:     11-Dec-23 at 02:14:52 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -139,7 +139,7 @@ A hyrolo-file consists of:
   :type '(repeat file)
   :initialize #'custom-initialize-default
   :set #'hyrolo-set-file-list
-  :group 'hyperbbole-hyrolo)
+  :group 'hyperbole-hyrolo)
 
 (defun hyrolo-file-list-changed (symbol set-to-value operation _where)
   (if (memq operation '(let unlet)) ;; not setting global value
@@ -172,7 +172,7 @@ level.")
                  hyrolo-entry-trailing-space-group-number 4)))
 
 (defcustom hyrolo-date-format "%m/%d/%Y"
-  "Format of date string used in Rolo automatic date stamps.
+  "Format of date string used in HyRolo automatic date stamps.
 An empty string disables adding or updating HyRolo dates.
 
 Default is American style.  See documentation of the function
@@ -331,39 +331,6 @@ String search expressions are converted to regular 
expressions.")
 (defvar hyrolo-mode-map nil
   "Keymap for the hyrolo match buffer.")
 
-(if hyrolo-mode-map
-    nil
-  (setq hyrolo-mode-map (make-keymap))
-  (if (fboundp 'set-keymap-name)
-      (set-keymap-name hyrolo-mode-map 'hyrolo-mode-map))
-  (suppress-keymap hyrolo-mode-map)
-  (define-key hyrolo-mode-map ","        'hyrolo-to-entry-beginning)
-  (define-key hyrolo-mode-map "."        'hyrolo-to-entry-end)
-  (define-key hyrolo-mode-map "<"        'beginning-of-buffer)
-  (define-key hyrolo-mode-map ">"        'end-of-buffer)
-  (define-key hyrolo-mode-map "?"        'describe-mode)
-  (define-key hyrolo-mode-map "\177"     'scroll-down)
-  (define-key hyrolo-mode-map " "        'scroll-up)
-  (define-key hyrolo-mode-map "a"        'outline-show-all)
-  (define-key hyrolo-mode-map "b"        'hyrolo-backward-same-level)
-  (define-key hyrolo-mode-map "e"        'hyrolo-edit-entry)
-  (define-key hyrolo-mode-map "f"        'hyrolo-forward-same-level)
-  (define-key hyrolo-mode-map "h"        'hyrolo-hide-subtree)
-  (define-key hyrolo-mode-map "l"        'hyrolo-locate)
-  (define-key hyrolo-mode-map "m"        'hyrolo-mail-to)
-  (define-key hyrolo-mode-map "n"        'hyrolo-next-visible-heading)
-  (define-key hyrolo-mode-map "o"        'hyrolo-overview)
-  (define-key hyrolo-mode-map "p"        'hyrolo-previous-visible-heading)
-  (define-key hyrolo-mode-map "q"        'hyrolo-quit)
-  (define-key hyrolo-mode-map "r"        'hyrolo-grep-or-fgrep)
-  (define-key hyrolo-mode-map "s"        'outline-show-subtree)
-  (define-key hyrolo-mode-map "\M-s"     'hyrolo-isearch)
-  (define-key hyrolo-mode-map "t"        'hyrolo-top-level)
-  (define-key hyrolo-mode-map "\C-i"     'hyrolo-next-match)      ;; {TAB}
-  (define-key hyrolo-mode-map "\M-\C-i"  'hyrolo-previous-match)  ;; {M-TAB}
-  (define-key hyrolo-mode-map [backtab]  'hyrolo-previous-match)  ;; 
{Shift-TAB}
-  (define-key hyrolo-mode-map "u"        'hyrolo-up-heading))
-
 ;;; ************************************************************************
 ;;; Commands
 ;;; ************************************************************************
@@ -645,7 +612,7 @@ the logical sexpression matching."
       (setq total-matches (hyrolo-grep (regexp-quote string)
                                       max-matches hyrolo-file count-only 
headline-only no-display)))
     (if (called-interactively-p 'interactive)
-       (message "%s matching entr%s found in rolo."
+       (message "%s matching entr%s found in HyRolo."
                 (if (= total-matches 0) "No" total-matches)
                 (if (= total-matches 1) "y" "ies")))
     total-matches))
@@ -691,7 +658,9 @@ It uses the setting of 
`hyrolo-find-file-noselect-function'."
       (hyrolo-find-file file hyrolo-find-file-noselect-function))))
 
 ;; This wraps forward-visible-line, making its ARG optional, making
-;; its calling convention match that of forward-line.
+;; its calling convention match that of forward-line and making it
+;; usable as an argument to `sort-subr' in `hyrolo-sort-lines' to fix a
+;; sorting issue visible in Emacs `sort-lines'.
 (defun hyrolo-forward-visible-line (&optional arg)
   "Move forward by optional ARG lines (default = 1).
 Ignore currently invisible newlines only.
@@ -741,23 +710,16 @@ Return number of entries matched.  See also documentation 
for the variable
        (num-matched 0)
        (inserting (or (eq max-matches t)
                       (and (integerp max-matches) (< max-matches 0))))
-       (hyrolo-entry-regexps (set:create))
-       (outline-regexps (set:create))
-       (file-or-buf)
-       hyrolo-buf)
+       (file-or-buf))
     (unless count-only
       (setq buffer-read-only nil)
       (unless inserting
-       (erase-buffer)))
+       (erase-buffer))
+      (hyrolo--cache-initialize))
     (while (and (setq file-or-buf (car files-or-bufs))
                (or (not (integerp max-matches))
                    (< total-matches (max max-matches (- max-matches)))))
-      (setq hyrolo-buf (hyrolo-find-file-noselect file-or-buf)
-           hyrolo-entry-regexps (set:add (buffer-local-value 
'hyrolo-entry-regexp hyrolo-buf)
-                                         hyrolo-entry-regexps)
-           outline-regexps (set:add (buffer-local-value 'outline-regexp 
hyrolo-buf)
-                                    outline-regexps)
-           files-or-bufs (cdr files-or-bufs)
+      (setq files-or-bufs (cdr files-or-bufs)
            num-matched (cond ((and (featurep 'bbdb) (equal file-or-buf 
bbdb-file))
                               (hyrolo-bbdb-grep-file file-or-buf regexp 
max-matches count-only))
                              ((and (hyrolo-google-contacts-p) (equal 
file-or-buf google-contacts-buffer-name))
@@ -770,19 +732,13 @@ Return number of entries matched.  See also documentation 
for the variable
              (if (>= max-matches 0)
                  (- max-matches num-matched)
                (+ max-matches num-matched)))))
-    (unless (or count-only no-display inserting (= total-matches 0))
-      (set-buffer display-buf)
-      (when hyrolo-entry-regexps
-       (setq hyrolo-entry-regexp (string-join hyrolo-entry-regexps "\\|"))
-       (unless (string-prefix-p hyrolo-hdr-regexp hyrolo-entry-regexp)
-         (setq hyrolo-entry-regexp (concat hyrolo-hdr-regexp "\\|" 
hyrolo-entry-regexp))))
-      (when outline-regexps
-       (setq-local outline-regexp (string-join outline-regexps "\\|"))
-       (unless (string-prefix-p hyrolo-hdr-regexp outline-regexp)
-         (setq-local outline-regexp (concat hyrolo-hdr-regexp "\\|" 
outline-regexp))))
-      (hyrolo-display-matches display-buf))
+    (unless (or count-only (= total-matches 0))
+      (hyrolo--cache-post-display-buffer)
+      (unless (or no-display inserting)
+       (set-buffer display-buf)
+       (hyrolo-display-matches display-buf)))
     (when (called-interactively-p 'interactive)
-      (message "%s matching entr%s found in rolo."
+      (message "%s matching entr%s found in HyRolo."
               (if (= total-matches 0) "No" total-matches)
               (if (= total-matches 1) "y" "ies")))
     total-matches))
@@ -794,20 +750,6 @@ With optional prefix ARG, do an fgrep string match instead 
of a regexp match."
   (interactive "P")
   (call-interactively (if arg 'hyrolo-fgrep 'hyrolo-grep)))
 
-(defun hyrolo-hide-subtree ()
-  "Move back to the start of current subtree and hide everything after the 
heading.
-
-Necessary, since with reveal-mode active, outline-hide-subtree works
-only if on the heading line of the subtree."
-  (interactive)
-  (let ((opoint (point)))
-    (forward-line 0)
-    (unless (looking-at outline-regexp)
-      (outline-previous-visible-heading 1))
-    (if (looking-at outline-regexp)
-       (outline-hide-subtree)
-      (goto-char opoint))))
-
 (defun hyrolo-isearch (&optional arg)
   "Interactively search forward for the next occurrence of current match 
string.
 Then add characters to further narrow the search.  With optional
@@ -933,14 +875,16 @@ lines of entries only to that depth."
   (interactive "P")
   (hyrolo-verify)
   ;; Use {t} to display top-level cells only.
-  (if (or (null levels-to-show)
-         (if (called-interactively-p 'interactive)
-             (progn (setq levels-to-show (prefix-numeric-value 
current-prefix-arg))
-                    (<= levels-to-show 0))
-           (not (integerp levels-to-show))))
-      (setq levels-to-show 100))
-  (hyrolo-hide-subtree) ;; Ensure reveal-mode does not expand current entry.
-  (hyrolo-show-levels levels-to-show))
+  (hyrolo-map-matches
+   (lambda ()
+     (if (or (null levels-to-show)
+            (if (called-interactively-p 'interactive)
+                (progn (setq levels-to-show (prefix-numeric-value 
current-prefix-arg))
+                       (<= levels-to-show 0))
+              (not (integerp levels-to-show))))
+        (setq levels-to-show 100))
+     (hyrolo-outline-hide-subtree) ;; Ensure reveal-mode does not expand 
current entry.
+     (hyrolo-show-levels levels-to-show))))
 
 (defun hyrolo-previous-match ()
   "Move point back to the start of the previous rolo search match.
@@ -1003,7 +947,8 @@ Raise an error if a match is not found."
 ;;;###autoload
 (defun hyrolo-let-file-list (symbol value)
   (set symbol value)
-  (setq hyrolo--expanded-file-list (hyrolo-expand-path-list value)))
+  (setq hyrolo--expanded-file-list (hyrolo-expand-path-list value))
+  (hyrolo--cache-initialize))
 
 ;;;###autoload
 (defun hyrolo-set-file-list (symbol value)
@@ -1011,6 +956,7 @@ Raise an error if a match is not found."
   (setq hyrolo--expanded-file-list (hyrolo-expand-path-list value))
   (unless (symbol-value symbol)
     (set-default symbol hyrolo--expanded-file-list))
+  (hyrolo--cache-initialize)
   ;; Prompt user to rename old personal rolo file to new name, if necessary.
   (unless (or noninteractive (hyperb:stack-frame '(hyrolo-rename)))
     (call-interactively 'hyrolo-rename)))
@@ -1067,7 +1013,9 @@ To a maximum of optional MAX-GROUPINGS.  Nil value of 
MAX-GROUPINGS means all
 groupings at the given level.  LEVEL-REGEXP should simply match the text of
 any rolo entry of the given level, not the beginning of a line (^); an
 example, might be (regexp-quote \"**\") to match level two.  Return number
-of groupings sorted."
+of groupings sorted.
+
+Current buffer should be an editable HyRolo source location, not the match 
buffer."
   (interactive "sRegexp for level's entries: \nP")
   ;; Divide by 2 in next line because each asterisk character is preceded
   ;; by a regexp-quote backslash character.
@@ -1134,8 +1082,10 @@ Top-level matches are those with the lowest outline 
level among the
 matched entries."
   (interactive)
   (hyrolo-verify)
-  (hyrolo-hide-subtree)
-  (hyrolo-show-levels 1))
+  (hyrolo-map-matches
+   (lambda ()
+     (hyrolo-outline-hide-subtree)
+     (hyrolo-show-levels 1))))
 
 (defun hyrolo-verify ()
   "Verify point is in a HyRolo or HyNote match buffer."
@@ -1172,10 +1122,10 @@ Return number of entries matched.  See also 
documentation for the variable
 hyrolo-file-list."
   (interactive "sFind rolo whole word matches of: \nP")
   (let ((total-matches (hyrolo-grep (format "\\b%s\\b" (regexp-quote string))
-                                 max-matches
-                                 hyrolo-file count-only headline-only 
no-display)))
+                                   max-matches
+                                   hyrolo-file count-only headline-only 
no-display)))
     (when (called-interactively-p 'interactive)
-      (message "%s matching entr%s found in the rolo."
+      (message "%s matching entr%s found in HyRolo."
               (if (= total-matches 0) "No" total-matches)
               (if (= total-matches 1) "y" "ies")))
     total-matches))
@@ -1367,23 +1317,23 @@ Return number of matching entries found."
         (hyrolo-google-contacts-insert-generic-list emails "E-mails")
         (hyrolo-google-contacts-insert-generic-list phones "Phones")
         (hyrolo-google-contacts-insert-generic-list postal-addresses 
"Addresses"
-                                             (lambda (address)
-                                               
(google-contacts-add-margin-to-text (cdr address)
-                                                                               
    (+ 4 (length (car address))))))
+                                                   (lambda (address)
+                                                     
(google-contacts-add-margin-to-text (cdr address)
+                                                                               
          (+ 4 (length (car address))))))
         (hyrolo-google-contacts-insert-generic-list websites "Websites"
-                                             (lambda (website) (cdr website)))
+                                                   (lambda (website) (cdr 
website)))
         (hyrolo-google-contacts-insert-generic-list events "Events")
         (hyrolo-google-contacts-insert-generic-list relations "Relations"
-                                             (lambda (relation)
-                                               (widget-create 'link
-                                                              :button-prefix 
"" :button-suffix ""
-                                                              :action (lambda 
(widget &optional _event)
-                                                                        
(google-contacts (widget-value widget)))
-                                                              (cdr relation))
-                                               ""))
+                                                   (lambda (relation)
+                                                     (widget-create 'link
+                                                                    
:button-prefix "" :button-suffix ""
+                                                                    :action 
(lambda (widget &optional _event)
+                                                                               
(google-contacts (widget-value widget)))
+                                                                    (cdr 
relation))
+                                                     ""))
         (hyrolo-google-contacts-insert-generic-list instant-messaging "Instant 
messaging"
-                                             (lambda (im)
-                                               (concat (cddr im) " (" (cadr 
im) ")")))
+                                                   (lambda (im)
+                                                     (concat (cddr im) " (" 
(cadr im) ")")))
 
         (when birthday
           (insert "\n" (google-contacts-margin-element) "Birthday: " birthday 
"\n"))
@@ -1640,7 +1590,7 @@ Return number of matching entries found."
   ;; Save pattern as last rolo search expression.
   (setq hyrolo-match-regexp pattern)
   ;;
-  (let ((new-buf-p) (actual-buf)
+  (let ((new-buf-flag) (actual-buf)
        ;; Disable magit-auto-revert-mode-enable-in-buffers for hyrolo
        ;; buffers; not needed and can slow/hang file loading
        (after-change-major-mode-hook
@@ -1649,7 +1599,7 @@ Return number of matching entries found."
             (or (setq actual-buf (hyrolo-buffer-exists-p hyrolo-file-or-buf))
                 (when (file-exists-p hyrolo-file-or-buf)
                   (setq actual-buf (hyrolo-find-file-noselect 
hyrolo-file-or-buf)
-                        new-buf-p t))))
+                        new-buf-flag t))))
        (let ((hdr-pos) (num-found 0) (curr-entry-level-len)
              (incl-hdr t)
              (stuck-negative-point 0)
@@ -1661,7 +1611,7 @@ Return number of matching entries found."
                   (setq incl-hdr nil
                         max-matches (- max-matches)))))
          (set-buffer actual-buf)
-         (when new-buf-p
+         (when new-buf-flag
            (setq buffer-read-only t))
          (setq stuck-negative-point
                (catch 'stuck
@@ -1717,7 +1667,7 @@ Return number of matching entries found."
                                  (goto-char (point-max))
                                  (if hdr-pos
                                      (progn
-                                       (insert-buffer-substring-no-properties
+                                       (insert-buffer-substring
                                         actual-buf (car hdr-pos) (cdr hdr-pos))
                                        (insert src-line "\n\n"))
                                    (insert (format hyrolo-hdr-format 
src-line)))
@@ -1727,6 +1677,8 @@ Return number of matching entries found."
                              (hyrolo-add-match hyrolo-display-buffer pattern 
entry-start (point)))
                          (setq backward-search-limit (point))))))
                  num-found))
+         (when (and (> num-found 0) (not count-only))
+           (hyrolo--cache-major-mode (current-buffer)))
          (when (< stuck-negative-point 0)
            (pop-to-buffer (current-buffer))
            (goto-char (- stuck-negative-point))
@@ -1737,6 +1689,8 @@ Return number of matching entries found."
 
 (defun hyrolo-map-level (func level-regexp &optional max-groupings)
   "Perform FUNC in current buffer on groupings of entries at level 
LEVEL-REGEXP.
+Current buffer should be an editable HyRolo source location, not the match 
buffer.
+
 Limit to a maximum of optional argument MAX-GROUPINGS.  Nil value
 of MAX-GROUPINGS means all groupings at the given level.  FUNC
 should take two arguments, the start and the end of the region
@@ -1796,8 +1750,31 @@ Return number of groupings matched."
        (funcall func start end)))
     num-found))
 
+(define-minor-mode hyrolo-outline-minor-mode
+  "Toggle HyRolo Outline minor mode for display matches buffer.
+This mode does not add any outline-related font-locking.
+
+See the command `outline-mode' for more information on this mode."
+  nil " Outl" nil
+  (if hyrolo-outline-minor-mode
+      (progn
+       ;; Turn off this mode if we change major modes.
+       (add-hook 'change-major-mode-hook
+                 (lambda () (hyrolo-outline-minor-mode -1))
+                 nil t)
+        (setq-local line-move-ignore-invisible t)
+       ;; Cause use of ellipses for invisible text.
+       (add-to-invisibility-spec '(outline . t)))
+    (when outline-minor-mode-cycle
+      (remove-overlays nil nil 'outline-overlay t))
+    (setq line-move-ignore-invisible nil)
+    ;; Cause use of ellipses for invisible text.
+    (remove-from-invisibility-spec '(outline . t))
+    ;; When turning off outline mode, get rid of any outline hiding.
+    (hyrolo-outline-show-all)))
+
 (defun hyrolo-mode ()
-  "Major mode for the rolo match buffer.
+  "Major mode for the HyRolo display match buffer.
 Calls the functions given by `hyrolo-mode-hook'.
 \\{hyrolo-mode-map}"
   (interactive)
@@ -1805,7 +1782,13 @@ Calls the functions given by `hyrolo-mode-hook'.
     ;; This next local value is dynamically overridden in `hyrolo-grep'.
     (setq-local outline-regexp (default-value 'outline-regexp)
                hyrolo-entry-regexp (default-value 'hyrolo-entry-regexp)
-               outline-level #'hyrolo-mode-outline-level)
+               outline-level #'hyrolo-mode-outline-level
+               ;; Can't cycle because {TAB} moves to next match
+               outline-minor-mode-cycle nil
+               ;; For speed reasons, don't want to ever font-lock
+               ;; in this mode
+               outline-minor-mode-highlight nil)
+
     (reveal-mode 1)) ;; Expose hidden text as move into it.
   (setq major-mode 'hyrolo-mode
        mode-name "HyRolo")
@@ -1813,8 +1796,7 @@ Calls the functions given by `hyrolo-mode-hook'.
   ;;
   (set-syntax-table hyrolo-mode-syntax-table)
   ;;
-  (when (fboundp 'outline-minor-mode)
-    (outline-minor-mode 1))
+  (hyrolo-outline-minor-mode 1) ;; no keymap
   (run-hooks 'hyrolo-mode-hook))
 
 (defun hyrolo-next-visible-heading (arg)
@@ -1825,6 +1807,175 @@ A heading line is one that starts with a `*' (or that
   (interactive "p")
   (hyrolo-move-forward #'outline-next-visible-heading arg))
 
+;;; In `hyrolo-mode' replace `outline-minor-mode' bindings with hyrolo-* 
overrides.
+;;; Wrap outline movement commands with a `hyrolo-funcall-match' call
+;;; Wrap outline whole buffer commands with a `hyrolo-map-matches' call
+(defun hyrolo-outline-back-to-heading (&optional invisible-ok)
+  "Move to previous heading line, or beg of this line if it's a heading.
+Only visible heading lines are considered, unless INVISIBLE-OK is non-nil."
+  (hyrolo-funcall-match (lambda () (outline-back-to-heading invisible-ok))))
+
+(defun hyrolo-outline-backward-same-level (arg)
+  "Move backward to the ARG'th subheading at same level as this one.
+Stop at the first and last subheadings of a superior heading."
+  (interactive "p")
+  (hyrolo-funcall-match (lambda () (outline-backward-same-level arg))))
+
+(defun hyrolo-outline-demote (&optional which)
+  "Demote headings lower down the tree.
+If `transient-mark-mode' is on, and mark is active, demote headings in
+the region (from a Lisp program, pass `region' for WHICH).  Otherwise:
+without prefix argument, demote current heading and all headings in the
+subtree (from a Lisp program, pass `subtree' for WHICH); with prefix
+argument, demote just the current heading (from a Lisp program, pass
+nil for WHICH, or do not pass any argument)."
+  (interactive
+   (list (if (and transient-mark-mode mark-active) 'region
+          (outline-back-to-heading)
+          (if current-prefix-arg nil 'subtree))))
+  (hyrolo-funcall-match (lambda () (outline-demote which))))
+
+(defun hyrolo-outline-forward-same-level (arg)
+  "Move forward to the ARG'th subheading at same level as this one.
+Stop at the first and last subheadings of a superior heading."
+  (interactive "p")
+  (hyrolo-funcall-match (lambda () (outline-forward-same-level arg))))
+
+(defun hyrolo-outline-hide-body ()
+  "Hide all body lines in buffer, leaving all headings visible.
+Note that this does not hide the lines preceding the first heading line."
+  (interactive)
+  (hyrolo-map-matches #'outline-hide-body))
+
+(defun hyrolo-outline-hide-entry ()
+  "Hide the body directly following this heading."
+  (interactive)
+  (hyrolo-funcall-match #'outline-hide-entry))
+
+(defun hyrolo-outline-hide-leaves ()
+  "Hide the body after this heading and at deeper levels."
+  (interactive)
+  (hyrolo-funcall-match #'outline-hide-leaves))
+
+(defun hyrolo-outline-hide-other ()
+  "Hide everything except current body and parent and top-level headings.
+This also unhides the top heading-less body, if any."
+  (interactive)
+  (hyrolo-funcall-match #'outline-hide-other))
+
+(defun hyrolo-outline-hide-sublevels (levels)
+  "Hide everything but the top LEVELS levels of headers, in whole buffer.
+This also unhides the top heading-less body, if any.
+
+Interactively, the prefix argument supplies the value of LEVELS.
+When invoked without a prefix argument, LEVELS defaults to the level
+of the current heading, or to 1 if the current line is not a heading."
+  (interactive (list
+               (cond
+                (current-prefix-arg (prefix-numeric-value current-prefix-arg))
+                ((save-excursion (beginning-of-line)
+                                 (looking-at outline-regexp))
+                 (funcall outline-level))
+                (t 1))))
+  (hyrolo-map-matches (lambda () (outline-hide-sublevels levels))))
+
+(defun hyrolo-outline-hide-subtree ()
+  "Move back to the start of current subtree and hide everything after the 
heading.
+
+Necessary, since with reveal-mode active, outline-hide-subtree works
+only if on the heading line of the subtree."
+  (interactive)
+  (hyrolo-funcall-match
+   (lambda ()
+     (let ((opoint (point)))
+       (forward-line 0)
+       (unless (looking-at outline-regexp)
+        (outline-previous-visible-heading 1))
+       (if (looking-at outline-regexp)
+          (outline-hide-subtree)
+        (goto-char opoint))))))
+
+(defun hyrolo-outline-insert-heading ()
+  "Insert a new heading at same depth at point."
+  (interactive)
+  (hyrolo-funcall-match #'outline-insert-heading))
+
+(defun hyrolo-outline-mark-subtree ()
+  "Mark the current subtree in an outlined document.
+This puts point at the start of the current subtree, and mark at the end."
+  (interactive)
+  (hyrolo-funcall-match #'outline-mark-subtree))
+
+(defun hyrolo-outline-move-subtree-down (&optional arg)
+  "Move the current subtree down past ARG headlines of the same level."
+  (interactive "p")
+  (hyrolo-funcall-match (lambda () (outline-move-subtree-down arg))))
+
+(defun hyrolo-outline-move-subtree-up (&optional arg)
+  "Move the current subtree up past ARG headlines of the same level."
+  (interactive "p")
+  (hyrolo-funcall-match (lambda () (outline-move-subtree-up arg))))
+
+(defun hyrolo-outline-next-visible-heading (arg)
+  "Move to the next visible heading line.
+With ARG, repeats or can move backward if negative.
+A heading line is one that starts with a `*' (or that
+`outline-regexp' matches)."
+  (interactive "p")
+  (hyrolo-funcall-match (lambda () (outline-next-visible-heading arg))))
+
+(defun hyrolo-outline-previous-visible-heading (arg)
+  "Move to the previous heading line.
+With ARG, repeats or can move forward if negative.
+A heading line is one that starts with a `*' (or that
+`outline-regexp' matches)."
+  (interactive "p")
+  (hyrolo-funcall-match (lambda () (outline-previous-visible-heading arg))))
+
+(defun hyrolo-outline-promote (&optional which)
+  "Promote headings higher up the tree.
+If `transient-mark-mode' is on, and mark is active, promote headings in
+the region (from a Lisp program, pass `region' for WHICH).  Otherwise:
+without prefix argument, promote current heading and all headings in the
+subtree (from a Lisp program, pass `subtree' for WHICH); with prefix
+argument, promote just the current heading (from a Lisp program, pass
+nil for WHICH, or do not pass any argument)."
+  (interactive
+   (list (if (and transient-mark-mode mark-active) 'region
+          (outline-back-to-heading)
+          (if current-prefix-arg nil 'subtree))))
+  (hyrolo-funcall-match (lambda () (outline-promote which))))
+
+;;; Don't need to override but alias them for completeness
+(defalias 'hyrolo-outline-show-all 'outline-show-all)
+(defalias 'hyrolo-outline-show-branches 'outline-show-branches)
+
+(defun hyrolo-outline-show-children (&optional level)
+  "Show all direct subheadings of this heading.
+Prefix arg LEVEL is how many levels below the current level should be shown.
+Default is enough to cause the following heading to appear."
+  (interactive "P")
+  (hyrolo-funcall-match (lambda () (outline-show-children level))))
+
+(defun hyrolo-outline-show-entry ()
+  "Show the body directly following this heading.
+Show the heading too, if it is currently invisible."
+  (interactive)
+  (hyrolo-funcall-match #'outline-show-entry))
+
+(defun hyrolo-outline-show-subtree ()
+  "Show everything after this heading at deeper levels."
+  (interactive)
+  (hyrolo-funcall-match
+   (lambda () (outline-show-subtree))))
+
+(defun hyrolo-outline-up-heading (arg &optional invisible-ok)
+  "Move to the visible heading line of which the present line is a subheading.
+With argument, move up ARG levels.
+If INVISIBLE-OK is non-nil, also consider invisible lines."
+  (interactive "p")
+  (hyrolo-funcall-match (lambda () (outline-up-heading arg invisible-ok))))
+
 (defun hyrolo-previous-visible-heading (arg)
   "Move to the previous heading line.
 With ARG, repeats or can move forward if negative.
@@ -1931,7 +2082,7 @@ beginning of the highest ancestor level.  Return final 
point."
 
 (defun hyrolo-to-entry-end (&optional include-sub-entries 
_curr-entry-level-len)
   "Move point past the end of the current entry.
-With optional prefix arg INCLUDE-SUB-ENTRIES non-nil, move past
+oWith optional prefix arg INCLUDE-SUB-ENTRIES non-nil, move past
 the end of the entire subtree.  Return final point.
 
 CURR-ENTRY-LEVEL-LEN is the integer length of the last entry
@@ -2053,6 +2204,10 @@ HYROLO-BUF is optional; the default is the current 
buffer."
   (and hyrolo-kill-buffers-after-use (not (buffer-modified-p hyrolo-buf))
        (kill-buffer hyrolo-buf)))
 
+(defun hyrolo-markdown-outline-level ()
+  "Fix markdown `outline-level' function to always return a non-nil level."
+  (or (markdown-outline-level) 1))
+
 (defun hyrolo-name-and-email ()
   "If point is in a mail message, return list of (name email-addr) of sender.
 Name is returned as `last, first-and-middle'."
@@ -2174,30 +2329,30 @@ matched from an outline is level 3, then levels 3 and 4 
will be
 shown."
   (outline-show-all)
   (save-excursion
-     (goto-char (point-min))
-     (if (not (re-search-forward hyrolo-hdr-regexp nil t 2))
-        (outline-hide-sublevels num-levels)
-       (goto-char (point-min))
-       (let (start
-            end
-            max-level-to-show)
-        (while (re-search-forward hyrolo-hdr-regexp nil t 2)
-          (forward-line)
-          (setq start (point)
-                end (if (re-search-forward hyrolo-hdr-regexp nil t)
-                        (progn (beginning-of-line) (point))
-                      (goto-char (point-max))))
-          (save-restriction
-            (narrow-to-region start end)
-            (if (> num-levels 20)
-                (setq max-level-to-show num-levels)
-              (setq max-level-to-show (+ (hyrolo-min-matched-level)
-                                         (1- num-levels))))
-            (outline-hide-sublevels max-level-to-show)))))
-     (goto-char (point-min))
-     ;; This pause forces a window redisplay that maximizes the
-     ;; entries displayed for any final location of point.
-     (sit-for 0.001))
+    (goto-char (point-min))
+    (if (not (re-search-forward hyrolo-hdr-regexp nil t 2))
+       (outline-hide-sublevels num-levels)
+      (goto-char (point-min))
+      (let (start
+           end
+           max-level-to-show)
+       (while (re-search-forward hyrolo-hdr-regexp nil t 2)
+         (forward-line)
+         (setq start (point)
+               end (if (re-search-forward hyrolo-hdr-regexp nil t)
+                       (progn (beginning-of-line) (point))
+                     (goto-char (point-max))))
+         (save-restriction
+           (narrow-to-region start end)
+           (if (> num-levels 20)
+               (setq max-level-to-show num-levels)
+             (setq max-level-to-show (+ (hyrolo-min-matched-level)
+                                        (1- num-levels))))
+           (outline-hide-sublevels max-level-to-show)))))
+    (goto-char (point-min))
+    ;; This pause forces a window redisplay that maximizes the
+    ;; entries displayed for any final location of point.
+    (sit-for 0.001))
   ;; Need to leave point on a visible character or since
   ;; hyrolo uses reveal-mode, redisplay will rexpand
   ;; hidden entries to make point visible.
@@ -2223,29 +2378,33 @@ shown."
 (defun hyrolo-move-backward (func &rest args)
   "Move back past any file header and apply FUNC to ARGS.
 Return final point."
-  ;; Prevent error when calling 'func' when within a file header.
-  (while (and (looking-at hyrolo-hdr-regexp)
-             (outline-previous-heading)))
-  (apply #'funcall func args)
-  ;; If on a file header, skip to its beginning.
-  (while (and (looking-at hyrolo-hdr-regexp)
-             (outline-previous-heading)))
-  (point))
+  (hyrolo-funcall-match
+   (lambda ()
+     ;; Prevent error when calling 'func' when within a file header.
+     (while (and (looking-at hyrolo-hdr-regexp)
+                (outline-previous-heading)))
+     (apply #'funcall func args)
+     ;; If on a file header, skip to its beginning.
+     (while (and (looking-at hyrolo-hdr-regexp)
+                (outline-previous-heading)))
+     (point))))
 
 (defun hyrolo-move-forward (func &rest args)
   "Move forward past any file header and apply FUNC to ARGS.
 Return final point."
-  (let (in-hdr)
-    (while (looking-at hyrolo-hdr-regexp)
-      (when (outline-next-heading)
-       (setq in-hdr t)))
-    (unless in-hdr
-      (condition-case nil
-         (apply #'funcall func args)
-       ;; Prevent error and move past file header.
-       (error (while (and (outline-next-heading)
-                          (looking-at hyrolo-hdr-regexp)))))))
-  (point))
+  (hyrolo-funcall-match
+   (lambda ()
+     (let (in-hdr)
+       (while (looking-at hyrolo-hdr-regexp)
+        (when (outline-next-heading)
+          (setq in-hdr t)))
+       (unless in-hdr
+        (condition-case nil
+            (apply #'funcall func args)
+          ;; Prevent error and move past file header.
+          (error (while (and (outline-next-heading)
+                             (looking-at hyrolo-hdr-regexp)))))))
+     (point))))
 
 (defun hyrolo-mode-outline-level ()
   "Heuristically determine `outline-level' function to use in HyRolo match 
buffer."
@@ -2297,6 +2456,225 @@ trailing periods and whitespace."
   (or (cdr (assoc (match-string 0) outline-heading-alist))
       (1- (- (match-end 0) (match-beginning 0)))))
 
+;;; ************************************************************************
+;;; Caching of buffer major-modes for use in HyRolo display match buffer
+;;; ************************************************************************
+
+(defvar hyrolo--cache-loc-match-bounds '(1)
+  "Ordered list of the bounds of each matched buffer in Hyrolo display buffer.
+First entry represents the start of the first matched buffer and the
+remaining entries are the end points of each matched buffer with the
+HyRolo display matches buffer.")
+
+(defvar hyrolo--cache-major-mode-indexes '(0)
+  "Ordered list of major-mode-indexes `hyrolo--cache-loc-match-bounds' 
positions.")
+
+(defvar hyrolo--cache-major-mode-index 1
+  "Next index value to use when caching buffer-local values.")
+
+(defvar hyrolo--cache-major-mode-to-index-hasht nil
+  "Hash table with `major-mode' name keys and integer major-mode index 
values.")
+
+(defvar hyrolo--cache-index-to-major-mode-hasht nil
+  "Hash table with integer major-mode index keys and `major-mode' values.")
+
+(defun hyrolo-map-matches (func)
+  "Map FUNC with no arguments over the current buffer of entries.
+FUNC must not move point nor change the narrowing restriction, as
+this function will restore both of those.
+
+If on a display match entry, set the appropriate major mode based on
+its source location."
+  (let ((display-buf (get-buffer hyrolo-display-buffer)))
+    (if (eq (current-buffer) display-buf)
+       (progn
+         (when (or (< (length hyrolo--cache-loc-match-bounds) 1)
+                   (not (get-buffer hyrolo-display-buffer)))
+           (error "(hryolo-map-matches): No HyRolo matches in display buffer"))
+         (let ((bounds hyrolo--cache-loc-match-bounds)
+               (ofont-lock font-lock-mode)
+               (omode major-mode)
+               start
+               end)
+           (unwind-protect
+               (save-excursion
+                 (save-restriction
+                   (while (setq start (car bounds)
+                                end (cadr bounds))
+                     (setq end (1- end)
+                           bounds (cdr bounds))
+                     (narrow-to-region start end)
+                     (goto-char start)
+                     (let ((font-lock-mode))
+                       (hyrolo-cache-set-major-mode (1+ start))
+                       (setq font-lock-mode nil) ;; Prevent Org mode from 
font-locking
+                       (funcall func)))))
+             ;; Restore original mode and font-locking
+             (funcall omode)
+             (font-lock-mode (if ofont-lock 1 0))
+             (when (fboundp 'orgtbl-mode)
+               ;; Disable as overrides single letter keys
+               (orgtbl-mode 0)))))
+      (save-excursion
+       (save-restriction
+         (funcall func))))))
+
+(defun hyrolo-funcall-match (func)
+  "Apply FUNC with no arguments to the entry at point.
+FUNC must not change the narrowing restriction as this function will
+restore it.
+
+If on a display match entry, set the appropriate major mode based on
+its source location."
+  (let ((display-buf (get-buffer hyrolo-display-buffer)))
+    (if (eq (current-buffer) display-buf)
+       (progn
+         (when (or (< (length hyrolo--cache-loc-match-bounds) 1)
+                   (not (get-buffer hyrolo-display-buffer)))
+           (error "(hryolo-funcall-match): No HyRolo matches in display 
buffer"))
+         (let ((ofont-lock font-lock-mode)
+               (omode major-mode))
+           (unwind-protect
+               (save-restriction
+                 (set-buffer display-buf)
+                 (cl-destructuring-bind (start end)
+                     (hyrolo-cache-location-start-and-end)
+                   (when end
+                     (setq end (1- end))
+                     (narrow-to-region start end)
+                     (let ((font-lock-mode))
+                       (hyrolo-cache-set-major-mode (1+ start))
+                       ;; Prevent Org and Outline minor modes from font-locking
+                       (setq font-lock-mode nil)
+                       (funcall func)))))
+             ;; Restore original mode and font-locking
+             (funcall omode)
+             (font-lock-mode (if ofont-lock 1 0))
+             (when (fboundp 'orgtbl-mode)
+               ;; Disable as overrides single letter keys
+               (orgtbl-mode 0)))))
+      (save-restriction
+       (funcall func)))))
+
+(defun hyrolo-cache-location-start-and-end ()
+  "Return a list of the (start end) of location matches that point is within.
+Assume point is in the HyRolo display matches buffer.
+
+Both positions may be nil if there are no matches yet found."
+  (let ((end-seq-pos (seq-position hyrolo--cache-loc-match-bounds (point) 
(lambda (e pos) (< pos e)))))
+    (if end-seq-pos
+       (list (nth (1- end-seq-pos) hyrolo--cache-loc-match-bounds)
+             (nth end-seq-pos hyrolo--cache-loc-match-bounds))
+      (list nil nil))))
+
+(defun hyrolo-cache-set-major-mode (pos)
+  "Set the `major-mode' for POS in the HyRolo display buffer.
+Add `hyrolo-hdr-regexp' to `hyrolo-entry-regexp' and `outline-regexp'."
+  (funcall
+   (hyrolo--cache-get-major-mode-from-index
+    (nth (seq-position hyrolo--cache-loc-match-bounds pos (lambda (e pos) (< 
pos e)))
+        hyrolo--cache-major-mode-indexes)))
+  (unless (string-prefix-p hyrolo-hdr-regexp hyrolo-entry-regexp)
+    (setq-local hyrolo-entry-regexp (concat hyrolo-hdr-regexp "\\|" 
hyrolo-entry-regexp)))
+  (unless (string-prefix-p hyrolo-hdr-regexp outline-regexp)
+    (setq-local outline-regexp (concat hyrolo-hdr-regexp "\\|" 
outline-regexp)))
+  (when (eq outline-level #'markdown-outline-level)
+    (setq-local outline-level #'hyrolo-markdown-outline-level)))
+
+(defun hyrolo--cache-get-major-mode-from-index (major-mode-index)
+  "Return `major-mode' key from hash table entry with key MAJOR-MODE-INDEX, 
else nil."
+  (gethash major-mode-index hyrolo--cache-index-to-major-mode-hasht))
+
+(defun hyrolo--cache-initialize ()
+  "Init cache hash table of (major-mode-name . loc-seq-number) key value pairs.
+Call whenever `hyrolo--expanded-file-list' is changed."
+  (setq hyrolo--cache-major-mode-to-index-hasht (if (hash-table-p 
hyrolo--cache-major-mode-to-index-hasht)
+                                                   (clrhash 
hyrolo--cache-major-mode-to-index-hasht)
+                                                 (make-hash-table))
+       hyrolo--cache-index-to-major-mode-hasht (if (hash-table-p 
hyrolo--cache-index-to-major-mode-hasht)
+                                                   (clrhash 
hyrolo--cache-index-to-major-mode-hasht)
+                                                 (make-hash-table))
+       ;; Don't use '(1) on the next line or the code will not initialize 
properly
+       hyrolo--cache-loc-match-bounds (list 1)
+       hyrolo--cache-major-mode-indexes (list 0)
+       hyrolo--cache-major-mode-index 1))
+
+;; TODO: !! See if need 'hyrolo-outline-level' or
+;;          'hyrolo-mode-outline-level' any more?
+;; TODO: !! Lookup hyrolo-entry-regexp like outline-regexp.
+
+(defun hyrolo--cache-major-mode (matched-buf)
+  "Cache buffer `major-mode' for MATCHED-BUF with point in HyRolo display 
buffer.
+MATCHED-BUF must be a live buffer, not a buffer name.
+
+Push (point-max) of `hyrolo-display-buffer' onto 
`hyrolo--cache-loc-match-bounds'.
+Push hash table's index key to `hyrolo--cache-major-mode-indexes'.
+Ensure MATCHED-BUF's `major-mode' is stored in the hash table."
+  (when (> (length hyrolo--cache-loc-match-bounds) 4)
+    (debug))
+  (push (with-current-buffer hyrolo-display-buffer (point-max))
+       hyrolo--cache-loc-match-bounds)
+  (push hyrolo--cache-major-mode-index hyrolo--cache-major-mode-indexes)
+  (with-current-buffer matched-buf
+    (unless (gethash (symbol-name major-mode) 
hyrolo--cache-major-mode-to-index-hasht)
+      (puthash (symbol-name major-mode) hyrolo--cache-major-mode-index 
hyrolo--cache-major-mode-to-index-hasht)
+      (puthash hyrolo--cache-major-mode-index major-mode 
hyrolo--cache-index-to-major-mode-hasht)))
+  (setq hyrolo--cache-major-mode-index (1+ hyrolo--cache-major-mode-index)))
+
+(defun hyrolo--cache-post-display-buffer ()
+  "Cache updates to make after display buffer modifications are finished."
+  ;; Reverse both of the above lists to order them properly.
+  (setq hyrolo--cache-loc-match-bounds   (nreverse 
hyrolo--cache-loc-match-bounds)
+       hyrolo--cache-major-mode-indexes (nreverse 
hyrolo--cache-major-mode-indexes)))
+
+;;; ************************************************************************
+;;; hyrolo-mode key bindings - set after all library functions have
+;;; been defined
+;;; ************************************************************************
+
+(if hyrolo-mode-map
+    nil
+  (setq hyrolo-mode-map (make-sparse-keymap "HyRolo"))
+  (set-keymap-parent hyrolo-mode-map (copy-keymap outline-mode-prefix-map))
+  (suppress-keymap hyrolo-mode-map)
+  (define-key hyrolo-mode-map ","        'hyrolo-to-entry-beginning)
+  (define-key hyrolo-mode-map "."        'hyrolo-to-entry-end)
+  (define-key hyrolo-mode-map "<"        'beginning-of-buffer)
+  (define-key hyrolo-mode-map ">"        'end-of-buffer)
+  (define-key hyrolo-mode-map "?"        'describe-mode)
+  (define-key hyrolo-mode-map "\177"     'scroll-down)
+  (define-key hyrolo-mode-map " "        'scroll-up)
+  (define-key hyrolo-mode-map "a"        'outline-show-all)
+  (define-key hyrolo-mode-map "b"        'hyrolo-backward-same-level)
+  (define-key hyrolo-mode-map "e"        'hyrolo-edit-entry)
+  (define-key hyrolo-mode-map "f"        'hyrolo-forward-same-level)
+  (define-key hyrolo-mode-map "h"        'hyrolo-outline-hide-subtree)
+  (define-key hyrolo-mode-map "l"        'hyrolo-locate)
+  (define-key hyrolo-mode-map "m"        'hyrolo-mail-to)
+  (define-key hyrolo-mode-map "n"        'hyrolo-next-visible-heading)
+  (define-key hyrolo-mode-map "o"        'hyrolo-overview)
+  (define-key hyrolo-mode-map "p"        'hyrolo-previous-visible-heading)
+  (define-key hyrolo-mode-map "q"        'hyrolo-quit)
+  (define-key hyrolo-mode-map "r"        'hyrolo-grep-or-fgrep)
+  (define-key hyrolo-mode-map "s"        'hyrolo-outline-show-subtree)
+  (define-key hyrolo-mode-map "\M-s"     'hyrolo-isearch)
+  (define-key hyrolo-mode-map "t"        'hyrolo-top-level)
+  (define-key hyrolo-mode-map "\C-i"     'hyrolo-next-match)      ;; {TAB}
+  (define-key hyrolo-mode-map "\M-\C-i"  'hyrolo-previous-match)  ;; {M-TAB}
+  (define-key hyrolo-mode-map [backtab]  'hyrolo-previous-match)  ;; 
{Shift-TAB}
+  (define-key hyrolo-mode-map "u"        'hyrolo-up-heading)
+  (let (otl-cmd-name
+       hyrolo-cmd-name
+       hyrolo-cmd)
+    (map-keymap
+     (lambda (event otl-cmd)
+       (when (and (event-basic-type event) ;; key or mouse event
+                 (symbolp otl-cmd) (setq otl-cmd-name (symbol-name otl-cmd))
+                 (setq hyrolo-cmd-name (intern-soft (concat "hyrolo-" 
otl-cmd-name)))
+                 (setq hyrolo-cmd (intern-soft hyrolo-cmd-name)))
+        (define-key hyrolo-mode-map (vector 'remap otl-cmd) hyrolo-cmd)))
+     outline-mode-prefix-map)))
+
 (provide 'hyrolo)
 
 ;;; hyrolo.el ends here
diff --git a/kotl/kotl-mode.el b/kotl/kotl-mode.el
index 2fd9af07d9..057647bbdf 100644
--- a/kotl/kotl-mode.el
+++ b/kotl/kotl-mode.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    6/30/93
-;; Last-Mod:      2-Dec-23 at 17:28:41 by Bob Weiner
+;; Last-Mod:     11-Dec-23 at 01:32:59 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -20,8 +20,8 @@
 ;;; ************************************************************************
 
 (eval-when-compile '(require 'klink)) ;; hibtypes.el loads this at run-time
-(eval-and-compile (mapc #'require '(cl-lib delsel hsettings hmail hypb kfile 
klabel
-                                   outline org org-table kotl-orgtbl)))
+(eval-and-compile (mapc #'require '(cl-lib delsel hsettings hmail hypb hyrolo
+                                   kfile klabel outline org org-table 
kotl-orgtbl)))
 
 ;;; ************************************************************************
 ;;; Public declarations
@@ -191,31 +191,37 @@ It provides the following keys:
 
   (setq auto-fill-function 'kfill:do-auto-fill)
 
-  ;; If buffer has not yet been formatted for editing, format it.
-  (let (version)
-    ;; Koutline file that has been loaded but not yet formatted for editing.
-    (if (setq version (kfile:is-p))
-        ;; Koutline file that has been loaded and formatted for editing.
-       (if (kview:is-p kotl-kview)
-           ;; The buffer might have been widened for inspection, so narrow to 
cells
-           ;; only.
-           (kfile:narrow-to-kcells)
-         (kfile:read
-          (current-buffer)
-          (and buffer-file-name (file-exists-p buffer-file-name))
-          version)
-         (kvspec:activate))
-      ;; New koutline buffer or a foreign text buffer that must be converted to
-      ;; koutline format.
-      (kfile:create (current-buffer))
-      (kvspec:activate)))
-  ;; We have been converting a buffer from a foreign format to a koutline.
-  ;; Now that it is converted, ensure that `kotl-previous-mode' is set to
-  ;; koutline.
-  (hyperb:with-suppressed-warnings ((free-vars kotl-previous-mode))
-    (setq kotl-previous-mode 'kotl-mode))
-  (run-hooks 'kotl-mode-hook)
-  (add-hook 'change-major-mode-hook #'kotl-mode:show-all nil t))
+  ;; May be a portion of a Koutline in a HyRolo match buffer; we set
+  ;; kotl-mode then to use its local variable settings but don't want
+  ;; to do any of the following formatting.
+  (if (string-prefix-p hyrolo-display-buffer (buffer-name))
+      (unless (and (boundp 'kotl-kview) (kview:is-p kotl-kview))
+       (kview:create (buffer-name))) ;; sets buffer-local `kotl-kview'
+    ;; If buffer has not yet been formatted for editing, format it.
+    (let (version)
+      ;; Koutline file that has been loaded but not yet formatted for editing.
+      (if (setq version (kfile:is-p))
+          ;; Koutline file that has been loaded and formatted for editing.
+         (if (kview:is-p kotl-kview)
+             ;; The buffer might have been widened for inspection, so narrow 
to cells
+             ;; only.
+             (kfile:narrow-to-kcells)
+           (kfile:read
+            (current-buffer)
+            (and buffer-file-name (file-exists-p buffer-file-name))
+            version)
+           (kvspec:activate))
+       ;; New koutline buffer or a foreign text buffer that must be converted 
to
+       ;; koutline format.
+       (kfile:create (current-buffer))
+       (kvspec:activate)))
+    ;; We have been converting a buffer from a foreign format to a koutline.
+    ;; Now that it is converted, ensure that `kotl-previous-mode' is set to
+    ;; koutline.
+    (hyperb:with-suppressed-warnings ((free-vars kotl-previous-mode))
+      (setq kotl-previous-mode 'kotl-mode))
+    (run-hooks 'kotl-mode-hook)
+    (add-hook 'change-major-mode-hook #'kotl-mode:show-all nil t)))
 
 ;;;###autoload
 (defun kotl-mode:example (&optional example replace-flag)
@@ -3458,36 +3464,42 @@ but always operates upon the current view."
                9999
              (current-column)))))
 
-(defun kotl-mode:to-visible-position (&optional backward-p)
+(defun kotl-mode:to-visible-position (&optional backward-flag)
   "Move point to nearest visible and editable position within current koutline.
-With optional BACKWARD-P, move backward if possible to get to valid position."
+With optional BACKWARD-FLAG, move backward if possible to get to valid 
position."
   ;; Empty, visible cell
   (unless (and (kotl-mode:bocp) (kotl-mode:eocp) (not (kcell-view:invisible-p 
(point))))
-    (if (if backward-p
+    (if (if backward-flag
            (invisible-p (1- (point)))
          (invisible-p (point)))
-       (goto-char (if backward-p
+       (goto-char (if backward-flag
                       (kview:previous-visible-point)
                     (kview:first-visible-point))))
-    (kotl-mode:to-valid-position backward-p)))
+    (kotl-mode:to-valid-position backward-flag)))
 
 ;;;###autoload
-(defun kotl-mode:to-valid-position (&optional backward-p)
+(defun kotl-mode:to-valid-position (&optional backward-flag)
   "Move point to the nearest editable position within the current koutline 
view.
-With optional BACKWARD-P, move backward if possible to get to valid position."
+With optional BACKWARD-FLAG, move backward if possible to get to valid 
position."
   (unless (kview:valid-position-p)
     (let ((lbl-sep-len (kview:label-separator-length kotl-kview)))
-      (cond ((kotl-mode:bobp)
-            (goto-char (kcell-view:start nil lbl-sep-len)))
-           ((kotl-mode:eobp)
-            (skip-chars-backward "\n\r"))
-           (t (when (bolp)
-                (if backward-p
-                    (skip-chars-backward "\n\r")
-                  (skip-chars-forward "\n\r")))
-              (let ((indent (kcell-view:indent nil lbl-sep-len)))
-                (when (< (current-column) indent)
-                  (move-to-column indent))))))))
+      (condition-case ()
+         (cond ((kotl-mode:bobp)
+                (goto-char (kcell-view:start nil lbl-sep-len)))
+               ((kotl-mode:eobp)
+                (skip-chars-backward "\n\r"))
+               (t (when (bolp)
+                    (if backward-flag
+                        (skip-chars-backward "\n\r")
+                      (skip-chars-forward "\n\r")))
+                  (let ((indent (kcell-view:indent nil lbl-sep-len)))
+                    (when (< (current-column) indent)
+                      (move-to-column indent)))))
+       (error
+        ;; May be on a file header in *HyRolo* match buffer; then
+        ;; move to next cell
+        (unless backward-flag
+          (kcell-view:next nil lbl-sep-len)))))))
 
 (defun kotl-mode:transpose-lines-internal (start end)
   "Transpose lines at START and END markers within an outline.
diff --git a/kotl/kview.el b/kotl/kview.el
index 3e5e11b63f..e3db327cb3 100644
--- a/kotl/kview.el
+++ b/kotl/kview.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    6/30/93
-;; Last-Mod:     25-Nov-23 at 16:34:27 by Mats Lidell
+;; Last-Mod:     11-Dec-23 at 01:47:48 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -524,7 +524,15 @@ Cell is at optional POS or point."
 Point is set at end of cell's label but before the label separator.
 If between kcells, move to the previous one.  The current cell may be hidden."
   (when pos (goto-char pos))
+  (when (eq (current-buffer) (get-buffer hyrolo-display-buffer))
+    ;; May need to move past header to a valid position in HyRolo
+    ;; display match buffer
+    (while (save-excursion (forward-line 0)
+                          (or (looking-at hyrolo-hdr-regexp)
+                              (looking-at hbut:source-prefix)))
+      (forward-line 1)))
   (kview:end-of-actual-line)
+
   (let (found)
     (unless (setq found (kproperty:get (1- (point)) 'kcell))
       ;; If not at beginning of cell contents, move there.
diff --git a/man/hyperbole.html b/man/hyperbole.html
index 776dc52c38..7ff9fdb17b 100644
--- a/man/hyperbole.html
+++ b/man/hyperbole.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd";>
 <html>
 <!-- This manual is for GNU Hyperbole
-(Edition 8.0.1pre, Published November, 2023).
+(Edition 9.0.0, Published December, 2023).
 
 Copyright (C) 1989-2023  Free Software Foundation, Inc.
 
@@ -381,8 +381,8 @@ WITHOUT ANY WARRANTY, without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.</P>
 
 <PRE>
-Edition 8.0.1pre
-Printed November 21, 2023.
+Edition 9.0.0
+Printed December 3, 2023.
 
   Published by the Free Software Foundation, Inc.
   Author:    Bob Weiner
@@ -904,7 +904,7 @@ Next: <a href="#Usage" accesskey="n" rel="next">Usage</a>, 
Previous: <a href="#T
 <h2 class="chapter">1 Introduction</h2>
 
 <p>This edition of the GNU Hyperbole Manual is for use with any version
-8.0.1pre or greater of GNU Hyperbole.  Hyperbole runs atop GNU Emacs 27.1
+9.0.0 or greater of GNU Hyperbole.  Hyperbole runs atop GNU Emacs 27.1
 or higher.  It will trigger an error if your Emacs is older.
 </p>
 <p>This chapter summarizes the structure of the rest of the manual,
diff --git a/man/hyperbole.info b/man/hyperbole.info
index 04893a642a..8d1890f832 100644
Binary files a/man/hyperbole.info and b/man/hyperbole.info differ
diff --git a/man/hyperbole.pdf b/man/hyperbole.pdf
index b724487ac2..6f491493fe 100644
Binary files a/man/hyperbole.pdf and b/man/hyperbole.pdf differ
diff --git a/man/hyperbole.texi b/man/hyperbole.texi
index 954c73e6fb..31f875bb3a 100644
--- a/man/hyperbole.texi
+++ b/man/hyperbole.texi
@@ -7,7 +7,7 @@
 @c Author:       Bob Weiner
 @c
 @c Orig-Date:     6-Nov-91 at 11:18:03
-@c Last-Mod:     21-Nov-23 at 03:27:45 by Bob Weiner
+@c Last-Mod:      3-Dec-23 at 09:46:58 by Bob Weiner
 
 @c %**start of header (This is for running Texinfo on a region.)
 @setfilename hyperbole.info
@@ -155,8 +155,8 @@ WITHOUT ANY WARRANTY, without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.</P>
 
 <PRE>
-Edition 8.0.1pre
-Printed November 21, 2023.
+Edition 9.0.0
+Printed December 3, 2023.
 
   Published by the Free Software Foundation, Inc.
   Author:    Bob Weiner
@@ -197,8 +197,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 @sp 2
 
 @example
-Edition 8.0.1pre
-November 21, 2023
+Edition 9.0.0
+December 3, 2023
 
   Published by the Free Software Foundation, Inc.
   Author:    Bob Weiner
@@ -512,7 +512,7 @@ Smart Keyboard Keys
 @chapter Introduction
 
 This edition of the GNU Hyperbole Manual is for use with any version
-8.0.1pre or greater of GNU Hyperbole.  Hyperbole runs atop GNU Emacs 27.1
+9.0.0 or greater of GNU Hyperbole.  Hyperbole runs atop GNU Emacs 27.1
 or higher.  It will trigger an error if your Emacs is older.
 
 This chapter summarizes the structure of the rest of the manual,
diff --git a/man/version.texi b/man/version.texi
index f7b32f07fc..a01e194cba 100644
--- a/man/version.texi
+++ b/man/version.texi
@@ -1,4 +1,4 @@
-@set UPDATED November, 2023
-@set UPDATED-MONTH November 2023
-@set EDITION 8.0.1pre
-@set VERSION 8.0.1pre
+@set UPDATED December, 2023
+@set UPDATED-MONTH December 2023
+@set EDITION 9.0.0
+@set VERSION 9.0.0
diff --git a/test/demo-tests.el b/test/demo-tests.el
index cd4f2c3324..c80bcb85d5 100644
--- a/test/demo-tests.el
+++ b/test/demo-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:    30-Jan-21 at 12:00:00
-;; Last-Mod:     22-Nov-23 at 23:22:33 by Mats Lidell
+;; Last-Mod:     11-Dec-23 at 01:58:53 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -67,7 +67,7 @@
         (re-search-forward " \\* Koutl")
         (action-key)
         (should (bolp))
-        (should (looking-at "^* Koutliner")))
+        (should (looking-at "^[ \t]*\\* Koutliner")))
     (hy-test-helpers:kill-buffer "DEMO")))
 
 ;; Smart scrolling
diff --git a/test/hibtypes-tests.el b/test/hibtypes-tests.el
index 93f6ebd6ba..21895fe01c 100644
--- a/test/hibtypes-tests.el
+++ b/test/hibtypes-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:    20-Feb-21 at 23:45:00
-;; Last-Mod:      2-Oct-23 at 05:02:34 by Bob Weiner
+;; Last-Mod:     11-Dec-23 at 02:08:38 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -237,10 +237,10 @@
       (progn
         (hypb:display-file-with-logo "DEMO")
         (goto-char (point-min))
-        (re-search-forward " \* Koutl")
+        (re-search-forward " \\* Koutl")
         (ibtypes::text-toc)
         (should (bolp))
-        (should (looking-at "^* Koutliner")))
+        (should (looking-at "^[ \t]*\\* Koutliner")))
     (kill-buffer "DEMO")))
 
 ;; dir-summary
diff --git a/test/hmouse-drv-tests.el b/test/hmouse-drv-tests.el
index b46ca20c31..1544020e2f 100644
--- a/test/hmouse-drv-tests.el
+++ b/test/hmouse-drv-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:    28-Feb-21 at 22:52:00
-;; Last-Mod:      2-Oct-23 at 05:03:07 by Bob Weiner
+;; Last-Mod:     11-Dec-23 at 01:57:54 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -461,10 +461,10 @@
       (progn
         (hypb:display-file-with-logo "DEMO")
         (goto-char (point-min))
-        (re-search-forward " \* Koutl")
+        (re-search-forward "^[ \t]*\\* Koutl")
         (action-key)
         (should (bolp))
-        (should (looking-at "^* Koutliner")))
+        (should (looking-at "^[ \t]*\\* Koutliner")))
     (hy-test-helpers:kill-buffer "DEMO")))
 
 ;; dir-summary

Reply via email to