branch: externals/hyperbole
commit 1773ce63928ea44706b5878fedac8551d356867e
Merge: 62e9eb4b24 29674ef91a
Author: Robert Weiner <r...@gnu.org>
Commit: GitHub <nore...@github.com>

    Merge pull request #679 from rswgnu/rsw
    
    - hywiki.el - Simplify per-char hook functions; improve hywiki-word-at
    - Latest rsw updates; hywiki hooks and hywiki-word-at rewritten
    - hywiki.el - Fix dehighlighting when first WikiWord char is deleted
    - hywiki-word-at - Fix delimited/non-delimited HyWikiWord handling
    - hywiki.el - Improve hywiki-word-at and hywiki-word-is-p #sections
    - hywiki.el - Fix much of hywiki-word-at and remove use of cl-lib
    - Fix hkey-alist vertico handling and more
    - hywiki.el, hsys-org.el - Fix a bunch of predicates and tests
---
 ChangeLog              | 228 +++++++++++++
 HY-ABOUT               |   2 +-
 Makefile               |   6 +-
 README.md              |   2 +-
 README.toc.md          |  19 +-
 hargs.el               |  14 +-
 hib-kbd.el             |   7 +-
 hibtypes.el            |  17 +-
 hmouse-drv.el          |  15 +-
 hmouse-tag.el          |   4 +-
 hpath.el               |   6 +-
 hproperty.el           |   9 +-
 hsys-org.el            |  88 ++++-
 hsys-xref.el           |   6 +-
 hui-mouse.el           |  29 +-
 hui-select.el          |  31 +-
 hypb.el                |  16 +-
 hyperbole.el           |   4 +-
 hywiki.el              | 906 ++++++++++++++++++++++++++++++++-----------------
 man/hyperbole.texi     |  30 +-
 test/MANIFEST          |   1 +
 test/hsys-org-tests.el |   7 +-
 test/hywiki-tests.el   | 160 ++++++---
 test/kcell-tests.el    |   4 +-
 24 files changed, 1160 insertions(+), 451 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 215bbbc140..ba518fa3f9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,81 @@
+2025-04-13  Bob Weiner  <r...@gnu.org>
+
+* hsys-org.el (hsys-org-thing-at-p): Fix to work outside of Org mode by
+    suppressing warnings and ignoring Org regex errors.  This fixes two
+    hsys-org tests where the 'www-url' ibtype fired instead of
+    'org-link-outside-org-mode'.
+              (hsys-org-link-at-p): Rewrite to fix sending back (start . end)
+    positions when on a link, to be used as an implicit button label.
+
+* hywiki.el (hywiki-section-to-headline-reference): Add to convert #section
+    dashes to spaces for matching to Org headlines.
+            (org-link-set-parameters): Set HyWiki's link type to call the above
+    function on HyWiki links so they properly match Org headlines.
+
+2025-04-12  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki-cache-save): Change to save any modified cache rather than
+    triggering an error (which can occur during regression testing).  This 
fixes
+    the `hywiki-tests--save-referent-info-node-use-menu' test.
+            (hywiki--buttonized-region-p): Add so buttonized region tests are
+    always handled correctly.  Use in the functions below.
+            (hywiki-convert-words-to-org-links,
+             hywiki-maybe-dehighlight-balanced-pairs,
+             hywiki-maybe-highlight-balanced-pairs,
+             hywiki-maybe-dehighlight-page-name,
+             hywiki-maybe-highlight-page-name,
+             hywiki--maybe-dehighlight-at-point,
+             hywiki--maybe-rehighlight-at-point): Fix to avoid using region
+    markers in a buffer other than the current one.  This also fixes a bug when
+    doing HyWiki exports to html and referencing the wrong buffer.
+
+* test/hywiki-tests.el (hywiki-tests--wikiword-step-check): Fix to not expect
+    closing paren delimiter as part of the WikiWord.
+
+* hywiki.el (hywiki-at-range-delimiter): Handle if scan-sexps returns nil then
+    return '(nil nil).
+
+* hypb.el (hypb:in-string-p): Update to handle change-log-mode which disables
+    syntax parsing and so is handled with a string search.
+
+* hmouse-drv.el (hkey-actions): Add for use in Hyperbole testing and call from
+    "test/hui-mouse-tests.el".
+
+* hui-mouse.el (hkey-alist): Ignore 'ivy-mode' if 'vertico-mode' is actively
+    prompting for an argument and allow for this outside of the minibuffer
+    since vertico may prompt within another buffer.  Also, ignore the value
+    of hargs:reading-type here, otherwise, it will not catch all uses of
+    'vertico-mode'.
+
+2025-04-07  Mats Lidell  <ma...@gnu.org>
+
+* test/MANIFEST: Add hui-mouse-tests.el
+
+* test/hui-mouse-tests.el (hui-mouse-tests--hkey-alist): Verify a
+    predicate setting leads to the proper action.
+    (hui-mouse-tests--hkey-get-action): Helper that gets primary action
+    and assist action from hkey-alist for the predicates in effect.
+
+2025-04-06  Bob Weiner  <r...@gnu.org>
+
+* test/hywiki-tests.el (hywiki-tests--wikiword-identified-in-emacs-lisp-mode):
+    Add this test from Mats with one correction.
+
+* hywiki.el (require cl-lib): Remove use.
+            (hywiki--org-export-new-title-reference): Remove use of 'cl-incf'.
+           (hywiki-maybe-at-wikiword-beginning,
+             hywiki-maybe-dehighlight-page-name,
+             hywiki-maybe-highlight-page-name
+             hywiki-word-at): Replace 'cl-find' with 'string-match' for speed.
+           (hywiki-buttonize-character-commands): Fix 'post-self-insert-hook'
+    so it highlights wikiwords after a closing delimiter is inserted.
+            (hywiki--maybe-rehighlight-at-point): Remove nullifying of
+    'hywiki--word-pre-command', 'hywiki--buttonize-start', 
'hywiki--buttonize-end'
+    and move this to the start of the hywiki 'pre-command-hook'
+    (hywiki-debuttonize-non-character-commands) so they are not nullified
+    by 'post-command-hook' before they can be used by 'post-self-insert-hook'.
+            (hywiki-delimited-p): Add support for strings as well.
+
 2025-04-06  Mats Lidell  <ma...@gnu.org>
 
 * test/hy-test-helpers.el (hy-test-run-failing-flag): Set to non-nil to
@@ -12,6 +90,30 @@
     (hywiki-tests--verify-hywiki-word): Add verification that
     hywiki-word-is-p agrees with hywiki-word-at.
 
+2025-04-05  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki-word-at, hywiki-word-is-p): If has a #section, ensure
+    there are no invalid chars.
+            (hywiki-word-at): Fix missing test for double quote as an opening
+    delimiter.
+
+* test/hywiki-tests.el (hywiki-tests--sections-with-dash-space): Update code
+    to ensure #section cannot contain quote marks.
+
+2025-03-30  Bob Weiner  <r...@gnu.org>
+
+* test/hywiki-tests.el (hywiki-tests--wikiword-step-check): Fix by removing
+    matching to trailing delimiters, since that is now fixed.
+
+* hywiki.el (hywiki-word-at): Fix so if not in a delimited HyWikiWord reference
+    or if such a reference contains more than one non-section word, then
+    disallow spaces in section names.
+    (hywiki-delimited-p): Add and use in above function.
+    (hywiki--get-delimited-range-backward, 
hywiki--get-delimited-range-forward):
+       Clarify required point position and inclusion of delimiters in the 
range.
+    (hywiki-word-highlighted-at-p): Add to return any highlighted wikiword ref
+       at point.
+
 2025-03-30  Mats Lidell  <ma...@gnu.org>
 
 * test/hywiki-tests.el (hywiki-tests--add-find): Remove hywiki-directory
@@ -58,6 +160,127 @@
     command while also executing the pre and post command hooks. Use it
     instead of the with-hywiki-buttonize macros.
 
+2025-03-17  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki-maybe-dehighlight-between-page-names): Fix to dehighlight
+    at point if on a highlighted prior WikiWork.
+            (hywiki--buttonize-characters): Add missing double quote char as
+    a match char to fix "WikiWord" not highlighting in a file when read in.
+
+2025-03-16  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki--rehighlight-at-point): Fix to dehighlight when the first
+    char of a wikiword is deleted.
+            (hywiki--maybe-rehighlight-at-point): Add maybe to the name.
+            (hywiki-maybe-dehighlight-page-name): Extract from above function
+    and use this standalone.
+
+* HY-ABOUT:
+  MELPA-RECIPE.el:
+  README.md:
+  man/hyperbole.texi:
+  hyperbole-pkg.el ("hyperbole"): Update requirement to Emacs version 28 from
+    27.2 since Markdown mode now requires this.
+
+2025-03-14  Bob Weiner  <r...@gnu.org>
+
+* hypb.el (hypb:in-string-p): Made return the start position of the string
+
+* hywiki.el (hywiki--page-name): Rename to 'hywiki--word-only'.
+            (hywiki--word-pre-command): Add for use in command hooks.
+            (hywiki-debuttonize-non-character-commands,
+             hywiki-buttonize-character-commands,
+             hywiki-buttonize-non-character-commands): Rewrite all of these
+    to capture the first HyWikiWord and then only dehighlight in post hooks
+    if the HyWikiWords has changed.
+
+2025-03-13  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki-word-at): Clarify :range return value in doc string.
+
+2025-03-08  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki-word-at): Fix so hy:WikiWord is recognized without any
+    delimiters.
+  hsys-org.el (hsys-org-link-at-p): Fix to handle Org links without square or
+    angle brackets, e.g. file:WikiWord.org.
+              (hsys-org-thing-at-p): Add to test if point is on a specific org
+    construct type, e.g. a link.
+              (hsys-org-link-at-p): Remove 'with-suppressed-warnings' since
+    inner call to 'hsys-org-thing-at-p' is now run only when in org mode.
+
+* test/hywiki-tests.el (hywiki-tests--convert-words-to-org-link): Fix expected
+value to be [[WikiWord]] not [[file:WikiWord.org][WikiWord]].
+
+2025-03-07  Bob Weiner  <r...@gnu.org>
+
+* test/hywiki-tests.el (hywiki-tests--wikiword-identified-with-delimiters):
+    Fix to show which wikiword item fails.
+
+* hywiki.el (hywiki-maybe-highlight-page-name): Fix to eliminate narrowing
+    of region that hides any balanced delimiters around a HyWikiWord.  Also
+    generalize HyWikiWord range finding using updated 'hywiki-word-at'.
+            (hywiki-word-at): Fix to allow whitespace between delimiters and
+    between #section words when delimited.  Also, if not on a wikiword and
+    'range-flag' is non-nil, return '(nil nil nil).
+
+2025-03-06  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki-maybe-highlight-between-page-names): Allow for whitespace
+    after opening delimiter.
+
+2025-03-02  Bob Weiner  <r...@gnu.org>
+
+* test/hywiki-tests.el (hywiki-tests--convert-words-to-org-link): Fix expected
+    link match strings.
+
+* hsys-xref.el (hsys-xref-identifier-at-point): Fix to return nil if xref 
returns
+    a pathname as an identifier.  This fixes a problem with the Action Key
+    triggering the wrong action; it should recognize it as a pathname.
+
+* test/hywiki-tests.el (hywiki-tests--add-org-roam-node): Mock variable,
+    `cl-struct-org-roam-node-tags' needed when org-roam package is not 
installed.
+
+2025-02-27  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki--maybe-de/highlight-sexp): Fix to narrow to region of
+    current HyWikiWord range before calling 'func'.
+            (hywiki--maybe-de/highlight-sexp): Add optional 'sexp-start' and
+    'sexp-end' args when known; range should include delimiters.
+            (hywiki-buttonize-character-commands,
+             hywiki-buttonize-non-character-commands): Pass 
'hywiki--buttonize-start'
+    and 'hywiki--buttonize-end' positions to 'hywiki--maybe-de/highlight-sexp'
+    when known rather than recomputing.
+
+* hproperty.el (hproperty:but-move): Add and use in "hywiki.el".
+
+* hywiki.el (hywiki-get-delimited-range): Rename to 
'hywiki-at-range-delimiter'.
+            (hywiki-referent-exists-p): Fix return value doc when given :range
+    arg.  Fix to send word string rather than tuple to 'hywiki-get-referent'.
+
+2025-02-25  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki-word-with-optional-spaces-suffix-exact-regexp): Remove
+    use in 'hywiki-word-is-p' and replace with
+    'hywiki-word-with-optional-suffix-exact-regexp' which actually allows 
spaces.
+            (hywiki-word-at): Add support for finding delimited WikiWords with
+    #sections that contain multiple space separated words and returning the
+    wikiword, start and end.
+            (hywiki-word-at): Fix last 'looking-at' expression to not match to
+    end of buffer.
+            (hywiki-buttonize-character-commands,
+             hywiki-buttonize-non-character-commands,
+             hywiki-debuttonize-non-character-commands): Rewrite and simplify.
+
+2025-02-24  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki--maybe-de/highlight-sexp): Ensure return the result of
+    calling 'func'.
+            (hywiki-buttonize-non-character-commands): Remove insert commands
+    handled by 'hywiki-buttonize-character-commands' attached to
+    'post-self-insert-hook'.
+            (hywiki-non-hook-context-p): Add.
+
 2025-03-07  Mats Lidell  <ma...@gnu.org>
 
 * hywiki.el (hywiki-convert-words-to-org-links)
@@ -128,8 +351,13 @@
 
 * hywiki.el (hywiki-referent-menu): Re-add accidentally deleted "Keys" key
     series referent type in the menu.
+            (hywiki-set-directory): Call as part of loading hywiki.el to ensure
+    HyWiki Org project publish settings are initialized.
             (hywiki--org-export-new-title-reference): Replace '--any' call from
     dash.el package with 'cl-some'.
+            (hywiki-buttonize-character-commands): In prog modes, limit to 
comments
+    and strings.  If within a delimited pair, highlight #sections with multiple
+    words.
 
 * test/hywiki-tests.el (hywiki-tests--convert-words-to-org-link): Fix to not
     expect 'hy:' prefix in HyWiki Org links.
diff --git a/HY-ABOUT b/HY-ABOUT
index da0954216c..9d43f05daa 100644
--- a/HY-ABOUT
+++ b/HY-ABOUT
@@ -11,7 +11,7 @@
 GNU Hyperbole (pronounced Ga-new Hi-per-bo-lee), or just Hyperbole, is
 an efficient and programmable hypertextual information management
 system implemented as a GNU Emacs package.  It works well on GNU Emacs
-27.2 or above.  (See also: "HY-WHY.kotl" for Hyperbole uses).
+28 or above.  (See also: "HY-WHY.kotl" for Hyperbole uses).
 
 Hyperbole includes easy-to-use, powerful hypertextual buttons without
 the need to learn a markup language; a hierarchical, record-based
diff --git a/Makefile b/Makefile
index 5611dac951..2a39b140be 100644
--- a/Makefile
+++ b/Makefile
@@ -3,9 +3,9 @@
 # Author:       Bob Weiner
 #
 # Orig-Date:    15-Jun-94 at 03:42:38
-# Last-Mod:      6-Apr-25 at 19:45:20 by Mats Lidell
+# Last-Mod:     12-Apr-25 at 13:15:02 by Bob Weiner
 #
-# Copyright (C) 1994-2023  Free Software Foundation, Inc.
+# Copyright (C) 1994-2025  Free Software Foundation, Inc.
 # See the file HY-COPY for license information.
 #
 # This file is part of GNU Hyperbole.
@@ -81,7 +81,7 @@
 #
 #               To interactively run a docker version of Emacs with Hyperbole:
 #                   make docker-run              - default to running master
-#                   make docker-run version=27.2 - run Emacs V27.2
+#                   make docker-run version=28.2 - run Emacs V28.2
 #
 #               To build and test a dockerized version of Emacs with Hyperbole:
 #                   make docker                  - defaults: version=master 
targets='clean bin test'
diff --git a/README.md b/README.md
index bf039a4d66..c91f9c8fe3 100644
--- a/README.md
+++ b/README.md
@@ -146,7 +146,7 @@ keyboard and mouse-based control of information display 
within multiple
 windows.  It also provides point-and-click access to World-Wide Web URLs,
 Info manuals, ftp archives, etc.
 
-Hyperbole works well on GNU Emacs 27.2 or above.  It is designed and written
+Hyperbole works well on GNU Emacs 28 or above.  It is designed and written
 by Bob Weiner.  It is maintained by him and Mats Lidell.  Its main
 distribution site is: <https://www.gnu.org/software/hyperbole/>.  If any
 term in here is new or unfamiliar to you, you can look it up in the
diff --git a/README.toc.md b/README.toc.md
index 9fb84e7230..c91f9c8fe3 100644
--- a/README.toc.md
+++ b/README.toc.md
@@ -2,12 +2,23 @@
 
 [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
- Hyperbole (mailto:r...@gnu.org)].
+ Hyperbole to [r...@gnu.org](mailto:r...@gnu.org)].
 
 [TOC]
 
 ![Hyperbole screenshot of the Koutliner, DEMO file and 
HyRolo](man/im/hyperbole-cv.png)
 
+## Reference Manual
+
+Hyperbole has many features you can explore interactively or by reading 
sections of
+the reference manual:
+
+   - [Browse Hyperbole Web Manual](man/hyperbole.html)
+
+   - [In Emacs, Browse Hyperbole Info Manual](man/hyperbole.info)
+
+   - [Display or Print PDF Manual](man/hyperbole.pdf)
+
 ## Videos
 
 If you prefer video introductions, visit the videos linked to below;
@@ -135,7 +146,7 @@ keyboard and mouse-based control of information display 
within multiple
 windows.  It also provides point-and-click access to World-Wide Web URLs,
 Info manuals, ftp archives, etc.
 
-Hyperbole works well on GNU Emacs 27.2 or above.  It is designed and written
+Hyperbole works well on GNU Emacs 28 or above.  It is designed and written
 by Bob Weiner.  It is maintained by him and Mats Lidell.  Its main
 distribution site is: <https://www.gnu.org/software/hyperbole/>.  If any
 term in here is new or unfamiliar to you, you can look it up in the
@@ -228,9 +239,9 @@ not a simple introduction.  It is included in the "man/" 
subdirectory
 of the Hyperbole package directory in four forms:
 
 [hyperbole.info](man/hyperbole.info)   - online Info browser version  
-[hyperbole.html](man/hyperbole.html)   - web HTML version  
+[hyperbole.html](man/hyperbole.html)   - web version  
 [hyperbole.pdf](man/hyperbole.pdf)     - printable version  
-[hyperbole.texi](man/hyperbole.texi)   - source form  
+[hyperbole.texi](man/hyperbole.texi)   - source version  
 
 The Hyperbole package installation places the Info version of this manual
 where needed and adds an entry for Hyperbole into the Info directory under
diff --git a/hargs.el b/hargs.el
index 4e9cb7067a..d22f3da1fc 100644
--- a/hargs.el
+++ b/hargs.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    31-Oct-91 at 23:17:35
-;; Last-Mod:      6-Oct-24 at 22:47:25 by Bob Weiner
+;; Last-Mod:     27-Feb-25 at 21:21:40 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -221,7 +221,7 @@ button key (no spaces)."
        ;; disk drive prefix, in which case the backslash is
        ;; considered part of a pathname.
        (and (if (and (> end (point-min))
-                     (= (char-before end) ?\\)
+                     (= (or (char-before end) 0) ?\\)
                      (not (string-match (concat "\\(\\`[\\][\\]\\)\\|"
                                                 hpath:mswindows-mount-prefix)
                                         (hargs:buffer-substring start end))))
@@ -525,8 +525,14 @@ following sexpression is returned.  Otherwise, the 
innermost sexpression
 that point is within is returned or nil if none."
   (let ((not-quoted
         '(condition-case ()
-             (not (and (eq (char-syntax (char-after (- (point) 2))) ?\\)
-                       (not (eq (char-syntax (char-after (- (point) 3))) 
?\\))))
+             (not (and (= (if (char-after (- (point) 2))
+                              (char-syntax (char-after (- (point) 2)))
+                            0)
+                          ?\\)
+                       (not (= (if (char-after (- (point) 3))
+                                   (char-syntax (char-after (- (point) 3)))
+                                 0)
+                               ?\\))))
            (error t))))
     (save-excursion
       (ignore-errors
diff --git a/hib-kbd.el b/hib-kbd.el
index 53cb6a2d3d..0d446a0f6a 100644
--- a/hib-kbd.el
+++ b/hib-kbd.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    22-Nov-91 at 01:37:57
-;; Last-Mod:     23-Nov-24 at 21:15:04 by Bob Weiner
+;; Last-Mod:     25-Feb-25 at 02:14:39 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -144,7 +144,10 @@ Any key sequence within the series must be a string of one 
of the following:
                  ;; In Texinfo, allow for @bkbd{} or @kbd{}, so an
                  ;; alpha char preceding
                  (and (derived-mode-p 'texinfo-mode)
-                      (= (char-syntax (char-before start)) ?w)))
+                      (= (if (char-before start)
+                             (char-syntax (char-before start))
+                           0)
+                         ?w)))
          (when (and (stringp key-series) (not (string-empty-p key-series)))
            ;; Replace any ${} internal or env vars; leave
            ;; $VAR untouched for the shell to evaluate.
diff --git a/hibtypes.el b/hibtypes.el
index 91ba677533..25b424ddee 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:     29-Jan-25 at 10:07:49 by Mats Lidell
+;; Last-Mod:      2-Mar-25 at 12:05:51 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -1591,10 +1591,19 @@ action type, function symbol to call or test to 
execute, i.e.
     ;;     at the end of the buffer
     ;;     or is followed by a space, punctuation or grouping character.
     (when (and lbl-key (or (null (char-before start-pos))
-                           (memq (char-syntax (char-before start-pos)) '(?\  
?\> ?\( ?\))))
-              (not (memq (char-syntax (char-after (1+ start-pos))) '(?\  ?\>)))
+                           (memq (if (char-before start-pos)
+                                    (char-syntax (char-before start-pos))
+                                  0)
+                                '(?\  ?\> ?\( ?\))))
+              (not (memq (if (char-after (1+ start-pos))
+                             (char-syntax (char-after (1+ start-pos)))
+                           0)
+                         '(?\  ?\>)))
               (or (null (char-after end-pos))
-                   (memq (char-syntax (char-after end-pos)) '(?\  ?\> ?. ?\( 
?\)))
+                   (memq (if (char-after end-pos)
+                            (char-syntax (char-after end-pos))
+                          0)
+                        '(?\  ?\> ?. ?\( ?\)))
                    ;; Some of these characters may have symbol-constituent 
syntax
                    ;; rather than punctuation, so check them individually.
                    (memq (char-after end-pos) '(?. ?, ?\; ?: ?! ?\' ?\"))))
diff --git a/hmouse-drv.el b/hmouse-drv.el
index bacb22e1ce..c2ea344f78 100644
--- a/hmouse-drv.el
+++ b/hmouse-drv.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    04-Feb-90
-;; Last-Mod:     22-Feb-25 at 11:52:57 by Bob Weiner
+;; Last-Mod:     12-Apr-25 at 15:47:32 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -992,6 +992,19 @@ frame instead."
           (mouse-drag-frame-move start-event)
         (mouse-drag-frame start-event 'move))))))
 
+(defun hkey-actions ()
+  "Return the cons of the Action and Assist Key actions at point.
+Useful in testing Smart Key contexts."
+  (let ((hkey-forms hkey-alist)
+       pred-value hkey-actions hkey-form pred)
+    (while (and (null pred-value) (setq hkey-form (car hkey-forms)))
+      (if (setq hkey-actions (cdr hkey-form)
+               pred (car hkey-form)
+               pred-value (hypb:eval-debug pred))
+          nil
+       (setq hkey-forms (cdr hkey-forms))))
+    hkey-actions))
+
 (defun hkey-debug (pred pred-value hkey-action)
   "Display a message with the context and values from Smart Key activation."
   (message (concat "(HyDebug) %sContext: %s; %s: %s; Buf: %s; Mode: %s; 
MinibufDepth: %s\n"
diff --git a/hmouse-tag.el b/hmouse-tag.el
index 7cb755198a..d861eb9b5a 100644
--- a/hmouse-tag.el
+++ b/hmouse-tag.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    24-Aug-91
-;; Last-Mod:     29-Jan-25 at 20:26:54 by Mats Lidell
+;; Last-Mod:     12-Apr-25 at 18:46:48 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -90,7 +90,7 @@ should insert the implicit link type definition name.")
 ;; default, `xref-find-definitions', so is not dependent on TAGS
 ;; tables or the `default-directory' in the ERT results buffer.  When
 ;; a test is loaded, its symbol property, `ert--test', holds the
-;; absolute path to its file, and find-function uses that when its
+;; absolute path to its file, and `find-function' uses that when its
 ;; entry in `find-function-regexp-alist' is a regexp.
 (defconst find-ert-test-regexp "^\\s-*(ert-deftest\\s-+%s\\s-"
   "The regexp used to search for an ert test definition.
diff --git a/hpath.el b/hpath.el
index f35f004b85..89e1bd60a9 100644
--- a/hpath.el
+++ b/hpath.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:     1-Nov-91 at 00:44:23
-;; Last-Mod:      7-Mar-25 at 00:22:47 by Mats Lidell
+;; Last-Mod:     13-Apr-25 at 01:06:44 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -1613,7 +1613,7 @@ but locational suffixes within the file are utilized."
                              (current-buffer)))))))))))
 
 (defun hpath:spaces-to-dashes-markup-anchor (anchor)
-  "Replace dashes with spaces in ANCHOR if not a prog mode and no existing 
dashes."
+  "Replace spaces with dashes in ANCHOR if not a prog mode and no existing 
dashes."
   (if (or (derived-mode-p 'prog-mode)
          (string-match-p "-.* \\| .*-" anchor))
       anchor
@@ -1623,7 +1623,7 @@ but locational suffixes within the file are utilized."
     (subst-char-in-string ?\  ?- anchor)))
 
 (defun hpath:dashes-to-spaces-markup-anchor (anchor)
-  "Replace dashes with spaces in ANCHOR if not a prog mode and no existing 
dashes."
+  "Replace dashes with spaces in ANCHOR if not a prog mode and no existing 
spaces."
   (if (or (derived-mode-p 'prog-mode)
          (string-match-p "-.* \\| .*-" anchor))
       anchor
diff --git a/hproperty.el b/hproperty.el
index ca27419f7a..c7fcc9e364 100644
--- a/hproperty.el
+++ b/hproperty.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    21-Aug-92
-;; Last-Mod:     18-Jan-25 at 20:53:20 by Bob Weiner
+;; Last-Mod:     27-Feb-25 at 22:50:13 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -274,6 +274,13 @@ If optional PROPERTY and VALUE are given, return only the 
first button
 with that PROPERTY and VALUE."
   (car (hproperty:but-get-first-in-region pos (1+ pos) property value)))
 
+(defun hproperty:but-move (hproperty-but start end &optional buffer)
+  "Set the endpoints of HPROPERTY-BUT to START and END in optional BUFFER.
+If BUFFER is nil and HPROPERTY-BUT has no buffer, put it in the current buffer;
+otherwise, if BUFFER is omitted, leave HPROPERTY-BUT in the same
+buffer it presently inhabits."
+  (move-overlay hproperty-but start end buffer))
+
 (defun hproperty:but-start (hproperty-but)
   "Return the end position of an HPROPERTY-BUT.
 See `hproperty:but-get'."
diff --git a/hsys-org.el b/hsys-org.el
index a66d35b3c9..d4a74c6477 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:      5-Jan-25 at 12:06:01 by Bob Weiner
+;; Last-Mod:     13-Apr-25 at 04:30:30 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -497,19 +497,50 @@ Match to all todos if `keyword' is nil or the empty 
string."
       (looking-at org-babel-src-block-regexp))))
 
 (defun hsys-org-link-at-p ()
-  "Return non-nil iff point is on a square-bracketed Org mode link.
+  "Return (start . end) iff point is on an Org mode link, else nil.
+Start and end are the buffer positions of the label that point is on
+delimited by square brackets.
+
 Ignore [[hy:HyWiki]] buttons and return nil (handle these as
 implicit buttons).  Assume caller has already checked that the
 current buffer is in `org-mode' or is looking for an Org link in
-another buffer type."
+a non-Org buffer type."
   (unless (or (smart-eolp) (smart-eobp))
-    (with-suppressed-warnings nil
-      (let ((in-org-link (org-in-regexp org-link-bracket-re nil t)))
-       (when in-org-link
-         (save-match-data
-           ;; If this Org link matches a potential HyWiki word, ignore it.
-           (unless (and (fboundp 'hywiki-word-at) (hywiki-word-at))
-             in-org-link)))))))
+    (if (derived-mode-p 'org-mode)
+       (let* ((org-plist (hsys-org-thing-at-p))
+              (type (plist-get org-plist :type))
+              (path (plist-get org-plist :path))
+              label-start-end)
+         (when (eq type 'link)
+           (save-match-data
+             ;; If this Org link matches a potential HyWiki word, ignore it.
+             (when (not (and (fboundp 'hywiki-word-at) (hywiki-word-at)))
+               (if (setq label-start-end (ibut:label-p t "[" "]" t))
+                   (cons (nth 1 label-start-end) (nth 2 label-start-end))
+                 t)))))
+      ;; non-Org mode (can't call org-element (which
+      ;; hsys-org-thing-at-p calls) outside of Org mode
+      (when (bound-and-true-p org-link-bracket-re)
+        (let ((pos (point)))
+          (when (save-excursion
+                 (or
+                  ;; Check if point is inside a link
+                  (and (re-search-backward org-link-bracket-re
+                                           (line-beginning-position) t)
+                       (> pos (point))
+                       (< pos (match-end 0)))
+                  ;; If not found before, check if we're in the middle of a 
link
+                  (and (forward-line 0)
+                       (re-search-forward org-link-bracket-re
+                                          (line-end-position 2) t)
+                       (> (point) pos)
+                       (< pos (match-end 0)))))
+           (save-match-data
+             ;; If this Org link matches a potential HyWiki word, ignore it.
+             (when (not (and (fboundp 'hywiki-word-at) (hywiki-word-at)))
+               (if (setq label-start-end (ibut:label-p t "[" "]" t))
+                   (cons (nth 1 label-start-end) (nth 2 label-start-end))
+                 t)))))))))
 
 ;; Assume caller has already checked that the current buffer is in org-mode.
 (defun hsys-org-heading-at-p (&optional _)
@@ -525,6 +556,43 @@ Assume caller has already checked that the current buffer 
is in
 `org-mode'."
   (hsys-org-face-at-p 'org-target))
 
+;; Derived from `org-open-at-point' in "org.el".
+(defun hsys-org-thing-at-p ()
+  "Return a plist of properties for Org thing at point or nil if none.
+This must work on Org links outside of Org mode.
+
+The plist form is: (:type <type> :value <value> :context <context>).
+The thing can be a link, citation, timestamp, footnote, src-block or
+tags.
+
+On top of syntactically correct links, this function also works
+on links and timestamps in comments, node properties, and
+keywords if point is on something looking like a timestamp or a
+link."
+  (ignore-errors
+    (org-load-modules-maybe)
+    ;; Org regex matching can fail in non-thing contexts, so we ignore
+    ;; these errors and return nil then.  Org-element will also warn to
+    ;; not use it outside of Org mode although it works, so we suppress
+    ;; those warnings as well.
+    (let* ((warning-minimum-level :error)
+          (warning-suppress-types '(org-element rx))
+          (warning-suppress-log-types '(org-element rx))
+          (context
+           ;; Only consider supported types, even if they are not the
+           ;; closest one.
+           (org-element-lineage
+            (org-element-context)
+            '(citation citation-reference clock comment comment-block
+                       footnote-definition footnote-reference headline
+                       inline-src-block inlinetask keyword link node-property
+                       planning src-block timestamp)
+            t))
+          (type (org-element-type context))
+          (value (org-element-property :value context)))
+      (when type
+       (list :type type :value value :context context)))))
+
 (defun hsys-org-todo-at-p ()
   "Return non-nil iff point is on an Org mode todo keyword.
 Assume caller has already checked that the current buffer is in `org-mode'."
diff --git a/hsys-xref.el b/hsys-xref.el
index d633699af1..798f598119 100644
--- a/hsys-xref.el
+++ b/hsys-xref.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    24-Aug-91
-;; Last-Mod:     14-Apr-24 at 19:03:32 by Bob Weiner
+;; Last-Mod:      2-Mar-25 at 18:11:45 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -49,7 +49,9 @@
   (car (hsys-xref-definitions identifier)))
 
 (defun hsys-xref-identifier-at-point ()
-  (xref-backend-identifier-at-point (xref-find-backend)))
+  ;; Return nil if xref returns a pathname as an identifier
+  (unless (hpath:at-p nil t)
+    (xref-backend-identifier-at-point (xref-find-backend))))
 
 (defun hsys-xref-item-buffer (item)
   "Return the buffer in which xref ITEM is defined."
diff --git a/hui-mouse.el b/hui-mouse.el
index 8f5b775234..30af357e44 100644
--- a/hui-mouse.el
+++ b/hui-mouse.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    04-Feb-89
-;; Last-Mod:     22-Feb-25 at 16:18:02 by Bob Weiner
+;; Last-Mod:     12-Apr-25 at 14:29:25 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -253,20 +253,19 @@ Its default value is `smart-scroll-down'.  To disable it, 
set it to
      . ((smart-push-button nil (mouse-event-p last-command-event))
        . (smart-push-button-help nil (mouse-event-p last-command-event))))
     ;;
-    ;; If in the minibuffer and reading an argument with vertico
-    ;; run the vertico command on {M-RET} which accepts the first
-    ;; line of minibuffer input, rather than any candidate.
-    ((and hargs:reading-type
-         (> (minibuffer-depth) 0)
-         (eq (selected-window) (minibuffer-window))
-         (not (bound-and-true-p ivy-mode))
-         (and (bound-and-true-p vertico-mode)
-              ;; Is vertico prompting for an argument?
-              (vertico--command-p nil (current-buffer))))
-     . ((vertico-exit-input) . (vertico-exit-input)))
-    ;;
-    ;; If in the minibuffer and reading an argument (aside from
-    ;; with vertico or ivy), accept argument or give completion help.
+    ;; If in a window reading an argument with vertico, run the
+    ;; vertico command on {M-RET} which by default accepts the
+    ;; existing input at the prompt rather than the candidate pointed
+    ;; to.
+    ((and (bound-and-true-p vertico-mode)
+         ;; Is vertico prompting for an argument?
+         (vertico--command-p nil (current-buffer)))
+     . ((funcall (lookup-key vertico-map (kbd "M-RET"))) 
+       . (funcall (lookup-key vertico-map (kbd "M-RET")))))
+    ;;
+    ;; If in the minibuffer and reading a non-menu Hyperbole argument
+    ;; (aside from with vertico or ivy), accept the argument or give
+    ;; completion help.
     ((and hargs:reading-type
          (> (minibuffer-depth) 0)
          (eq (selected-window) (minibuffer-window))
diff --git a/hui-select.el b/hui-select.el
index 4429e69c15..44e734f071 100644
--- a/hui-select.el
+++ b/hui-select.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    19-Oct-96 at 02:25:27
-;; Last-Mod:      7-Mar-25 at 00:39:21 by Mats Lidell
+;; Last-Mod:     27-Feb-25 at 21:24:19 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -327,7 +327,6 @@ Used to include a final line when marking indented code.")
 ;;; Public declarations
 ;;; ************************************************************************
 
-(defvar hbut:syntax-table)              ; "hbut.el"
 (defvar help-mode-syntax-table)         ; "help-mode.el"
 (defvar hkey-init)                      ; "hyperbole.el"
 (defvar hkey-value)                     ; "hui-mouse.el"
@@ -431,13 +430,13 @@ returned is the function to call to select that syntactic 
unit."
   (unless (smart-eobp)
     (or (numberp pos) (setq pos (point)))
     (setq hui-select-previous 'char)
-    (let* ((syntax (char-syntax (or (char-after pos) (char-before pos))))
+    (let* ((syntax (char-syntax (or (char-after pos) (char-before pos) 0)))
           (pair (assq syntax hui-select-syntax-alist)))
       (and pair (or hui-select-whitespace (not (eq (cdr pair) 
'thing-whitespace)))
           ;; Ignore matches that are preceded by '\' as a quote, e.g. ?\'
           (or (not (char-after pos))
               (= pos (point-min))
-              (and (char-before pos) (/= ?\\ (char-before pos))))
+              (and (char-before pos) (/= ?\\ (or (char-before pos) 0))))
           (cdr pair)))))
 
 ;;;###autoload
@@ -850,7 +849,7 @@ If an error occurs during syntax scanning, return nil."
   (setq hui-select-previous 'char)
   (if (save-excursion (goto-char pos) (eolp))
       (hui-select-line pos)
-    (let* ((syntax (char-syntax (or (char-after pos) (char-before pos))))
+    (let* ((syntax (char-syntax (or (char-after pos) (char-before pos) 0)))
           (pair (assq syntax hui-select-syntax-alist)))
       (cond ((and pair
                  (or hui-select-whitespace
@@ -904,7 +903,7 @@ Use `hui-select-mark-delimited-sexp' to select it."
          (syn-after  (if (char-after)  (char-syntax (char-after)) 0)))
       (or (and (/= syn-before ?\\) (or (= syn-after ?\() (= syn-after ?\))))
          (and (= syn-before ?\)) (char-before (1- (point)))
-              (/= ?\\ (char-syntax (char-before (1- (point))))))))))
+              (/= ?\\ (if (char-before (1- (point))) (char-syntax (char-before 
(1- (point)))) 0)))))))
 
 (defun hui-select-mark-delimited-sexp ()
   "When point is before or after an sexp deactivate the mark and mark the sexp.
@@ -916,7 +915,7 @@ end sexp delimiters, ignore it, and return nil."
                          (when (region-active-p) (deactivate-mark))
                          (mark-sexp) t)))
     (ignore-errors
-      (let ((syn-after (char-syntax (char-after)))
+      (let ((syn-after (if (char-after) (char-syntax (char-after)) 0))
            syn-before)
        (cond ((eq syn-after ?\()
               (funcall mark-sexp-func))
@@ -925,7 +924,7 @@ end sexp delimiters, ignore it, and return nil."
               (backward-sexp)
               (funcall mark-sexp-func))
              ((and (not (eolp))
-                   (setq syn-before (char-syntax (char-before)))
+                   (setq syn-before (if (char-before) (char-syntax 
(char-before)) 0))
                    (eq syn-before ?\)))
               (backward-sexp)
               (funcall mark-sexp-func)))))))
@@ -1051,14 +1050,14 @@ string."
   (with-syntax-table hbut:syntax-table
     (or (and (equal start-delim "\"") (equal end-delim "\"")
             (ignore-errors
-              (cond ((and (= (char-after) ?\")
-                          (/= (char-before) ?\\))
+              (cond ((and (= (or (char-after) 0) ?\")
+                          (/= (or (char-before) 0) ?\\))
                      (if (hypb:in-string-p)
                          (hui-select-set-region (1+ (point))
                                                 (scan-sexps (1+ (point)) -1))
                        (hui-select-set-region (point) (scan-sexps (point) 1))))
-                    ((and (= (char-before) ?\")
-                          (/= (char-before (1- (point))) ?\\))
+                    ((and (= (or (char-before) 0) ?\")
+                          (/= (or (char-before (1- (point))) 0) ?\\))
                      (if (hypb:in-string-p)
                          (hui-select-set-region (1- (point)) (scan-sexps (1- 
(point)) 1))
                        (hui-select-set-region (point) (scan-sexps (point) 
-1)))))))
@@ -1339,8 +1338,8 @@ included in the list, hui-select-brace-modes."
 The region includes sexpressions before and after POS"
   (or (hui-select-markup-pair pos)
       (hui-select-delimited-thing-call #'hui-select-thing)
-      (and (or (and (= (char-after) ?\") (/= (char-before) ?\\))
-              (and (= (char-before) ?\") (/= (char-before (1- (point))) ?\\)))
+      (and (or (and (= (or (char-after) 0) ?\") (/= (or (char-before) 0) ?\\))
+              (and (= (or (char-before) 0) ?\") (/= (or (char-before (1- 
(point))) 0) ?\\)))
           (hui-select-string pos))
       (hui-select-comment pos)
       (hui-select-preprocessor-def pos)
@@ -1348,9 +1347,9 @@ The region includes sexpressions before and after POS"
       (save-excursion
        (setq hui-select-previous 'punctuation)
        (goto-char (min (1+ pos) (point-max)))
-       (cond ((and (char-after pos) (= ?\  (char-syntax (char-after pos))))
+       (cond ((and (char-after pos) (= ?\  (if (char-after pos) (char-syntax 
(char-after pos)) 0)))
               (hui-select-set-region pos (1+ pos)))
-             ((and (char-before pos) (= ?\  (char-syntax (char-before pos))))
+             ((and (char-before pos) (= ?\  (if (char-before pos) (char-syntax 
(char-before pos)) 0)))
               (hui-select-set-region (1- pos) pos))
              (t (goto-char pos)
                 (ignore-errors (hui-select-set-region
diff --git a/hypb.el b/hypb.el
index 90fd98bbc6..1ca259e9d6 100644
--- a/hypb.el
+++ b/hypb.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:     6-Oct-91 at 03:42:38
-;; Last-Mod:     29-Jan-25 at 20:27:07 by Mats Lidell
+;; Last-Mod:     12-Apr-25 at 16:58:59 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -664,9 +664,17 @@ This will this install the Emacs helm package when needed."
                      help-file))))))
 
 (defun hypb:in-string-p ()
-  "Return non-nil iff point is in a double quoted string."
-  (syntax-ppss-flush-cache (line-beginning-position))
-  (nth 3 (syntax-ppss)))
+  "Return non-nil iff point is in the first line of a double quoted string."
+  (if (derived-mode-p 'change-log-mode)
+      ;; limited to single line strings; count must be odd to be
+      ;; inside a string
+      (when (cl-oddp (count-matches "\"" (line-beginning-position) (point)))
+       (save-excursion (search-backward "\"" (line-beginning-position) t)))
+    (syntax-ppss-flush-cache (line-beginning-position))
+    (let ((sexp-state-list (syntax-ppss)))
+      (when (eq ?\" (nth 3 sexp-state-list))   ; in a double quoted string
+       ;; return start of str position (opening quote)
+       (nth 8 sexp-state-list)))))
 
 (defun hypb:indirect-function (obj)
   "Return the function at the end of OBJ's function chain.
diff --git a/hyperbole.el b/hyperbole.el
index 6db1ed9c7e..30c4871bc1 100644
--- a/hyperbole.el
+++ b/hyperbole.el
@@ -9,12 +9,12 @@
 ;; Maintainer:   Robert Weiner <r...@gnu.org>
 ;; Maintainers:  Robert Weiner <r...@gnu.org>, Mats Lidell <ma...@gnu.org>
 ;; Created:      06-Oct-92 at 11:52:51
-;; Last-Mod:      2-Feb-25 at 07:27:43 by Bob Weiner
+;; Last-Mod:     16-Mar-25 at 10:11:31 by Bob Weiner
 ;; Released:     10-Mar-24
 ;; Version:      9.0.2pre
 ;; Keywords:     comm, convenience, files, frames, hypermedia, languages, 
mail, matching, mouse, multimedia, outlines, tools, wp
 ;; Package:      hyperbole
-;; Package-Requires: ((emacs "27.2"))
+;; Package-Requires: ((emacs "28"))
 ;; URL:          http://www.gnu.org/software/hyperbole
 
 ;; See the "HY-COPY" file for license information.
diff --git a/hywiki.el b/hywiki.el
index 76bb894123..3c9ed8dc4d 100644
--- a/hywiki.el
+++ b/hywiki.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    21-Acpr-24 at 22:41:13
-;; Last-Mod:      7-Mar-25 at 01:00:19 by Mats Lidell
+;; Last-Mod:     13-Apr-25 at 02:03:01 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -136,7 +136,6 @@
 ;;; Other required Elisp libraries
 ;;; ************************************************************************
 
-(require 'cl-lib)     ;; For `cl-find' and `cl-incf'
 (require 'hactypes)   ;; For `link-to-file-interactively'
 (require 'hargs)
 (require 'hasht)
@@ -148,6 +147,7 @@
 (require 'hui-mini)   ;; For `hui:menu-act'
 (require 'hypb)       ;; Requires `seq'
 (require 'outline)    ;; For `outline-mode-syntax-table'
+(require 'seq)        ;; For 'seq-contains-p' and 'seq-difference'
 (require 'subr-x)     ;; For `string-remove-prefix'
 (require 'thingatpt)
 
@@ -234,8 +234,10 @@ Each element is of the form: (wikiword . (referent-type . 
referent-value)).")
 (defvar hywiki--buttonize-start (make-marker)) ;; This must always stay a 
marker
 (defvar hywiki--current-page nil)
 (defvar hywiki--end nil)
+(defvar hywiki--flag nil)
 (defvar hywiki--highlighting-done-flag t)
-(defvar hywiki--page-name nil)
+(defvar hywiki--word-pre-command nil)
+(defvar hywiki--word-only nil)
 (defvar hywiki--range nil)
 (defvar hywiki--save-case-fold-search nil)
 (defvar hywiki--save-org-link-type-required nil)
@@ -311,7 +313,7 @@ See `hywiki-org-publishing-directory' for exported pages in 
html format."
 
 (defun hywiki-directory-changed (option set-to-value operation _where)
   "Watch function for variable `hywiki-directory'.
-Function is called with 4 arguments: (SYMBOL SET-TO-VALUE OPERATION WHERE)."
+Function is called with 4 arguments: (OPTION SET-TO-VALUE OPERATION WHERE)."
   (if (memq operation '(let unlet)) ;; not setting global value
       (hywiki-let-directory option set-to-value)
     (hywiki-set-directory option set-to-value)))
@@ -355,7 +357,7 @@ Presently, there are no key bindings; this is for future 
use.")
   "HyWiki string prefix type for Org links.  Excludes trailing colon.")
 
 (defvar hywiki-org-link-type-required t
-  "When non-nil, HyWiki Org links must start with `hywiki-org-link-type'.
+  "When t, [[hy:HyWiki Org links]] must start with `hywiki-org-link-type':.
 Otherwise, this prefix is not needed and HyWiki word Org links
 override standard Org link lookups.  See \"(org)Internal Links\".")
 
@@ -437,6 +439,7 @@ where PATH is the un-resolvable reference."
         :publishing-directory hywiki-org-publishing-directory
         :publishing-function hywiki-org-publishing-function
         :section-numbers t
+        :shell "shell-command"
         :sitemap-filename "index.org"
         ;; sitemap (TOC) is stored in "sitemap.html"
         :sitemap-title hywiki-org-publishing-sitemap-title
@@ -464,7 +467,7 @@ Do not use a start or end line/string anchor in this 
regexp.")
 
 (defconst hywiki-word-section-regexp
   "\\(#[^][# \t\n\r\f]+\\)"
-  "Regexp that matches a HyWiki word #section extension.
+  "Regexp that matches a non-delimited HyWiki word #section extension.
 After the first # character, this may contain any non-square-bracket,
 non-# and non-whitespace characters.")
 
@@ -487,19 +490,6 @@ file-based referents (relative to any section given).
 Group 6 is any optional 0-based column number to jump to for any
 file-based referents.")
 
-(defconst hywiki-word-with-optional-spaces-suffix-exact-regexp
-  (concat "\\`" hywiki-word-with-optional-suffix-regexp "\\'")
-  "Exact regexp for a HyWiki word with optional #section, :Lline-num, 
:Ccol-num.
-Section may not contain whitespace or square brackets.  Use '-' to
-substitute for spaces in the section/headline name.
-
-Group 1 is the HyWiki word.
-Group 2 is any optional #section with the # included.
-Group 4 is any optional 1-based line number to jump to for any
-file-based referents (relative to any section given).
-Group 6 is any optional 0-based column number to jump to for any
-file-based referents.")
-
 (defconst hywiki-word-with-optional-suffix-exact-regexp
   (concat "\\`" hywiki-word-regexp "\\(#[^][\n\r\f]+\\)??"
          hywiki-word-line-and-column-numbers-regexp "?\\'")
@@ -552,84 +542,122 @@ Non-nil is the default."
   :group 'hyperbole-hywiki)
 
 ;;; ************************************************************************
-;;; hywiki minor mode
+;;; hywiki minor mode and text edit command hooks
 ;;; ************************************************************************
 
-(defun hywiki-buttonize-character-commands ()
-  "Turn any HyWikiWords between point into highlighted Hyperbole buttons.
-Triggered by `post-self-insert-hook' for self-inserting characters.
-Highlight after inserting any non-word character."
-  (unless (or (minibuffer-window-active-p (selected-window))
-             (and (boundp 'edebug-active) edebug-active
-                  (active-minibuffer-window)))
-    (hywiki-maybe-highlight-between-page-names)))
+(defun hywiki-debuttonize-non-character-commands ()
+  "Store any HyWikiWord before or after point for later comparison.
+Triggered by `pre-command-hook' for non-character -commands, including
+deletion commands and those in `hywiki-non-character-commands'."
+  (setq hywiki--word-pre-command nil)
+  (set-marker hywiki--buttonize-start nil)
+  (set-marker hywiki--buttonize-end nil)
+
+  (unless (hywiki-non-hook-context-p)
+    ;; Record the WikiWord from any WikiWord ref that point is on
+    (setq hywiki--word-pre-command (hywiki-get-singular-wikiword 
(hywiki-word-at)))
+    (when (or (memq this-command hywiki-non-character-commands)
+             (and (symbolp this-command)
+                  (string-match-p 
"^\\(org-\\)?\\(delete-\\|kill-\\)\\|\\(-delete\\|-kill\\)\\(-\\|$\\)" 
(symbol-name this-command))))
+      ;; Test if at delimiters surrounding a WikiWord and if so,
+      ;; record those for use by post hooks.
+      (cl-destructuring-bind (start end)
+         ;; Get delimited region only if before or after delimiters,
+         ;; else return (nil nil).
+         (hywiki-at-range-delimiter) ;; includes delimiters
+       ;; Use these to store any range of a delimited HyWikiWord#section
+       (set-marker hywiki--buttonize-start start)
+       (set-marker hywiki--buttonize-end end)
+       start)))
+  (setq hywiki--flag nil))
 
 (defun hywiki-buttonize-non-character-commands ()
   "Highlight any HyWikiWord before or after point as a Hyperbole button.
 Triggered by `post-command-hook' for non-character-commands, including
 deletion commands and those in `hywiki-non-character-commands'."
-  (unless (or (minibuffer-window-active-p (selected-window))
-             (and (boundp 'edebug-active) edebug-active
-                  (active-minibuffer-window))
-             (and (derived-mode-p 'prog-mode)
-                  (not (apply #'derived-mode-p 
hywiki-highlight-all-in-prog-modes))
-                ;; Not inside a comment or a string
-                  (not (or (nth 4 (syntax-ppss)) (hypb:in-string-p)))))
+  (unless (or hywiki--flag (hywiki-non-hook-context-p))
     (when (or (memq this-command hywiki-non-character-commands)
              (and (symbolp this-command)
-                  (string-match-p 
"^\\(org-\\)?\\(delete-\\|kill-\\)\\|\\(-delete\\|-kill\\|insert\\)\\(-\\|$\\)" 
(symbol-name this-command))))
-      (when (and (marker-position hywiki--buttonize-start)
-                (marker-position hywiki--buttonize-end))
-       ;; This means the command just deleted an opening or closing
-       ;; delimiter of a range that now needs any HyWikiWords
-       ;; inside to be re-highlighted.
-       (save-excursion
-         (goto-char hywiki--buttonize-start)
-         (let ((opening-char (char-after))
-               closing-char)
-           (when (memq opening-char '(?\( ?\"))
-             (delete-char 1))
-           (goto-char hywiki--buttonize-end)
-           (setq closing-char (char-before))
-           (when (memq closing-char '(?\) ?\"))
-             (delete-char -1)
-             (insert " "))
-           (goto-char hywiki--buttonize-start)
-           (hywiki-maybe-highlight-between-page-names)
-           (when (memq opening-char '(?\( ?\"))
-             (insert opening-char))
-           (when (memq closing-char '(?\) ?\"))
-             (goto-char (1+ hywiki--buttonize-end))
-             (delete-char -1)
-             (insert closing-char)
-             ))))
-      (hywiki-maybe-highlight-between-page-names))))
+                  (string-match-p 
"^\\(org-\\)?\\(delete-\\|kill-\\)\\|\\(-delete\\|-kill\\)\\(-\\|$\\)" 
(symbol-name this-command))))
+      (setq hywiki--range nil)
 
-(defun hywiki-debuttonize-non-character-commands ()
-  "Dehighlight any HyWikiWord before or after point.
-Triggered by `pre-command-hook' for non-character-commands, including
-deletion commands and those in `hywiki-non-character-commands'."
-  (when (and (markerp hywiki--buttonize-start) (markerp hywiki--buttonize-end))
-    (set-marker hywiki--buttonize-start nil)
-    (set-marker hywiki--buttonize-end nil))
-  (when (and (or (memq this-command hywiki-non-character-commands)
-                (and (symbolp this-command)
-                     (string-match-p 
"\\`\\(org-\\)?\\(delete-\\|kill-\\)\\|-delete-\\|-kill-"
-                                     (symbol-name this-command))))
-            (or (not (derived-mode-p 'prog-mode))
-                (apply #'derived-mode-p hywiki-highlight-all-in-prog-modes)
-                ;; Inside a comment or a string
-                (nth 4 (syntax-ppss))
-                (hypb:in-string-p)))
-    (cl-destructuring-bind (start end)
-       (hywiki-get-delimited-range) ;; includes delimiters
-      ;; Use these to store any range of a delimited HyWikiWord#section
-      (set-marker hywiki--buttonize-start start)
-      (set-marker hywiki--buttonize-end end)
-      ;; Enable dehighlighting in HyWiki pages
-      (unless (and start end)
-       ;; Dehighlight any page name at point
-       (hywiki-maybe-dehighlight-between-page-names)))))
+      ;; Dehighlight any previously highlighted WikiWord at point
+      ;; before we move to the start of any current WikiWord and
+      ;; rehighlight that.
+      (hywiki--maybe-dehighlight-at-point)
+
+      (save-excursion
+       (cond ((marker-position hywiki--buttonize-start)
+              ;; Point was before or after a WikiWord delimiter
+              (goto-char (1+ hywiki--buttonize-start)))
+             ((setq hywiki--range (hywiki-word-at :range))
+              (cl-destructuring-bind (_ start end)
+                  hywiki--range
+                (if (and start end)
+                    (progn
+                      ;; On a non-delimited HyWikiWord
+                      (set-marker hywiki--buttonize-start start)
+                      (set-marker hywiki--buttonize-end end)
+                      (goto-char start)
+                      (skip-chars-backward "-" (line-beginning-position))
+                      t)
+                  (setq hywiki--range nil)))))
+
+       (hywiki--maybe-rehighlight-at-point)))))
+
+(defun hywiki-buttonize-character-commands ()
+  "Turn any HyWikiWords between point into highlighted Hyperbole buttons.
+Triggered by `post-self-insert-hook' after self-inserting one or more
+characters after `post-command-hook' has run."
+  ;; If `hywiki--flag' is set non-nil below, then
+  ;; `hywiki-buttonize-non-character-commands' on `post-command-hook'
+  ;; does nothing.
+  (unless (setq hywiki--flag (hywiki-non-hook-context-p))
+    (setq hywiki--range nil)
+
+    ;; Dehighlight any previously highlighted WikiWord at point
+    ;; before we move to the start of any current WikiWord and
+    ;; rehighlight that.
+    (hywiki--maybe-dehighlight-at-point)
+
+    (save-excursion
+      (cond ((marker-position hywiki--buttonize-start)
+            ;; Point was before or after a WikiWord delimiter
+            (goto-char hywiki--buttonize-start)
+            (skip-chars-backward "-" (line-beginning-position))
+            (goto-char (1- (point))))
+           ((not (equal (setq hywiki--range (hywiki-word-at :range))
+                        '(nil nil nil)))
+            (cl-destructuring-bind (_ start end)
+                hywiki--range
+              (if (and start end)
+                  (progn
+                    ;; On a non-delimited HyWikiWord
+                    (set-marker hywiki--buttonize-start start)
+                    (set-marker hywiki--buttonize-end end)
+                    (goto-char start)
+                    (skip-chars-backward "-" (line-beginning-position))
+                    t)
+                (setq hywiki--range nil))))
+           ((not (equal (setq hywiki--range (hywiki-at-range-delimiter)) ;; 
includes delimiters
+                        '(nil nil)))
+            ;; At delimiters surrounding a WikiWord
+            (let ((start (nth 0 hywiki--range))
+                  (end   (nth 1 hywiki--range)))
+              (when (and start end)
+                ;; Use these to store any range of a delimited 
HyWikiWord#section
+                (set-marker hywiki--buttonize-start (1+ start))
+                (set-marker hywiki--buttonize-end (1- end))))))
+
+      ;; This first rehighlighting is needed to ensure
+      ;; any wikiword before an inserted whitespace character is
+      ;; properly highlighted when separating two words or after a
+      ;; closing delimiter.
+      (save-excursion
+       (goto-char (max (1- (point)) (point-min)))
+       (hywiki--maybe-rehighlight-at-point))
+
+      (hywiki--maybe-rehighlight-at-point))))
 
 (defun hywiki-buttonize-word (func start end face)
   "Create a HyWikiWord button by calling FUNC with START and END positions.
@@ -656,7 +684,7 @@ the button."
            cmd (cdr key-cmd))
       (when (eq cmd 'self-insert-command)
        (cond ((and (characterp key)
-                   (= (char-syntax key) ?.))
+                   (eq (char-syntax key) ?.))
               ;; char with punctuation/symbol syntax
               (setq result (cons key result)))
              ((and (consp key)
@@ -669,6 +697,15 @@ the button."
                   (when (memq (char-syntax k) '(?. ?_))
                     (setq result (cons k result)))))))))))
 
+(defun hywiki-non-hook-context-p ()
+  (or (minibuffer-window-active-p (selected-window))
+      (and (boundp 'edebug-active) edebug-active
+          (active-minibuffer-window))
+      (and (derived-mode-p 'prog-mode)
+          (not (apply #'derived-mode-p hywiki-highlight-all-in-prog-modes))
+          ;; Not inside a comment or a string
+          (not (or (nth 4 (syntax-ppss)) (hypb:in-string-p))))))
+
 ;;;###autoload
 (define-minor-mode hywiki-mode
   "Toggle HyWiki global minor mode with \\[hywiki-mode].
@@ -1430,15 +1467,8 @@ Use when publishing a HyWiki file to another format, 
e.g. html.
 
 For example, the link:
   \"WikiWord#Multi-Word Section\"
-or
-  \"[[hy:WikiWord#Multi-Word Section]]\"
 is converted to:
-  \"[[file:<hywiki-directory>/WikiWord.org::Multi-Word Section]
-    [WikiWord#Multi-Word Section]]\".
-
-If the reference is in a file within the `hywiki-directory', it
-simplifies to:
-  \"[[file:WikiWord.org::Multi-Word Section][WikiWord#Multi-Word Section]]\".
+  \"[[hy:WikiWord#Multi-Word Section]]\".
 
 If the reference is within the WikiWord page to which it refers, it
 simplifies to:
@@ -1447,7 +1477,9 @@ simplifies to:
 The finalized Org link is then exported to html format by the Org
 publish process."
   (barf-if-buffer-read-only)
-  (hywiki-maybe-highlight-page-names)
+  ;; Need to be explicit about the region here so does not use markers
+  ;; from a region pointing to another buffer
+  (hywiki-maybe-highlight-page-names (point-min) (point-max))
   (let ((make-index (hywiki-org-get-publish-property :makeindex))
        org-link
        wikiword-and-section
@@ -1516,7 +1548,9 @@ Do not test whether or not a page exists for the HyWiki 
word.
 Use `hywiki-get-referent' to determine whether a HyWiki page exists."
   ;; Ignore wikiwords preceded by any non-whitespace character, except
   ;; any of these: [({<"'`'
-  (when (or (bolp) (cl-find (char-before) "\[\(\{\<\"'`\t\n\r\f "))
+  (when (or (bolp)
+           (string-match (regexp-quote (char-to-string (char-before)))
+                         "\[\(\{\<\"'`\t\n\r\f "))
     t))
 
 (defun hywiki-directory-edit ()
@@ -1640,8 +1674,8 @@ positions of each HyWikiWord and its optional #section."
            (overlays-in (point-min) (point-max)))))
   nil)
 
-(defun hywiki-get-delimited-range ()
-  "Before or after a balanced delimiter, return the delimited range list.
+(defun hywiki-at-range-delimiter ()
+  "Immediately before or after a balanced delimiter, return the delimited 
range.
 If no such range, return \\='(nil nil).
 This includes the delimiters: (), {}, <>, [] and \"\" (double quotes)."
   (save-excursion
@@ -1687,7 +1721,7 @@ This includes the delimiters: (), {}, <>, [] and \"\" 
(double quotes)."
                               (not (hypb:in-string-p)))
                          (list (point) (scan-sexps (point) 1))))
                      (error nil))))
-       (if result
+       (if (and result (integerp (nth 0 result)) (integerp (nth 1 result)))
            (sort result #'<)
          (list nil nil))))))
 
@@ -1706,8 +1740,7 @@ and radio targets.
 Ignore return value; it has no meaning."
   (save-excursion
     (save-restriction
-      (if (and (marker-position hywiki--buttonize-start)
-              (marker-position hywiki--buttonize-end))
+      (if (hywiki--buttonized-region-p)
          (narrow-to-region hywiki--buttonize-start hywiki--buttonize-end)
        ;; Limit balanced pair checks to the next two lines for speed
        (narrow-to-region (line-beginning-position) (line-end-position 2)))
@@ -1773,8 +1806,7 @@ and radio targets.
 Return t if no errors and a pair was found, else nil."
   (save-excursion
     (save-restriction
-      (if (and (marker-position hywiki--buttonize-start)
-              (marker-position hywiki--buttonize-end))
+      (if (hywiki--buttonized-region-p)
          (narrow-to-region hywiki--buttonize-start hywiki--buttonize-end)
        ;; Limit balanced pair checks to the next two lines for speed
        (narrow-to-region (line-beginning-position) (line-end-position 2)))
@@ -1847,11 +1879,28 @@ Return t if no errors and a pair was found, else nil."
        (when result t)))))
 
 (defun hywiki-maybe-dehighlight-between-page-names ()
-  "Dehighlight any non-Org link HyWiki page#section names between point.
-If in a programming mode, must be within a comment.  Use
+  "Dehighlight any non-Org link HyWiki page#section between point.
+If in a programming mode, must be within a comment or string.  Use
 `hywiki-word-face' to dehighlight."
-  (hywiki-maybe-dehighlight-off-page-name)
-  (hywiki-maybe-dehighlight-on-page-name))
+  (when (hproperty:char-property-range (point) 'face hywiki-word-face)
+    (hproperty:but-clear-all-in-list
+     (hproperty:but-get-all-in-region (point) (1+ (point))
+                                     'face hywiki-word-face)))
+
+  (cond ((cl-destructuring-bind (start end)
+            (hywiki-at-range-delimiter)
+          (when (and start end)
+            (save-excursion
+              (goto-char (1+ start))
+              (and (hproperty:char-property-range (point) 'face 
hywiki-word-face)
+                   (equal (hywiki-referent-exists-p :range)
+                          '(nil nil nil))
+                   ;; non-existing wikiword
+                   (hywiki-maybe-dehighlight-on-page-name)))
+            t)))
+       ((looking-at "[ \t\n\r\f]")
+        (hywiki-maybe-dehighlight-off-page-name)
+        (hywiki-maybe-dehighlight-on-page-name))))
 
 (defun hywiki-maybe-dehighlight-off-page-name ()
   "Dehighlight any non-Org link HyWiki page#section at or one char before 
point.
@@ -1862,7 +1911,7 @@ in a programming mode, must be within a comment."
   (hywiki-maybe-dehighlight-page-name
    ;; Flag on-page-name if on a whitespace character
    (or (= (point) (point-max))
-       (= (char-syntax (char-after)) ? ))))
+       (= (if (char-after) (char-syntax (char-after)) 0) ? ))))
 
 (defun hywiki-maybe-dehighlight-on-page-name ()
   "Dehighlight any non-Org link HyWiki page#section at or one char before 
point.
@@ -1873,7 +1922,7 @@ be within a comment."
   (hywiki-maybe-dehighlight-page-name
    ;; Flag on-page-name if not on a whitespace character
    (and (/= (point) (point-max))
-       (/= (char-syntax (char-after)) ? ))))
+       (/= (if (char-after) (char-syntax (char-after)) 0) ? ))))
 
 ;;;###autoload
 (defun hywiki-maybe-dehighlight-page-name (&optional on-page-name)
@@ -1886,6 +1935,8 @@ use these as the region in which to dehighlight.
 If in a programming mode, must be within a comment.  Use
 `hywiki-word-face' to dehighlight."
   (interactive)
+  (setq hywiki--start nil
+       hywiki--end   nil)
   (when (and (hywiki-active-in-current-buffer-p)
             (if (and (derived-mode-p 'prog-mode)
                      (not (apply #'derived-mode-p 
hywiki-highlight-all-in-prog-modes)))
@@ -1893,7 +1944,8 @@ If in a programming mode, must be within a comment.  Use
                 (or (nth 4 (syntax-ppss)) (hypb:in-string-p))
               t)
             (or on-page-name
-                (cl-find (char-syntax last-command-event)
+                (string-match (regexp-quote
+                               (char-to-string (char-syntax 
last-command-event)))
                          " _()<>$.\"'"))
              (not executing-kbd-macro)
              (not noninteractive))
@@ -1901,8 +1953,7 @@ If in a programming mode, must be within a comment.  Use
     (with-syntax-table hbut:syntax-table
       (save-excursion
        (save-restriction
-         (when (and (marker-position hywiki--buttonize-start)
-                    (marker-position hywiki--buttonize-end))
+         (when (hywiki--buttonized-region-p)
            (narrow-to-region hywiki--buttonize-start hywiki--buttonize-end)
            (goto-char hywiki--buttonize-start))
 
@@ -1915,7 +1966,7 @@ If in a programming mode, must be within a comment.  Use
          (unless hywiki--highlighting-done-flag
            (unless on-page-name
              ;; May be a closing delimiter that we have to skip past
-             (skip-chars-backward (regexp-quote 
(hywiki-get-buttonize-characters))))
+             (skip-chars-backward (hywiki-get-buttonize-characters)))
            ;; Skip past HyWikiWord or section
            (skip-syntax-backward "^-$()<>._\"\'")
            (skip-chars-backward "-_*#:[:alnum:]")
@@ -1924,31 +1975,29 @@ If in a programming mode, must be within a comment.  Use
                  case-fold-search nil
                  hywiki--save-org-link-type-required 
hywiki-org-link-type-required
                  hywiki-org-link-type-required t)
-           (if (and (hywiki-maybe-at-wikiword-beginning)
-                    (looking-at hywiki--word-and-buttonize-character-regexp)
-                    (progn
-                      (setq hywiki--page-name (match-string-no-properties 2)
-                            hywiki--start (match-beginning 1)
-                            hywiki--end   (match-end 1))
-                      (hywiki-get-referent hywiki--page-name)))
-               (when (setq hywiki--buts (hproperty:but-get-all-in-region
-                                         hywiki--start hywiki--end
-                                         'face hywiki-word-face))
-                 (hproperty:but-clear-all-in-list hywiki--buts))
+           (unless (and (hywiki-maybe-at-wikiword-beginning)
+                        (looking-at 
hywiki--word-and-buttonize-character-regexp)
+                        (progn
+                          (setq hywiki--word-only (match-string-no-properties 
2)
+                                hywiki--start (match-beginning 1)
+                                hywiki--end   (match-end 1))
+                          (hywiki-get-referent hywiki--word-only)))
              ;; Remove any potential earlier highlighting since the
              ;; previous word may have changed.
-             (skip-syntax-backward "^-$()<>._\"\'")
-             (hproperty:but-clear-all-in-list
-              (hproperty:but-get-all-in-region (point) (1+ (point))
-                                               'face hywiki-word-face)))))))))
+             (skip-syntax-backward "^-$()<>._\"\'"))
+
+           (hproperty:but-clear-all-in-list
+            (hproperty:but-get-all-in-region (or hywiki--start (point))
+                                             (or hywiki--end (1+ (point)))
+                                             'face hywiki-word-face))))))))
 
 ;;;###autoload
 (defun hywiki-maybe-highlight-page-name (&optional on-page-name)
-  "Highlight any non-Org link HyWiki page#section at or one char before point.
+  "Highlight any non-Org link HyWikiWord#section at or one char before point.
 With optional ON-PAGE-NAME non-nil, assume point is within the page or
-section name.  Otherwise, if `pre-command-hook' has set
+section name.  Otherwise, if a HyWiki per-character hook has set
 `hywiki--buttonize-start' `hywiki--buttonize-end' global variables,
-use these as the region in which to highlight.
+use these as the region to highlight.
 
 If in a programming mode, must be within a comment.  Use
 `hywiki-word-face' to highlight.  Do not highlight references to
@@ -1957,89 +2006,87 @@ the current page unless they have sections attached."
   (when (and (hywiki-active-in-current-buffer-p)
             (if (and (derived-mode-p 'prog-mode)
                      (not (apply #'derived-mode-p 
hywiki-highlight-all-in-prog-modes)))
-                ;; Non-nil if match is inside a comment
+                ;; Non-nil if match is inside a comment or string
                 (or (nth 4 (syntax-ppss)) (hypb:in-string-p))
               t)
             ;;  (or on-page-name
-            ;;  (cl-find (char-syntax last-command-event)
-            ;;           " _()<>$.\"'"))
+            ;;  (string-match (regexp-quote (char-to-string (char-syntax 
last-command-event)))
+            ;;                " _()<>$.\"'"))
              (not executing-kbd-macro)
              (not noninteractive))
       (setq hywiki--highlighting-done-flag nil)
       (with-syntax-table hbut:syntax-table
        (save-excursion
-         (save-restriction
-           (when (and (marker-position hywiki--buttonize-start)
-                      (marker-position hywiki--buttonize-end))
-             (narrow-to-region hywiki--buttonize-start hywiki--buttonize-end)
-             (goto-char hywiki--buttonize-start))
+         (when (hywiki--buttonized-region-p)
+           (goto-char hywiki--buttonize-start))
 
-           (unless on-page-name
-             ;; after page name
-             (skip-syntax-backward ">-"))
+         (unless on-page-name
+           ;; after page name
+           (skip-syntax-backward ">-"))
+
+         (unless (or hywiki--highlighting-done-flag
+                     (hywiki-maybe-highlight-balanced-pairs))
 
-           (unless (or hywiki--highlighting-done-flag
-                       (hywiki-maybe-highlight-balanced-pairs))
+           (unless on-page-name
+             ;; May be a HyWikiWord ending character to skip past
+             (skip-chars-backward (hywiki-get-buttonize-characters)
+                                  (line-beginning-position)))
+           ;; Skip past HyWikiWord or section
+           (skip-syntax-backward "^-$()<>._\"\'")
+           (skip-chars-backward "-_*#:[:alnum:]")
 
-             (unless on-page-name
-               ;; May be a closing delimiter that we have to skip past
-               (skip-chars-backward (regexp-quote 
(hywiki-get-buttonize-characters))))
-             ;; Skip past HyWikiWord or section
+           (setq hywiki--save-case-fold-search case-fold-search
+                 case-fold-search nil
+                 hywiki--save-org-link-type-required 
hywiki-org-link-type-required
+                 hywiki-org-link-type-required t
+                 hywiki--start nil
+                 hywiki--end   nil)
+
+           (if (and (cl-destructuring-bind (word start end)
+                        (hywiki-word-at :range)
+                      (setq hywiki--word-only word
+                            hywiki--start start
+                            hywiki--end end))
+                    hywiki--start
+                    (hywiki-get-referent hywiki--word-only)
+                    (goto-char hywiki--start))
+               (progn
+                 (setq hywiki--current-page (hywiki-get-buffer-page-name))
+                 ;; Don't highlight current-page matches unless they
+                 ;; include a #section.
+                 (unless (string-equal hywiki--current-page
+                                       (buffer-substring-no-properties
+                                        hywiki--start hywiki--end))
+                   (if (setq hywiki--buts (hproperty:but-get-all-in-region
+                                           hywiki--start hywiki--end
+                                           'face hywiki-word-face))
+                       (if (> (length hywiki--buts) 1)
+                           (progn (hproperty:but-clear-all-in-list 
hywiki--buts)
+                                  (hywiki-maybe-highlight-page-names
+                                   hywiki--start hywiki--end))
+                         ;; There is only one existing button
+                         (setq hywiki--buts (car hywiki--buts)
+                               hywiki--but-start (hproperty:but-start 
hywiki--buts)
+                               hywiki--but-end   (hproperty:but-end 
hywiki--buts))
+                         (unless (and (= hywiki--start hywiki--but-start)
+                                      (= hywiki--end hywiki--but-end))
+                           (hproperty:but-delete hywiki--buts)
+                           (hywiki-maybe-highlight-page-names
+                            hywiki--start hywiki--end)))
+                     (hywiki-maybe-highlight-page-names
+                      hywiki--start hywiki--end))))
+             ;; Remove any potential earlier highlighting since the
+             ;; previous word may have changed.
              (skip-syntax-backward "^-$()<>._\"\'")
-             (skip-chars-backward "-_*#:[:alnum:]")
-
-             (setq hywiki--save-case-fold-search case-fold-search
-                   case-fold-search nil
-                   hywiki--save-org-link-type-required 
hywiki-org-link-type-required
-                   hywiki-org-link-type-required t
-                   hywiki--start nil
-                   hywiki--end   nil)
-
-             (if (and (hywiki-maybe-at-wikiword-beginning)
-                      (looking-at hywiki--word-and-buttonize-character-regexp)
-                      (progn
-                        (setq hywiki--page-name (match-string-no-properties 2)
-                              hywiki--start (match-beginning 1)
-                              ;; This excludes optional char after the 
page#section
-                              hywiki--end   (match-end 1))
-                        (hywiki-get-referent hywiki--page-name)))
-                 (progn
-                   (setq hywiki--current-page (hywiki-get-buffer-page-name))
-                   ;; Don't highlight current-page matches unless they
-                   ;; include a #section.
-                   (unless (string-equal hywiki--current-page
-                                         (buffer-substring-no-properties
-                                          hywiki--start hywiki--end))
-                     (if (setq hywiki--buts (hproperty:but-get-all-in-region
-                                             hywiki--start hywiki--end
-                                             'face hywiki-word-face))
-                         (if (> (length hywiki--buts) 1)
-                             (progn (hproperty:but-clear-all-in-list 
hywiki--buts)
-                                    (hywiki-maybe-highlight-page-names
-                                     hywiki--start hywiki--end))
-                           ;; There is only one existing button
-                           (setq hywiki--buts (car hywiki--buts)
-                                 hywiki--but-start (hproperty:but-start 
hywiki--buts)
-                                 hywiki--but-end   (hproperty:but-end 
hywiki--buts))
-                           (unless (and (= hywiki--start hywiki--but-start)
-                                        (= hywiki--end hywiki--but-end))
-                             (hproperty:but-delete hywiki--buts)
-                             (hywiki-maybe-highlight-page-names
-                              hywiki--start hywiki--end)))
-                       (hywiki-maybe-highlight-page-names
-                        hywiki--start hywiki--end))))
-               ;; Remove any potential earlier highlighting since the
-               ;; previous word may have changed.
-               (skip-syntax-backward "^-$()<>._\"\'")
-               (if (setq hywiki--buts (hproperty:but-get-all-in-region
+             (when (setq hywiki--buts (hproperty:but-get-all-in-region
                                        (point) (1+ (point)) 'face 
hywiki-word-face))
-                   (if (> (length hywiki--buts) 1)
-                       (hproperty:but-clear-all-in-list hywiki--buts)
-                     ;; There is only one existing button
-                     (setq hywiki--buts (car hywiki--buts)
-                           hywiki--but-start (hproperty:but-start hywiki--buts)
-                           hywiki--but-end   (hproperty:but-end hywiki--buts))
-                     (hproperty:but-delete hywiki--buts))))))))))
+               (if (> (length hywiki--buts) 1)
+                   (hproperty:but-clear-all-in-list hywiki--buts)
+                 ;; There is only one existing button
+                 (setq hywiki--buts (car hywiki--buts)
+                       hywiki--but-start (hproperty:but-start hywiki--buts)
+                       hywiki--but-end   (hproperty:but-end hywiki--buts))
+                 (hproperty:but-delete hywiki--buts)))))))))
 
 (defun hywiki-maybe-highlight-between-page-names ()
   "Highlight any non-Org link HyWiki page#section names between point.
@@ -2047,8 +2094,31 @@ the current page unless they have sections attached."
 If in a programming mode, must be within a comment.  Use
 `hywiki-word-face' to highlight.  Do not highlight references to
 the current page unless they have sections attached."
-  (hywiki-maybe-highlight-off-page-name)
-  (hywiki-maybe-highlight-on-page-name))
+  (cond ((hproperty:char-property-range (point) 'face hywiki-word-face))
+       ((cl-destructuring-bind (word start end)
+            (hywiki-word-at :range)
+          (when (and start end)
+            (save-excursion
+              (goto-char start)
+              (when (hywiki-referent-exists-p word)
+                ;; existing wikiword
+                (hywiki-maybe-highlight-on-page-name)))
+            t)))
+       ((cl-destructuring-bind (start end)
+            (hywiki-at-range-delimiter)
+          (when (and start end)
+            (save-excursion
+              (goto-char (1+ start))
+              (skip-syntax-forward "-" (line-end-position))
+              (unless (equal (hywiki-referent-exists-p :range)
+                             '(nil nil nil))
+                ;; existing wikiword
+                (hywiki-maybe-highlight-on-page-name)))
+            t)))
+       ((looking-at "[ \t\n\r\f]")
+        (hywiki-maybe-highlight-off-page-name)
+        (hywiki-maybe-highlight-on-page-name))
+       (t (hywiki-maybe-highlight-on-page-name))))
 
 (defun hywiki-maybe-highlight-off-page-name ()
   "Highlight any non-Org link HyWiki page#section at or one char before point.
@@ -2062,9 +2132,9 @@ the current page unless they have sections attached."
   (hywiki-maybe-highlight-page-name
    ;; flag on-page-name if on a whitespace character
    (and (or (= (point) (point-max))
-           (= (char-syntax (char-after)) ? ))
+           (= (if (char-after) (char-syntax (char-after)) 0) ?\ ))
        (or (= (point) (point-min))
-           (/= (char-syntax (char-before)) ? )))))
+           (/= (if (char-before) (char-syntax (char-before)) 0) ?\ )))))
 
 (defun hywiki-maybe-highlight-on-page-name ()
   "Highlight any non-Org link HyWiki page#section at or one char before point.
@@ -2077,7 +2147,7 @@ the current page unless they have sections attached."
   (hywiki-maybe-highlight-page-name
    ;; flag on-page-name if not on a whitespace character
    (and (/= (point) (point-max))
-       (/= (char-syntax (char-after)) ? ))))
+       (/= (if (char-after) (char-syntax (char-after)) 0) ? ))))
 
 (defun hywiki-maybe-dehighlight-org-element-backward ()
   "Dehighlight HyWikiWords within a closing double/single square/angle 
bracket."
@@ -2136,8 +2206,8 @@ interactively), limit dehighlighting to the region."
       'face hywiki-word-face))
     (unless (or region-start region-end)
       (setq hywiki-buffer-highlighted-state 'd))))
-
-;;;###autoload
+;
+;;###autoload
 (defun hywiki-maybe-highlight-page-names (&optional region-start region-end 
skip-lookups-update-flag)
   "Highlight each non-Org link HyWiki page#section in a buffer/region.
 With optional REGION-START and REGION-END positions or markers (active
@@ -2179,9 +2249,12 @@ value of `hywiki-word-highlight-flag' is changed."
                           (narrow-to-region region-start region-end)))
                      ((and region-start region-end)
                       (narrow-to-region region-start region-end)))
-               ;; Enable dehighlighting in HyWiki pages
-               (let ((hywiki-word-highlight-flag))
-                 (hywiki-maybe-dehighlight-page-names))
+               ;; Enable dehighlighting in HyWiki pages only when
+               ;; whole buffer is being processed; this prevents an
+               ;; error when called from `hywiki-maybe-highlight-sexp'.
+               (unless (and region-start region-end)
+                 (let ((hywiki-word-highlight-flag))
+                   (hywiki-maybe-dehighlight-page-names)))
                (dolist (hywiki-words-regexp hywiki--any-wikiword-regexp-list)
                  (goto-char (point-min))
                  (let ((highlight-in-comments-and-strings-only
@@ -2406,7 +2479,7 @@ regexps of wikiwords, if the hash table is out-of-date."
 (defun hywiki-get-singular-wikiword (wikiword)
   "Return the singular version of the given WIKIWORD with any suffix removed.
 If `hywiki-allow-plurals-flag' is nil, return unchanged WIKIWORD name
-with andy suffix removed."
+with any suffix removed."
   (setq wikiword (hywiki-word-strip-suffix wikiword))
   (if (or (not hywiki-allow-plurals-flag)
          (not (stringp wikiword)))
@@ -2492,7 +2565,11 @@ save and potentially set `hywiki--directory-mod-time' and
   (or (file-writable-p save-file)
       (error "(hywiki-cache-save): Non-writable Environment file, \"%s\"" 
save-file))
   (let ((buf (get-file-buffer save-file)))
-    (and buf (kill-buffer buf)))
+    (when buf
+      (if (buffer-modified-p buf)
+         (save-buffer)
+       ;; (error "(hywiki-cache-save): Attempt to kill modified Environment 
file failed to save, \"%s\"" save-file)
+       (kill-buffer buf))))
   (let ((dir (or (file-name-directory save-file)
                 default-directory)))
     (or (file-writable-p dir)
@@ -2518,8 +2595,9 @@ save and potentially set `hywiki--directory-mod-time' and
        (princ ")\n")
 
        (save-buffer)
-       (set-buffer-modified-p nil)
-       (kill-buffer standard-output)))))
+       (if (buffer-modified-p)
+           (error "(hywiki-cache-save): Attempt to kill modified Environment 
file failed to save, \"%s\"" save-file)
+         (kill-buffer standard-output))))))
 
 (defun hywiki-make-referent-hasht ()
   "Rebuld referent hasht from list of HyWiki page files and non-page entries."
@@ -2713,6 +2791,7 @@ variables."
                             :complete #'hywiki-org-link-complete
                            :export #'hywiki-org-link-export
                            :follow #'hywiki-find-referent
+                           :htmlize-link #'hywiki-section-to-headline-reference
                            :store #'hywiki-org-link-store))
 
 (defun hywiki-word-strip-suffix (page-name)
@@ -2737,8 +2816,8 @@ Customize this directory with:
     {M-x customize-variable RET hywiki-org-publishing-directory RET}."
   (interactive "P")
   ;; Export Org to html with useful link ids.
-  ;; Instead of random ids like \"orga1b2c3\", use heading titles,
-  ;; made unique when necessary."
+  ;; Instead of random ids like "orga1b2c3", use heading titles with
+  ;; spaces replaced with dashes, made unique when necessary.
   (unwind-protect
       (progn
        (advice-add #'org-export-get-reference :override 
#'hywiki--org-export-get-reference)
@@ -2746,37 +2825,48 @@ Customize this directory with:
     (advice-remove #'org-export-get-reference 
#'hywiki--org-export-get-reference)))
 
 (defun hywiki-referent-exists-p (&optional word start end)
-  "Return an optional HyWiki WORD or word at point, if has an existing 
referent.
+  "Return the HyWikiWord at point or optional HyWiki WORD, if has a referent.
 If no such referent exists, return nil.
 
 Word may be of form:
  1. HyWikiWord#section with an optional #section.
  2. If WORD is the symbol, :range, and there is a HyWikiWord at point
     with an existing referent, return the tuple of values: (word
-    word-start word-end) instead of the word.
+    word-start word-end) instead of the word; otherwise, return the tuple
+    '(nil nil nil).
 
 When using the word at point, a call to `hywiki-active-in-current-buffer-p'
-at point must return non-nil or this function will return nil." 
-  (setq hywiki--page-name word)
+at point must return non-nil or this function will return nil."
+  (setq hywiki--word-only word)
   (when (stringp word)
     (setq word (hywiki-strip-org-link word)))
   (if (or (stringp word)
          (setq word (hywiki-word-at word)))
-      (unless (hywiki-get-referent word)
+      (unless (hywiki-get-referent (if (stringp word) word (nth 0 word)))
        (setq word nil))
     (setq word nil))
   (when (and (listp word) (= (length word) 3))
     (setq start (nth 1 word)
          end   (nth 2 word)
+         ;; `word' must be set last so list version can be referenced
+         ;; first above
          word  (nth 0 word)))
-  (if (eq hywiki--page-name :range)
-      (if (and word (setq hywiki--range
-                         (hproperty:char-property-range
-                          (point) 'face hywiki-word-face)))
-         (list word (or start (car hywiki--range)) (or end (cdr 
hywiki--range)))
-       (list word start end))
+  (if (eq hywiki--word-only :range)
+      (or (hywiki-word-at :range)
+         (list word start end))
     word))
 
+(defun hywiki-section-to-headline-reference ()
+  "Replace file#section dashes with spaces to match to an Org headline.
+Does replacement only when not in a programming mode and section
+contains no spaces."
+ (let ((link (get-text-property (point) 'org-link)))
+   (if (and link (string-match "#" link))
+       (let* ((file (substring link 0 (match-beginning 0)))
+              (section (substring link (match-beginning 0))))
+        (concat file (hpath:dashes-to-spaces-markup-anchor section)))
+     link)))
+
 (defun hywiki-strip-org-link (link-str)
   "Return the hy:HyWikiWord#section part of an Org link string.
 Strip any square bracket delimiters, description and leading or
@@ -2846,12 +2936,13 @@ Action Key press; with a prefix ARG, emulate an Assist 
Key press."
        (hywiki-find-referent word)
       (hkey-either arg))))
 
-(defun hywiki-word-at (&optional range-flag)
-  "Return potential HyWikiWord and optional #section:Lnum:Cnum at point or nil.
-Point should be on the HyWikiWord itself.
+(defun hywiki-word-highlighted-at-p (&optional range-flag)
+  "Return highlighted HyWikiWord and optional #section:Lnum:Cnum at point or 
nil.
+If the HyWikiWord is delimited, point must be within the delimiters.
 
 With optional RANGE-FLAG, return a list of (HyWikiWord start-position
-end-position); the positions are for only the HyWikiWord itself.
+end-position); the positions include the entire
+HyWikiWord#section:Lnum:Cnum string but exclude any delimiters.
 
 This does not test whether a referent exists for the HyWiki word; call
 `hywiki-referent-exists-p' without an argument for that.
@@ -2862,10 +2953,29 @@ or this will return nil."
     (if (setq hywiki--range
              (hproperty:char-property-range (point) 'face hywiki-word-face))
        (let ((wikiword (buffer-substring-no-properties (car hywiki--range) 
(cdr hywiki--range))))
-         (when (string-match hywiki-word-with-optional-suffix-exact-regexp 
wikiword)
-           (if range-flag
-               (list wikiword (car hywiki--range) (cdr hywiki--range))
-             wikiword)))
+         (if (string-match hywiki-word-with-optional-suffix-exact-regexp 
wikiword)
+             (if range-flag
+                 (list wikiword (car hywiki--range) (cdr hywiki--range))
+               wikiword)
+           (when range-flag
+             '(nil nil nil)))))))
+
+(defun hywiki-word-at (&optional range-flag)
+  "Return potential HyWikiWord and optional #section:Lnum:Cnum at point or nil.
+If the HyWikiWord is delimited, point must be within the delimiters.
+This works regardless of whether the HyWikiWord has been highlighted
+or not.
+
+With optional RANGE-FLAG, return a list of (HyWikiWord start-position
+end-position); the positions include the entire
+HyWikiWord#section:Lnum:Cnum string but exclude any delimiters.
+
+This does not test whether a referent exists for the HyWiki word; call
+`hywiki-referent-exists-p' without an argument for that.
+
+A call to `hywiki-active-in-current-buffer-p' at point must return non-nil
+or this will return nil."
+  (if (hywiki-active-in-current-buffer-p)
       (save-excursion
        ;; Don't use `cl-destructuring-bind' here since the `hargs:delimited' 
call
        ;; can return nil rather than the 3 arg list that would be required
@@ -2880,56 +2990,183 @@ or this will return nil."
               (wikiword (nth 0 wikiword-start-end))
               (start    (nth 1 wikiword-start-end))
               (end      (nth 2 wikiword-start-end)))
-         (when (if wikiword
-                   ;; Handle an Org link [[HyWikiWord]] [[hy:HyWikiWord]]
-                   ;; or [[HyWikiWord#section][Description Text]].
-                   ;; Get the HyWikiWord link reference, ignoring any
-                   ;; description given in the link
-                   ;; Don't use next line so don't have to load all of Org
-                   ;; mode just to check for HyWikiWords; however, disables
-                   ;; support for Org mode aliases.
-                   ;; (setq wikiword (org-link-expand-abbrev 
(org-link-unescape (string-trim wikiword))))
-                   (progn
-                     (setq wikiword (hywiki-strip-org-link wikiword))
-                     (when (and wikiword end)
-                       ;; Update start and end to newly stripped
-                       ;; string positions
-                       (save-excursion
-                         (save-restriction
-                           (narrow-to-region start end)
-                           (goto-char (point-min))
-                           (when (search-forward wikiword nil t)
-                             (setq start (match-beginning 0)
-                                   end   (match-end 0))))))
-                     (hywiki-word-is-p wikiword))
-                 ;; Handle a non-delimited HyWiki word with optional
-                 ;; #section:Lnum:Cnum; if it is an Org link, it may
-                 ;; optionally have a hy: link-type prefix.  Ignore
-                 ;; wikiwords preceded by any non-whitespace
-                 ;; character, except any of these: "([\"'`'"
-                 (let ((case-fold-search nil))
-                   (skip-chars-backward "-_*#:[:alnum:]")
-                   (when (hywiki-maybe-at-wikiword-beginning)
-                     (cond ((looking-at 
hywiki--word-and-buttonize-character-regexp)
-                            (setq start (match-beginning 1)
-                                  end (match-end 1)
-                                  wikiword (string-trim
-                                            (buffer-substring-no-properties 
start end))))
-                           ((looking-at (concat 
hywiki-word-with-optional-suffix-regexp "\\'"))
+         (with-syntax-table hywiki--org-mode-syntax-table
+           (if (and (cond (wikiword
+                      ;; Handle an Org link [[HyWikiWord]] [[hy:HyWikiWord]]
+                      ;; or [[HyWikiWord#section][Description Text]].
+                      ;; Get the HyWikiWord link reference, ignoring any
+                      ;; description given in the link
+                      ;; Don't use next line so don't have to load all of Org
+                      ;; mode just to check for HyWikiWords; however, disables
+                      ;; support for Org mode aliases.
+                      ;; (setq wikiword (org-link-expand-abbrev 
(org-link-unescape (string-trim wikiword))))
+                      (setq wikiword (hywiki-strip-org-link wikiword))
+                      (when (and wikiword end)
+                        ;; Update start and end to newly stripped
+                        ;; string positions
+                        (save-excursion
+                          (save-restriction
+                            (narrow-to-region start end)
+                            (goto-char (point-min))
+                            (when (search-forward wikiword nil t)
+                              (setq start (match-beginning 0)
+                                    end   (match-end 0))))))
+                      (hywiki-word-is-p wikiword))
+
+                     ;; Handle delimited HyWikiWord references with
+                     ;; multiple words in their sections,
+                     ;; e.g. (MyWikiWord WikiWord#one two three)
+                     ((let ((case-fold-search nil)
+                            (bol (line-beginning-position))
+                            opoint)
+                        ;; May be a HyWikiWord ending character to skip past
+                        (skip-chars-backward (hywiki-get-buttonize-characters) 
bol)
+                        (setq opoint (point))
+                        (when (hywiki-delimited-p)
+                          (unless (progn
+                                    ;; Skip past HyWikiWord or section with
+                                    ;; possible whitespace
+                                    (skip-syntax-backward "^$()<>._\"\'" bol)
+                                    (unless (= (or (char-before) 0) ?#)
+                                      (goto-char opoint)
+                                      (skip-syntax-backward "^-$()<>._\"\'" 
bol))
+                                    ;; Move to start of wikiword reference
+                                    (skip-chars-backward "-_*#:[:alnum:]" bol)
+                                    (skip-syntax-backward "-" bol)
+                                    ;; Preceding char must now be the
+                                    ;; opening delimiter or else there may
+                                    ;; be multiple non-section words within
+                                    ;; the delimiters, so reprocess and do
+                                    ;; not allow spaces in the #section part
+                                    (memq (char-syntax (or (char-before) 0))
+                                          '(?\( ?\< ?\")))
+                            (goto-char opoint)
+                            (skip-syntax-backward "^-$()<>._\"\'" bol)
+                            ;; Move to start of wikiword reference
+                            (skip-chars-backward "-_*#:[:alnum:]" bol)
+                            (skip-syntax-backward "-" bol))
+                          (when (and (or (bolp)
+                                         (string-match (regexp-quote
+                                                        (char-to-string 
(char-before)))
+                                                       "\[\(\{\<\""))
+                                     (progn
+                                       (skip-chars-forward " \t")
+                                       (hywiki-maybe-at-wikiword-beginning))
+                                     (looking-at (concat
+                                                  hywiki-word-regexp
+                                                  
"\\(#[^][#()<>{}\"\n\r\f]+\\)?"
+                                                  
hywiki-word-line-and-column-numbers-regexp "?"))
+                                     ;; Can't be followed by a # character
+                                     (/= (or (char-after (match-end 0)) 0)
+                                         ?#)
+                                     (progn (goto-char (match-end 0))
+                                            (skip-syntax-forward "-")))
                             (setq start (match-beginning 0)
                                   end   (match-end 0)
                                   ;; No following char
                                   wikiword (string-trim
-                                            (buffer-substring-no-properties 
start end))))))))
-           (if range-flag
-               (list wikiword start end)
-             wikiword)))))))
+                                            (buffer-substring-no-properties 
start end)))))))
+
+                     ;; Handle non-delimited HyWikiWord references
+                     ;; with multiple dash-separated words in their sections,
+                     ;; e.g. WikiWord#one-two-three.
+                     ((let ((case-fold-search nil)
+                            (bol (line-beginning-position))
+                            opoint)
+                        ;; May be a HyWikiWord ending character to skip past
+                        (skip-chars-backward (hywiki-get-buttonize-characters) 
bol)
+                        (setq opoint (point))
+                        (goto-char opoint)
+                        (skip-syntax-backward "^-$()<>._\"\'" bol)
+                        ;; Move to start of wikiword reference
+                        (skip-chars-backward "-_*#:[:alnum:]" bol)
+                        (skip-syntax-backward "-" bol)
+                        (when (and (or (bolp)
+                                       (string-match (regexp-quote
+                                                      (char-to-string 
(char-before)))
+                                                     "\[\(\{\<\""))
+                                   (progn
+                                     (skip-chars-forward " \t")
+                                     (hywiki-maybe-at-wikiword-beginning))
+                                   (looking-at (concat
+                                                hywiki-word-regexp
+                                                "\\(#[^][#()<>{}\" 
\t\n\r\f]+\\)?"
+                                                
hywiki-word-line-and-column-numbers-regexp "?"))
+                                   ;; Can't be followed by a # character
+                                   (/= (or (char-after (match-end 0)) 0)
+                                       ?#)
+                                   (goto-char (match-end 0)))
+                          (setq start (match-beginning 0)
+                                end   (match-end 0)
+                                ;; No following char
+                                wikiword (string-trim
+                                          (buffer-substring-no-properties 
start end))))))
+
+                     ;; Handle a non-delimited HyWikiWord with optional
+                     ;; #section:Lnum:Cnum; if it is an Org link, it may
+                     ;; optionally have a hy: link-type prefix.  Ignore
+                     ;; wikiwords preceded by any non-whitespace
+                     ;; character, except any of these: "([\"'`'"
+                     (t (let ((case-fold-search nil))
+                          (skip-chars-forward " \t")
+                          (when (hywiki-maybe-at-wikiword-beginning)
+                            (when (looking-at (concat hywiki-org-link-type 
":"))
+                              (goto-char (match-end 0)))
+                            (cond ((looking-at 
hywiki--word-and-buttonize-character-regexp)
+                                   (setq start (match-beginning 1)
+                                         end (match-end 1)
+                                         wikiword (string-trim
+                                                   
(buffer-substring-no-properties start end))))
+                                  ((and (looking-at 
hywiki-word-with-optional-suffix-regexp)
+                                        ;; Can't be followed by a # character
+                                        (/= (or (char-after (match-end 0)) 0)
+                                            ?#))
+                                   (setq start (match-beginning 0)
+                                         end   (match-end 0)
+                                         ;; No following char
+                                         wikiword (string-trim
+                                                   
(buffer-substring-no-properties start end)))))))))
+                    ;; If `wikiword' has a #section, ensure there are
+                    ;; no invalid chars
+                    (if (and (stringp wikiword) (string-match "#" wikiword))
+                        (string-match "#[^][#()<>{}\"\n\r\f]+\\'" wikiword)
+                      t))
+               (if range-flag
+                   (list wikiword start end)
+                 wikiword)
+             (when range-flag
+               '(nil nil nil))))))
+    (when range-flag
+      '(nil nil nil))))
 
 (defun hywiki-word-at-point ()
   "Return singular HyWikiWord at point with its suffix stripped or nil.
-Point should be on the HyWikiWord itself."
+Point should be on the HyWikiWord itself.  Suffix is anything after
+the # symbol.
+
+This does not test whether a referent exists for the HyWiki word; call
+`hywiki-referent-exists-p' without an argument for that.
+
+A call to `hywiki-active-in-current-buffer-p' at point must return non-nil
+or this will return nil."
   (hywiki-get-singular-wikiword (hywiki-word-strip-suffix (hywiki-word-at))))
 
+(defun hywiki-delimited-p (&optional pos)
+  "Return non-nil if optional POS or point is surrounded by matching 
delimiters.
+The delimited range must be two lines or less.
+
+Use `hywiki-word-at', which calls this, to determine whether there is
+a HyWikiWord at point."
+  (save-excursion
+    (when (natnump pos)
+      (goto-char pos))
+    (or (hypb:in-string-p)
+       (let ((range (hargs:delimited-p "[\[<\(\{]" "[\]\}\)\>]" t t t)))
+         (when range
+           ;; Ensure closing delimiter is a match for the opening one
+           (= (matching-paren (char-before (nth 1 range)))
+              (char-after (nth 2 range))))))))
+
 (defun hywiki-word-face-at-p ()
   "Non-nil if but at point has `hywiki-word-face' property."
   (hproperty:but-get (point) 'face hywiki-word-face))
@@ -2962,12 +3199,16 @@ Return nil if WORD is a prefixed, typed hy:HyWikiWord, 
since
 these are handled by the Org mode link handler."
   (and (stringp word) (not (string-empty-p word))
        (let (case-fold-search)
-        (or (string-match hywiki-word-with-optional-suffix-exact-regexp word)
-            ;; For now this next version allows spaces and tabs in
-            ;; the suffix part
-            (eq 0 (string-match
-                   hywiki-word-with-optional-spaces-suffix-exact-regexp
-                   word))))))
+        (and (or (string-match hywiki-word-with-optional-suffix-exact-regexp 
word)
+                 ;; For now this next version allows spaces and tabs in
+                 ;; the suffix part
+                 (eq 0 (string-match
+                        hywiki-word-with-optional-suffix-exact-regexp
+                        word)))
+             ;; If has a #section, ensure there are no invalid chars
+             (if (string-match "#" word)
+                 (string-match "#[^][#()<>{}\"\n\r\f]+\\'" word)
+               t)))))
 
 (defun hywiki-word-read (&optional prompt)
   "Prompt with completion for and return an existing HyWikiWord.
@@ -3036,6 +3277,13 @@ auto-highlighting."
 ;;; Private functions
 ;;; ************************************************************************
 
+(defun hywiki--buttonized-region-p ()
+  "Return non-nil when hywiki--buttonize-start/end point to the current 
buffer."
+  (and (marker-position hywiki--buttonize-start)
+       (eq (marker-buffer hywiki--buttonize-start) (current-buffer))
+       (marker-position hywiki--buttonize-end)
+       (eq (marker-buffer hywiki--buttonize-end) (current-buffer))))
+
 (defun hywiki--add-suffix-to-referent (suffix referent)
   "Add SUFFIX to REFERENT's value and return REFERENT.
 SUFFIX includes its type prefix, e.g. #.  Return nil if any input is
@@ -3114,7 +3362,8 @@ or balanced pair delimiters."
 
 (defun hywiki--get-delimited-range-backward ()
   "Return a list of (start end) if not between/after end ]] or >>.
-Otherwise, return nil."
+Delimiters are included in the range.  Point must be on or after the
+closing delimiter.  Otherwise, return nil."
   (save-excursion
     (unless (or (eq (char-before) (char-before (1- (point))))
                (and (char-after)
@@ -3124,7 +3373,8 @@ Otherwise, return nil."
 
 (defun hywiki--get-delimited-range-forward ()
   "Return a list of (start end) if not between/before opening [[ or <<.
-Otherwise, return nil."
+Delimiters are included in the range.  Point must be on or after the
+opening delimiter.  Otherwise, return nil."
   (save-excursion
     (unless (or (eq (char-after) (char-after (1+ (point))))
                (and (char-before)
@@ -3174,21 +3424,66 @@ delimited grouping."
       ;; single delimiters - highlight
       (funcall func 1))))
 
-(defun hywiki--maybe-de/highlight-sexp (func direction-number)
-  "De/highlight HyWikiWord with FUNC on a single square/angle bracket.
+(defun hywiki--maybe-de/highlight-sexp (func direction-number &optional 
sexp-start sexp-end)
+  "De/highlight HyWikiWord with FUNC on a single paired delimiter char.
 DIRECTION-NUMBER is 1 for forward scanning and -1 for backward scanning."
-  (let* ((sexp-start (point))
-        (sexp-end (scan-sexps sexp-start direction-number)))
-    (when (and sexp-start sexp-end)
-      (cl-destructuring-bind (start end)
-         ;; Point may be at end of sexp, so start and end may
-         ;; need to be reversed.
-         (list (min sexp-start sexp-end) (max sexp-start sexp-end))
-       ;; Increment sexp-start so regexp matching excludes the
-       ;; delimiter and starts with the page name.  But include any
-       ;; trailing delimiter or regexp matching will not work.
-       (funcall func (1+ start) end)
-       (setq hywiki--highlighting-done-flag nil)))))
+  (setq sexp-start (or sexp-start (point))
+       sexp-end (or sexp-end (scan-sexps sexp-start direction-number)))
+  (when (and sexp-start sexp-end)
+    (cl-destructuring-bind (start end)
+       ;; Point may be at end of sexp, so start and end may
+       ;; need to be reversed.
+       (list (min sexp-start sexp-end) (max sexp-start sexp-end))
+      ;; Increment sexp-start so regexp matching excludes the
+      ;; delimiter and starts with the HyWikiWord.  But include any
+      ;; trailing delimiter or regexp matching will not work.
+      (save-restriction
+       (narrow-to-region (1+ start) end)
+       (prog1 (funcall func (1+ start) end)
+         (setq hywiki--highlighting-done-flag nil))))))
+
+(defun hywiki--maybe-dehighlight-at-point ()
+  "Dehighlight any existing HyWikiWord when needed.
+That is, only if the editing command has changed the word-only part of
+the HyWikiWord reference."
+  (when (and hywiki--word-pre-command
+            (not (equal hywiki--word-pre-command
+                        (hywiki-get-singular-wikiword
+                         (or (car hywiki--range)
+                             (when (hywiki--buttonized-region-p)
+                               (buffer-substring hywiki--buttonize-start
+                                                 hywiki--buttonize-end))
+                             (when (and (setq hywiki--range (hywiki-word-at 
:range))
+                                        (nth 1 hywiki--range))
+                               (prog1 (nth 1 hywiki--range)
+                                 (setq hywiki--range nil)))
+)))))
+    ;; Dehighlight if point is on or between a HyWikiWord
+    (hywiki-maybe-dehighlight-between-page-names)))
+
+(defun hywiki--maybe-rehighlight-at-point ()
+  "Dehighlight any existing HyWikiWord when needed.
+That is, only if the editing command has changed the word-only part of
+the HyWikiWord reference.
+
+This must be called within a `save-excursion' or it may move point."
+
+  (hywiki--maybe-dehighlight-at-point)
+
+  ;; Highlight wikiwords around point as needed
+  (when hywiki--range
+    (hywiki-maybe-highlight-on-page-name))
+
+  (when (hywiki--buttonized-region-p)
+    (hywiki--maybe-de/highlight-sexp
+     #'hywiki-maybe-highlight-page-names 1
+     hywiki--buttonize-start hywiki--buttonize-end))
+
+  (cond ((= (char-syntax (or (char-before) 0)) ?\ )
+        (goto-char (1- (point)))
+        (hywiki-maybe-highlight-between-page-names))
+       ((= (char-syntax (or (char-after) 0)) ?\ )
+        (hywiki-maybe-highlight-between-page-names))))
 
 ;;; ************************************************************************
 ;;; Private Org export override functions
@@ -3293,7 +3588,8 @@ matching DATUM before creating a new reference."
                  num (if num
                           (string-to-number num)
                         0)
-                 ref (format "%s%s" parent (cl-incf num)))))))
+                 num (1+ num)
+                 ref (format "%s%s" parent num))))))
     ref))
 
 (defun hywiki--org-format-reference (title)
@@ -3311,7 +3607,7 @@ matching DATUM before creating a new reference."
 ;; Must be set after `hywiki-get-buttonize-characters' is defined
 (unless hywiki--buttonize-characters
   (setq hywiki--buttonize-characters
-       (concat "[]()<>{} \t\r\n'" (hywiki-get-buttonize-characters))
+       (concat "[]()<>{}\"' \t\r\n" (hywiki-get-buttonize-characters))
        hywiki--buttonize-character-regexp
        (concat "\\([]["
                (regexp-quote (substring hywiki--buttonize-characters 2))
@@ -3339,6 +3635,10 @@ matching DATUM before creating a new reference."
 (hywiki-word-highlight-flag-changed 'hywiki-word-highlight-flag
                                    hywiki-word-highlight-flag 'set nil)
 
+;; Ensures HyWiki referent lookup table is initialized as are HyWiki Org
+;; Publish settings.
+(hywiki-set-directory 'hywiki-directory hywiki-directory)
+
 (provide 'hywiki)
 
 ;;; hywiki.el ends here
diff --git a/man/hyperbole.texi b/man/hyperbole.texi
index e66da842f1..438331af61 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:     19-Jan-25 at 18:06:31 by Bob Weiner
+@c Last-Mod:     16-Mar-25 at 10:23:12 by Bob Weiner
 
 @c %**start of header (This is for running Texinfo on a region.)
 @setfilename hyperbole.info
@@ -30,8 +30,8 @@
 @set txicodequoteundirected
 @set txicodequotebacktick
 
-@set UPDATED January, 2025
-@set UPDATED-MONTH January 2025
+@set UPDATED March, 2025
+@set UPDATED-MONTH March 2025
 @set EDITION 9.0.2pre
 @set VERSION 9.0.2pre
 
@@ -171,7 +171,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.</P>
 
 <PRE>
 Edition 9.0.2pre
-Printed January 19, 2025.
+Printed March 16, 2025.
 
   Published by the Free Software Foundation, Inc.
   Author:    Bob Weiner
@@ -213,7 +213,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 @example
 Edition 9.0.2pre
-January 19, 2025
+March 16, 2025
 
   Published by the Free Software Foundation, Inc.
   Author:    Bob Weiner
@@ -538,8 +538,8 @@ Smart Keyboard Keys
 @chapter Introduction
 
 This edition of the GNU Hyperbole Manual is for use with any version
-9.0.2pre or greater of GNU Hyperbole.  Hyperbole runs atop GNU Emacs 27.2
-or higher.  It will trigger an error if your Emacs is older.
+9.0.2pre or greater of GNU Hyperbole.  Hyperbole runs atop GNU Emacs
+28 or higher.  It will trigger an error if your Emacs is older.
 
 This chapter summarizes the structure of the rest of the manual,
 describes Hyperbole, lists some of its potential applications, and
@@ -8628,8 +8628,8 @@ the GNU Emacs Manual}).
 @group
 ;; Below are the lines to add:
 
-(when (< emacs-major-version 27)
-  (error "Hyperbole requires Emacs 27 or above, not %d"
+(when (< emacs-major-version 28)
+  (error "Hyperbole requires Emacs 28 or above, not %d"
          emacs-major-version))
 (require 'package)
 (unless (package-installed-p 'hyperbole)
@@ -8677,8 +8677,8 @@ the GNU Emacs Manual}).
 @group
 ;; Below are the lines to add:
 
-(when (< emacs-major-version 27)
-  (error "Hyperbole requires Emacs 27 or above, not %d"
+(when (< emacs-major-version 28)
+  (error "Hyperbole requires Emacs 28 or above, not %d"
          emacs-major-version))
 (require 'package)
 (add-to-list 'package-archives
@@ -8724,8 +8724,8 @@ the GNU Emacs Manual}).
 @group
 ;; Use this in your Emacs init file to install Straight
 (progn
-  (when (< emacs-major-version 27)
-    (error "Hyperbole requires Emacs 27 or above, not %d"
+  (when (< emacs-major-version 28)
+    (error "Hyperbole requires Emacs 28 or above, not %d"
            emacs-major-version))
   (defvar bootstrap-version)
   (setq package-enable-at-startup nil)
@@ -8785,8 +8785,8 @@ lines to your personal Emacs initialization file, 
@file{~/.emacs}:
 @lisp
 @group
 (unless (and (featurep 'hyperbole) hyperbole-mode)
-  (when (< emacs-major-version 27)
-    (error "Hyperbole requires Emacs 27 or above, not %d"
+  (when (< emacs-major-version 28)
+    (error "Hyperbole requires Emacs 28 or above, not %d"
            emacs-major-version))
   (push "<directory-ending-with-hyperbole-where-you-unpacked>"
         load-path)
diff --git a/test/MANIFEST b/test/MANIFEST
index 00dbe43c1e..37356fdd7b 100644
--- a/test/MANIFEST
+++ b/test/MANIFEST
@@ -13,6 +13,7 @@ hpath-tests.el          - unit tests for hpath
 hsettings-test.el       - unit tests for hsettings
 hsys-org-tests.el       - hsys-org tests
 hui-mini-tests.el       - hui-mini tests
+hui-mouse-tests.el      - hui-mouse and hkey-alist Action Key tests
 hui-register-tests.el   - test for hui-register
 hui-select-tests.el     - hui-select tests
 hui-tests.el            - tests for hui.el Hyperbole UI
diff --git a/test/hsys-org-tests.el b/test/hsys-org-tests.el
index 48117ee803..a7fa8ed9a0 100644
--- a/test/hsys-org-tests.el
+++ b/test/hsys-org-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:    23-Apr-21 at 20:55:00
-;; Last-Mod:     16-Nov-24 at 09:45:51 by Mats Lidell
+;; Last-Mod:     13-Apr-25 at 03:23:46 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -139,9 +139,8 @@ This is independent of the setting of 
`hsys-org-enable-smart-keys'."
           (with-temp-buffer
             (insert "[[file:/tmp/abc][file]]\n")
             (goto-char 6)
-            (mocklet (((org-open-at-point-global) => t))
-              (should (equal hsys-org-enable-smart-keys v)) ; Traceability
-              (should (action-key))))))))
+            (should (equal hsys-org-enable-smart-keys v)) ; Traceability
+            (should (action-key)))))))
 
 (ert-deftest hsys-org--org-outside-org-mode-tmp-file ()
   "Org links in a non `org-mode' file should work.
diff --git a/test/hywiki-tests.el b/test/hywiki-tests.el
index 1e7f54e2dd..efc1071d6a 100644
--- a/test/hywiki-tests.el
+++ b/test/hywiki-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell
 ;;
 ;; Orig-Date:    18-May-24 at 23:59:48
-;; Last-Mod:     19-Mar-25 at 19:59:12 by Mats Lidell
+;; Last-Mod:     12-Apr-25 at 17:00:40 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -234,51 +234,60 @@ line 2
           (progn
             (hywiki-mode 1)
 
-            ;; Matches a WikiWord
-            (dolist (v '("WikiWord" "[WikiWord]" "[[WikiWord]]" "{WikiWord}" 
"(WikiWord)"
-                         "<WikiWord>" "<<WikiWord>>" "{[[WikiWord]]}" 
"([[WikiWord]])"
-                         "[WikiWord AnotherWord]"
-                         ))
-              (with-temp-buffer
-                (org-mode)
-                (insert v)
-               (newline nil t)
-                (goto-char 6)
-                (should (string= "WikiWord" (hywiki-word-at)))))
-
-            ;; Does not match as a WikiWord
-            (dolist (v '("WikiWord#"))
-              (with-temp-buffer
-                (org-mode)
-                (insert v)
-               (newline nil t)
-                (goto-char 6)
-                (should-not (string= "WikiWord" (hywiki-word-at)))))
-
-            ;; Identifies as org link (Note: Not checked if target
-            ;; exists.) AND matches WikiWord
-            (dolist (v '("[[hy:WikiWord]]" "[[hy:WikiWord\\]]]"))
-              (with-temp-buffer
-                (org-mode)
-                (insert v)
-               (newline nil t)
-                (goto-char 6)
-                (font-lock-ensure)
-                (should (hsys-org-face-at-p 'org-link))
-                (should (string= "WikiWord" (hywiki-word-at)))))
-
-            ;; Identifies as org link (Note: Not checked if target
-            ;; exists.) AND DOES NOT match WikiWord
-            (dolist (v '("[[WikiWord AnotherWord]]"))
-              (with-temp-buffer
-                (org-mode)
-                (insert v)
-               (newline nil t)
-                (goto-char 6)
-                (font-lock-ensure)
-                (should (hsys-org-face-at-p 'org-link))
-                (should-not (string= "WikiWord" (hywiki-word-at))))))
-        (hy-delete-dir-and-buffer hywiki-directory)))))
+          ;; Matches a WikiWord
+          (dolist (v '("WikiWord" "[WikiWord]" "[[WikiWord]]" "{WikiWord}" 
"(WikiWord)"
+                       "<WikiWord>" "<<WikiWord>>" "{[[WikiWord]]}" 
"([[WikiWord]])"
+                       "[WikiWord AnotherWord WikiWord WikiWord]"
+                       ))
+            (with-temp-buffer
+              (org-mode)
+              (insert v)
+             (newline nil t)
+              (goto-char 6)
+              (if (string= "WikiWord" (hywiki-word-at))
+                 (should t)
+               (should-not v))))
+
+          ;; Does not match as a WikiWord
+          (dolist (v '("WikiWord#"))
+            (with-temp-buffer
+              (org-mode)
+              (insert v)
+             (newline nil t)
+              (goto-char 6)
+             (if (string= "WikiWord" (hywiki-word-at))
+                 (should-not v)
+               (should t))))
+
+          ;; Identifies as org link (Note: Not checked if target
+          ;; exists.) AND matches WikiWord
+          (dolist (v '("[[hy:WikiWord]]" "[[hy:WikiWord\\]]]"))
+            (with-temp-buffer
+              (org-mode)
+              (insert v)
+             (newline nil t)
+              (goto-char 6)
+              (font-lock-ensure)
+              (should (hsys-org-face-at-p 'org-link))
+             (if (string= "WikiWord" (hywiki-word-at))
+                 (should t)
+               (should-not v))))
+
+          ;; Identifies as org link (Note: Not checked if target
+          ;; exists.) AND DOES NOT match WikiWord
+          (dolist (v '("[[WikiWord AnotherWord]]"))
+            (with-temp-buffer
+              (org-mode)
+              (insert v)
+             (newline nil t)
+              (goto-char 6)
+              (font-lock-ensure)
+              (should (hsys-org-face-at-p 'org-link))
+              (if (string= "WikiWord" (hywiki-word-at))
+                 (should-not v)
+               (should t)))))
+      (hywiki-mode 0)
+      (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--at-wikiword-finds-word-and-section ()
   "Verify `hywiki-word-at' finds WikiWord and section if available."
@@ -287,7 +296,7 @@ line 2
           (words '("WikiWord" "WikiWord:L1" "WikiWord:L1:C2"
                    "WikiWord#section" "WikiWord#section:L1" 
"WikiWord#section:L1:C2"
                    "WikiWord#section-subsection" 
"WikiWord#section-subsection:L1" "WikiWord#section-subsection:L1:C2"
-                   ;; FIXME: Uncomment when implemented.
+                   ;; !! FIXME: Uncomment when implemented.
                    ;; ("(WikiWord#section with spaces)" . "WikiWord#section 
with spaces")
                    ;; ("(WikiWord#section)" . "WikiWord#section")
                    )))
@@ -321,7 +330,7 @@ line 2
             (with-temp-buffer
               (insert "WikiWord#\"section-within-quotes\"")
               (goto-char 4)
-              (should (string= "WikiWord#\"section-within-quotes\"" 
(hywiki-word-at)))))
+              (should-not (string= "WikiWord#\"section-within-quotes\"" 
(hywiki-word-at)))))
         (hy-delete-dir-and-buffer hywiki-directory)))))
 
 (ert-deftest hywiki-tests--word-is-p ()
@@ -986,7 +995,8 @@ Note special meaning of `hywiki-allow-plurals-flag'."
   (let* ((hywiki-directory (make-temp-file "hywiki" t))
         (wikiword (hy-make-random-wikiword)))
     (unwind-protect
-        (mocklet (((hypb:require-package 'org-roam) => t)
+        (mocklet ((cl-struct-org-roam-node-tags => nil)
+                 ((hypb:require-package 'org-roam) => t)
                  ((org-roam-node-read) => "node")
                  (org-roam-node-title => "node-title"))
          (hywiki-add-org-roam-node wikiword)
@@ -1064,6 +1074,7 @@ up the test."
    (should (hact 'kbd-key "C-u C-h hhck{ABC} RET"))
    (hy-test-helpers:consume-input-events)))
 
+;; !! TODO: Have to make this work or remove it.
 ;; Expanded for easier debugging
 ;; (ert-deftest hywiki-tests--save-referent-keyseries-use--menu-expanded ()
 ;;   "Verify saving and loading a referent works when using Hyperbole's menu."
@@ -1281,6 +1292,7 @@ up the test."
    (save-excursion
      (unwind-protect
          (progn
+           ;; (should (hact 'kbd-key "C-u C-h hhc MyWiki RET n (emacs) RET"))
            (should (hact 'kbd-key "C-u C-h hhcn (emacs) RET"))
            (hy-test-helpers:consume-input-events))
        (kill-buffer "*info*")))))
@@ -1336,7 +1348,6 @@ up the test."
 (ert-deftest hywiki-tests--delete-parenthesised-char ()
   "Verify removing a char between parentheses only removes the char.
 See gh#rswgnu/hyperbole/669."
-  :expected-result :failed
   (with-temp-buffer
     (insert "(a)")
     (goto-char 2)
@@ -1430,8 +1441,8 @@ the function is called."
     (("HiHo#s " . t) (" n"))
     ;; With delimiters
     (("(HiHo#s" . "HiHo#s") (" " . "HiHo#s"))
-    (("(HiHo#s" . "HiHo#s") (")" . "HiHo#s)")) ; Delimiter part of WikiWord. 
See below too.
-    (("(HiHo#s" . "HiHo#s") ("-" . "HiHo#s-") ("n" . "HiHo#s-n") (")" . 
"HiHo#s-n)"))
+    (("(HiHo#s" . "HiHo#s") (")" . "HiHo#s")) ; Delimiter part of WikiWord. 
See below too.
+    (("(HiHo#s" . "HiHo#s") ("-" . "HiHo#s-") ("n" . "HiHo#s-n") (")" . 
"HiHo#s-n"))
     ;; Insert and delete between WikiWords
     (("HiHo" . t) (p3 . t) (" " . "Hi") (p4 . "Ho") (-1 . "HiHo"))
     (("Hiho" . t) (p3 . t) (" " . "Hi") (p4) (-1 . "Hiho"))
@@ -1489,6 +1500,51 @@ Insert test in the middle of other text."
                 (p1 . t) (p4) (-1 . "Hiho")))))
        (hy-delete-dir-and-buffer hywiki-directory)))))
 
+(ert-deftest hywiki-tests--wikiword-identified-in-emacs-lisp-mode ()
+  "Verify WikiWord is identified when surrounded by delimiters in 
`emacs-lisp-mode'."
+  (hywiki-tests--preserve-hywiki-mode
+    (let ((hsys-org-enable-smart-keys t)
+          (hywiki-directory (make-temp-file "hywiki" t)))
+      (unwind-protect
+          (progn
+            (hywiki-mode 1)
+
+            ;; Matches a WikiWord
+            (dolist (v '("WikiWord" "[WikiWord]" "[[WikiWord]]" "{WikiWord}" 
"(WikiWord)"
+                         "<WikiWord>" "<<WikiWord>>" "{[[WikiWord]]}" 
"([[WikiWord]])"
+                         "[WikiWord AnotherWord]"
+                         ))
+              (with-temp-buffer
+                (emacs-lisp-mode)
+                (insert (format ";; %s" v))
+                (hywiki-tests--command-execute #'newline 1 'interactive)
+                (goto-char 9)
+                (should (string= "WikiWord" (hywiki-word-at))))
+
+              (with-temp-buffer
+                (emacs-lisp-mode)
+                (insert (format  "(setq var \"%s\")" v))
+                (hywiki-tests--command-execute #'newline 1 'interactive)
+                (goto-char 16)
+                (should (string= "WikiWord" (hywiki-word-at)))))
+
+            ;; Does not match as a WikiWord
+            (dolist (v '("WikiWord#"))
+              (with-temp-buffer
+                (emacs-lisp-mode)
+                (insert (format ";; %s" v))
+                (hywiki-tests--command-execute #'newline 1 'interactive)
+                (goto-char 9)
+                (should-not (hywiki-word-at)))
+
+              (with-temp-buffer
+                (emacs-lisp-mode)
+                (insert (format  "(setq var \"%s\")" v))
+                (hywiki-tests--command-execute #'newline 1 'interactive)
+                (goto-char 16)
+                (should-not (hywiki-word-at)))))
+        (hy-delete-dir-and-buffer hywiki-directory)))))
+
 (provide 'hywiki-tests)
 
 ;; This file can't be byte-compiled without the `el-mock' package
diff --git a/test/kcell-tests.el b/test/kcell-tests.el
index 5d4ddeba58..9fed2b5f6c 100644
--- a/test/kcell-tests.el
+++ b/test/kcell-tests.el
@@ -7,14 +7,14 @@
 ;; e-mail:       ma...@gnu.org
 ;;
 ;; orig-date:    16-Feb-22 at 23:28:49
-;; last-mod:     23-Aug-24 at 13:27:11 by Bob Weiner
+;; last-mod:     16-Mar-25 at 10:15:23 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
 ;; Copyright (C) 2021-2024  Free Software Foundation, Inc.
 ;; Licensed under the GNU General Public License, version 3.
 ;;
-;; This file is not part of Emacs.  It requires Emacs 27.2 or above.
+;; This file is not part of Emacs.  It requires Emacs 28 or above.
 ;; This file is part of Hyperbole.
 ;;
 ;;; Commentary:

Reply via email to