branch: externals/hyperbole
commit 7fd90d5e192223ec0cbfe40b12d57875b8731afb
Merge: 575f988b41 eaad29f6e4
Author: Robert Weiner <r...@gnu.org>
Commit: GitHub <nore...@github.com>

    Merge pull request #761 from rswgnu/rsw
    
    hargs:delimited and hypb:in-string-p - point can now be on 2nd line
---
 ChangeLog                 |  47 ++++++++
 hargs.el                  | 166 ++++++++++++++--------------
 hypb.el                   |  52 ++++++---
 hywiki.el                 | 117 ++++++++++++--------
 test/hargs-tests.el       | 274 +++++++++++++++++++++++++++++++++++++++++++++-
 test/hmouse-drv-tests.el  |   6 +-
 test/hmouse-info-tests.el |   4 +-
 test/hpath-tests.el       |   2 +-
 test/hui-tests.el         |  40 +++----
 test/hy-test-helpers.el   |  14 ++-
 test/hypb-tests.el        |   9 +-
 test/hywiki-tests.el      |  26 ++---
 12 files changed, 564 insertions(+), 193 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index f18e89c785..38293d1939 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,50 @@
+2025-07-06  Bob Weiner  <r...@gnu.org>
+
+* hargs.el (hargs:delimited): Fix bug with regexp delimiters where 'start-pos' 
was
+    used instead of 'start' and this stop point from moving in a loop when 
matched
+    to bol.  This was seen in a failure of this call in 
'hpath:delimited-possible-path':
+         (let* ((space-delimiter "[ \t]"))
+           (setq triplet (hargs:delimited (format 
"^\\|\\(%s\\|[\]\[()<>\;&,@]\\)+"
+                                                  space-delimiter)
+                                          "\\([\]\[()<>\;&,@]\\|:*\\s-\\)+\\|$"
+                                          t t t)
+                 p (car triplet)))
+* hypb.el (hypb:in-string-p): Internally when computing the number of lines in
+    the string match, ignore any leading and trailing newlines.  This allows
+    for opening and closing quotes to be on separate lines, useful with
+    multi-line strings.
+  test/hypb-tests.el (hypb--in-string-p--max-lines): Update to allow for
+    quotes on separate lines from the string but don't count these lines when
+    applying 'max-lines'.
+
+* test/hy-test-helpers.el (hy-test-helpers:ert-simulate-keys): Add to
+    disable 'vertico-mode' which gets in the way of 'ert-simulate-keys' calls.
+
+* hargs.el (hargs:delimited): Use 'hypb:in-string-p' when delimiters indicate
+    a string match.  Rewrite to remove the limit that point must be on
+    the first line; can also be on the second line now and string delimiters
+    can be on lines by themselves..  Change so the 'exclude-regexp' arg is
+    compared against the match string without its delimiters, rather than with
+    them as before.  Update doc string.
+  test/hargs-tests.el (hargs-delimited-*): Add a bunch of tests for
+    `hargs:delimited'.
+
+2025-07-03  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki-word-at): A HyWikiWord reference can contain one set of
+    '\n\r' in it, so fix to allow these characters.
+
+* hypb.el (hypb:in-string-p): Allow point to be on the last line of a string
+    when given 'max-lines' arg, i.e. support prior lines.  If 'max-lines' is
+    0, always return a nil-type result.
+  hywiki.el (hywiki-at-range-delimiter, hywiki-maybe-highlight-balanced-pairs,
+             hywiki-maybe-dehighlight-balanced-pairs): Update and document to
+    allow 2-line HyWikiWord references with point on the trailing delimiter,
+    i.e. allow a line before point and one after.
+            (hywiki-delimited-p): Narrow to just a few lines to constrain
+    search for delimiters.  The use case for this function does not require
+    looking back to the previous line.
+
 2025-06-26  Mats Lidell  <ma...@gnu.org>
 
 * man/.dir-locals.el: Use with-locale-environment to ensure English is
diff --git a/hargs.el b/hargs.el
index f9a2542fcf..726de96e47 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:     11-Jun-25 at 00:20:07 by Mats Lidell
+;; Last-Mod:      6-Jul-25 at 15:28:05 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -121,20 +121,25 @@ Convert NUL characters to colons for use with grep lines."
 (defun hargs:delimited (start-delim end-delim
                        &optional start-regexp-flag end-regexp-flag
                        list-positions-flag exclude-regexp as-key)
-  "Return a delimited string that point is within the first line of, or nil.
-The string matched may be up to two lines long.  The delimiters
-are removed, the string is normalized and reduced to a single
-line.  START-DELIM and END-DELIM are strings that specify the
-argument delimiters.  With optional START-REGEXP-FLAG non-nil,
-START-DELIM is treated as a regular expression.  END-REGEXP-FLAG
-is similar.  With optional LIST-POSITIONS-FLAG, return list
-of (string-matched start-pos end-pos), where the positions
-exclude the delimiters.  Optional EXCLUDE-REGEXP is compared
-against the match string with its delimiters included; any string
-that matches this regexp is ignored.  With optional AS-KEY =
-\\='none, return t rather than the string result.  Any other
-non-nil value, means return the string normalized as a Hyperbole
-button key (no spaces)." 
+  "Return a delimited string that point is within two lines of, or nil.
+The string matched may be up to two lines long and must not
+contain any nested occurrences of START-DELIM and END-DELIM.  In
+the returned value, the delimiters are removed and the string is
+normalized by changing newlines followed by any additional
+whitespace to a single space, reducing the string to a single
+line.  Other occurrences of multiple spaces and tabs are left
+unchanged.
+
+START-DELIM and END-DELIM are strings that specify the argument
+delimiters.  With optional START-REGEXP-FLAG non-nil, START-DELIM
+is treated as a regular expression.  END-REGEXP-FLAG is similar.
+With optional LIST-POSITIONS-FLAG, return list of (string-matched
+start end), where the positions exclude the delimiters.  Optional
+EXCLUDE-REGEXP is compared against the match string without its
+delimiters; any string that matches this regexp is ignored.  With
+optional AS-KEY = \\='none, return t rather than the string
+result.  Any other non-nil value, means return the string
+normalized as a Hyperbole button key (no spaces)."
   (let* ((opoint (point))
         ;; This initial limit is the forward search limit for start delimiters
         (limit (if start-regexp-flag
@@ -148,71 +153,71 @@ button key (no spaces)."
         first
         start ;; excludes delimiter
         end   ;; excludes delimiter
-        start-pos
         end-pos
-        start-with-delim
-        end-with-delim)
+        string-start-end)
 
-    (if (string-equal start-delim end-delim)
-       (save-excursion
-         (beginning-of-line)
-         (while (and (setq end-pos (funcall start-search-func start-delim 
limit t))
-                     (setq start-with-delim (match-beginning 0))
+    (if (and (null start-regexp-flag) (null end-regexp-flag)
+            (string-match "\\`['`\"]+\\'" start-delim)
+            (string-match "\\`['`\"]+\\'" end-delim))
+       ;; This is a string match
+       (setq string-start-end (hypb:in-string-p 2 :range)
+             start (nth 1 string-start-end)
+             end   (nth 2 string-start-end))
+      (save-excursion
+       (beginning-of-line 0) ;; start of previous line
+       (if (string-equal start-delim end-delim)
+           (progn
+             (while (and (setq end-pos (funcall start-search-func start-delim 
limit t))
+                         ;; Prevent infinite loop where regexp match does not
+                         ;; move end-pos forward, e.g. match to bol.
+                         (not (eq first end-pos))
+                         (setq start end-pos)
+                         (setq count (1+ count))
+                         (< (point) opoint)
+                         ;; This is not to find the real end delimiter but to 
find
+                         ;; end delimiters that precede the current argument 
and are
+                         ;; therefore false matches, hence the search is 
limited to
+                         ;; prior to the original point.
+                         (funcall end-search-func end-delim opoint t)
+                         (setq count (1+ count)))
+               (setq first (or first start)
+                     start nil))
+             (when (and (not start) (> count 0) (zerop (% count 2)))
+               ;; Since strings can span lines but this function matches only
+               ;; strings that start on the current line, when start-delim and
+               ;; end-delim are the same and there are an even number of
+               ;; delimiters in the search range, causing the end-delim
+               ;; search to match to what should probably be the start-delim,
+               ;; assume point is within a string and not between two other 
strings.
+               ;; -- RSW, 02-05-2019
+               (setq start (if (string-equal start-delim end-delim)
+                               (point)
+                             first))))
+         ;;
+         ;; Start and end delims are different, so don't have to worry
+         ;; about whether in or outside two of the same delimiters and
+         ;; can match much more simply.
+         ;; Use forward rather than reverse search here to perform greedy
+         ;; searches when optional matches within a regexp.
+         (while (and (<= (point) limit)
+                     (setq end-pos (funcall start-search-func start-delim 
limit t))
                      ;; Prevent infinite loop where regexp match does not
                      ;; move end-pos forward, e.g. match to bol.
-                     (not (eq first end-pos))
-                     (setq start end-pos)
-                     (setq count (1+ count))
-                     (< (point) opoint)
-                     ;; This is not to find the real end delimiter but to find
-                     ;; end delimiters that precede the current argument and 
are
-                     ;; therefore false matches, hence the search is limited to
-                     ;; prior to the original point.
-                     (funcall end-search-func end-delim opoint t)
-                     (setq count (1+ count)))
-           (setq first (or first start)
-                 start nil))
-         (when (and (not start) (> count 0) (zerop (% count 2)))
-           ;; Since strings can span lines but this function matches only
-           ;; strings that start on the current line, when start-delim and
-           ;; end-delim are the same and there are an even number of
-           ;; delimiters in the search range, causing the end-delim
-           ;; search to match to what should probably be the start-delim,
-           ;; assume point is within a string and not between two other 
strings.
-           ;; -- RSW, 02-05-2019
-           (setq start (if (string-equal start-delim end-delim)
-                           (point)
-                         first))))
-      ;;
-      ;; Start and end delims are different, so don't have to worry
-      ;; about whether in or outside two of the same delimiters and
-      ;; can match much more simply.
-      ;; Use forward rather than reverse search here to perform greedy
-      ;; searches when optional matches within a regexp.
-      (save-excursion
-       (beginning-of-line)
-       (while (and (<= (point) limit)
-                   (setq start-pos (point)
-                         end-pos (funcall start-search-func start-delim limit 
t))
-                   ;; Prevent infinite loop where regexp match does not
-                   ;; move end-pos forward, e.g. match to bol.
-                   (not (eq start end-pos)))
-         (setq start-with-delim (match-beginning 0)
-               start (match-end 0))
-         (when (eq start-pos end-pos)
-           ;; start-delim contains a match for bol, so move point
-           ;; forward a char to prevent loop exit even though start
-           ;; delim matched.
-           (goto-char (min (1+ (point)) (point-max)))))))
+                     (not (eq start end-pos)))
+           (setq start (match-end 0))
+           (when (eq start end-pos)
+             ;; start-delim contains a match for bol, so move point
+             ;; forward a char to prevent loop exit even though start
+             ;; delim matched.
+             (goto-char (min (1+ (point)) (point-max)))))))
 
-    (when start
-      (save-excursion
-       (forward-line 2)
-       (setq limit (point))
-       (goto-char opoint)
-       (and (funcall end-search-func end-delim limit t)
-            (setq end (match-beginning 0)
-                  end-with-delim (match-end 0)))))
+      (when start
+       (save-excursion
+         (forward-line 2)
+         (setq limit (point))
+         (goto-char opoint)
+         (and (funcall end-search-func end-delim limit t)
+              (setq end (match-beginning 0))))))
 
     (when (and start end)
       (save-excursion
@@ -234,12 +239,11 @@ button key (no spaces)."
                 (if list-positions-flag
                     (list t start end)
                   t)
-              (let ((result (hargs:buffer-substring start end))
-                    (string-with-delims (when (stringp exclude-regexp)
-                                          (hargs:buffer-substring 
start-with-delim
-                                                                  
end-with-delim))))
-                (unless (and string-with-delims
-                             (string-match exclude-regexp string-with-delims))
+              (let ((result (hargs:buffer-substring start end)))
+                (unless (or
+                         ;; Ignore if more than 2 lines matched
+                         (> (hypb:string-count-matches "\n" result) 1)
+                         (when exclude-regexp (string-match exclude-regexp 
result)))
                   ;; Normalize the result
                   (setq result
                         (if as-key
diff --git a/hypb.el b/hypb.el
index e8a09ceb51..4f741872f8 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:     21-Jun-25 at 13:54:25 by Bob Weiner
+;; Last-Mod:      6-Jul-25 at 14:46:41 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -684,9 +684,9 @@ This will this install the Emacs helm package when needed."
   "Return non-nil iff point is within a string and not on the closing quote.
 
 With optional MAX-LINES, an integer, match only within that many
-lines from point.  With optional RANGE-FLAG, return list
-of (string-matched start-pos end-pos), where the positions
-exclude the delimiters.
+lines from point.  With optional RANGE-FLAG when there is a
+match, return list of (string-matched start-pos end-pos), where
+the positions exclude the delimiters.
 
 To prevent searching back to the buffer start and producing slow
 performance, this limits its count of quotes found prior to point
@@ -703,14 +703,21 @@ Quoting conventions recognized are:
   (save-excursion
     (save-restriction
       (when (integerp max-lines)
-       (narrow-to-region (line-beginning-position)
-                         (line-end-position max-lines)))
+       (if (zerop max-lines)
+           (narrow-to-region (point) (point)) ;; Empty range
+         ;; Allow for +/- (+ 1 max-lines) including current line so start
+         ;; and end delimiters can be on separate lines.  Before returning,
+         ;; this function checks that any matched string has <= max-lines.
+         (narrow-to-region (line-beginning-position
+                            (when max-lines (1+ (- max-lines))))
+                           (line-end-position (1+ max-lines)))))
       ;; Don't use `syntax-ppss' here as it fails to ignore backquoted
       ;; double quote characters in strings and doesn't work in
       ;; `change-log-mode' due to its syntax-table.
       (let ((opoint (point))
            (start (point-min))
            (open-match-string "")
+           str
            str-start
            str-end)
        (cl-destructuring-bind (open-regexp close-regexp)
@@ -747,12 +754,8 @@ Quoting conventions recognized are:
                                            (regexp-quote texinfo-close-quote))
                                    start (point))))
                       (search-forward texinfo-close-quote nil t)
-                      (if range-flag
-                          (progn
-                            (setq str-end (match-beginning 0))
-                            (list (buffer-substring-no-properties str-start 
str-end)
-                                  str-start str-end))
-                        t))
+                      (setq str-end (match-beginning 0)
+                            str (buffer-substring-no-properties str-start 
str-end)))
                (and (cl-oddp (- (count-matches (regexp-quote open-match-string)
                                                start (point))
                                 ;; Subtract any backslash quoted delimiters
@@ -767,12 +770,25 @@ Quoting conventions recognized are:
                         (goto-char (1- (point)))
                       t)
                     (re-search-forward close-regexp nil t)
-                    (if range-flag
-                        (progn
-                          (setq str-end (match-beginning 2))
-                          (list (buffer-substring-no-properties str-start 
str-end)
-                                str-start str-end))
-                      t))))))))))
+                    (setq str-end (match-beginning 2)
+                          str (buffer-substring-no-properties str-start 
str-end))))
+
+             ;; Ignore if more than `max-lines' matched
+             (when (and str
+                        (or (null max-lines)
+                            (and (integerp max-lines)
+                                 ;; When computing the number of lines in
+                                 ;; the string match, ignore any leading and
+                                 ;; trailing newlines.  This allows for
+                                 ;; opening and closing quotes to be on
+                                 ;; separate lines, useful with multi-line
+                                 ;; strings.
+                                 (< (hypb:string-count-matches
+                                     "\n" (string-trim str))
+                                    max-lines))))
+               (if range-flag
+                   (list str str-start str-end)
+                 t)))))))))
 
 (defun hypb:indirect-function (obj)
   "Return the function at the end of OBJ's function chain.
diff --git a/hywiki.el b/hywiki.el
index 460a69820d..1f8aa30206 100644
--- a/hywiki.el
+++ b/hywiki.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    21-Apr-24 at 22:41:13
-;; Last-Mod:     22-Jun-25 at 22:36:22 by Bob Weiner
+;; Last-Mod:      4-Jul-25 at 19:46:06 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -571,8 +571,8 @@ deletion commands and those in 
`hywiki-non-character-commands'."
     (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.
+      ;; Test if at delimiters surrounding a single WikiWord reference
+      ;; 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).
@@ -628,7 +628,7 @@ deletion commands and those in 
`hywiki-non-character-commands'."
        (hywiki--maybe-rehighlight-at-point)))))
 
 (defun hywiki-buttonize-character-commands ()
-  "Turn any HyWikiWords between point into highlighted Hyperbole buttons.
+  "Turn any HyWikiWords around point into highlighted Hyperbole buttons.
 Triggered by `post-self-insert-hook' after self-inserting one or more
 characters after `post-command-hook' has run."
   (unless (hywiki-non-hook-context-p)
@@ -1532,6 +1532,7 @@ publish process."
                          (insert "\n#+INDEX: " wikiword "\n"))))))
 
 (defun hywiki-word-to-org-link (link &optional description)
+  "From a HyWikiWord reference LINK with an optional DESCRIPTION to an Org 
link."
 ;; \"[[file:<hywiki-directory>/WikiWord.org::Multi-Word 
Section][WikiWord#Multi-Word Section]]\".
   (let ((resolved-link (hywiki-org-link-resolve link :full-data)))
     (when (stringp (car resolved-link))
@@ -1700,12 +1701,19 @@ positions of each HyWikiWord and its optional #section."
 
 (defun hywiki-at-range-delimiter ()
   "Immediately before or after a balanced delimiter, return the delimited 
range.
+Include: (), {}, <>, [] and \"\" (double quotes).  Exclude Org links
+and radio targets.
+
+Range is limited to the previous, current and next lines, as HyWikiWord 
references
+are limited to two lines maximum.
+
 If no such range, return \\='(nil nil).
 This includes the delimiters: (), {}, <>, [] and \"\" (double quotes)."
   (save-excursion
     (save-restriction
-      ;; Limit balanced pair checks to the next two lines for speed
-      (narrow-to-region (line-beginning-position) (line-end-position 2))
+      ;; Limit balanced pair checks to previous through next lines for speed
+      ;; Point must be either on the opening or the closing line.
+      (narrow-to-region (line-beginning-position 0) (line-end-position 2))
       (let ((result (condition-case nil
                        (cond
                         ;; Handle opening delimiters
@@ -1761,13 +1769,16 @@ This includes the delimiters: (), {}, <>, [] and \"\" 
(double quotes)."
 Include: (), {}, <>, [] and \"\" (double quotes).  Exclude Org links
 and radio targets.
 
+Range is limited to the previous, current and next lines, as HyWikiWord 
references
+are limited to two lines maximum.
+
 Ignore return value; it has no meaning."
   (save-excursion
     (save-restriction
       (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)))
+       ;; Limit balanced pair checks to two lines around point for speed
+       (narrow-to-region (line-beginning-position 0) (line-end-position 2)))
 
       ;; char-before
       (ignore-errors
@@ -1827,13 +1838,16 @@ Ignore return value; it has no meaning."
 Include: (), {}, <>, [] and \"\" (double quotes).  Exclude Org links
 and radio targets.
 
+Range is limited to the previous, current and next lines, as HyWikiWord
+references are limited to two lines maximum.
+
 Return t if no errors and a pair was found, else nil."
   (save-excursion
     (save-restriction
       (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)))
+       ;; Limit balanced pair checks to two lines around point for speed
+       (narrow-to-region (line-beginning-position 0) (line-end-position 2)))
 
       (let ((result t))
        (condition-case nil
@@ -1989,7 +2003,8 @@ 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
+             ;; May be a non-delimiter but HyWikiWord ending punctuation to
+             ;; skip past
              (skip-chars-backward (hywiki-get-buttonize-characters)))
            ;; Skip past HyWikiWord or section
            (skip-syntax-backward "^-$()<>._\"\'")
@@ -2052,7 +2067,8 @@ the current page unless they have sections attached."
                      (hywiki-maybe-highlight-balanced-pairs))
 
            (unless on-page-name
-             ;; May be a HyWikiWord ending character to skip past
+             ;; May be a non-delimiter but HyWikiWord ending punctuation to
+             ;; skip past
              (skip-chars-backward (hywiki-get-buttonize-characters)
                                   (line-beginning-position)))
            ;; Skip past HyWikiWord or section
@@ -3019,10 +3035,11 @@ non-nil or this will return nil."
                            ;; Handle an Org link [[HyWikiWord]] 
[[hy:HyWikiWord]]
                            ;; or [[HyWikiWord#section][Description Text]].
                            ;; Get the HyWikiWord link reference, ignoring any
-                           ;; description given in the link
+                           ;; 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.
+                           ;; mode just to check for HyWikiWords; however,
+                           ;; ignoring this 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)
@@ -3037,13 +3054,17 @@ non-nil or this will return nil."
                                          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)
+                          ;; Handle a delimited HyWikiWord reference with
+                          ;; multiple, possibly whitespace-separated words in
+                          ;; its section, e.g. (MyWikiWord#one two three).
+                          ;; Whitespace between section words is allowed only
+                          ;; if the delimiters are immediately before and
+                          ;; after a single HyWikiWord reference.
                           ((let ((case-fold-search nil)
                                  (bol (line-beginning-position))
                                  opoint)
-                             ;; May be a HyWikiWord ending character to skip 
past
+                             ;; May be a non-delimiter but HyWikiWord ending
+                             ;; punctuation to skip past
                              (skip-chars-backward 
(hywiki-get-buttonize-characters) bol)
                              (setq opoint (point))
                              (when (setq wikiword-start-end 
(hywiki-delimited-p)) ;; limited to 2 lines
@@ -3110,13 +3131,14 @@ non-nil or this will return nil."
                                          wikiword (string-trim
                                                    
(buffer-substring-no-properties start end))))))))
 
-                          ;; Handle non-delimited HyWikiWord references
-                          ;; with multiple dash-separated words in their 
sections,
+                          ;; Handle a non-delimited HyWikiWord reference
+                          ;; with multiple dash-separated words in its section,
                           ;; 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
+                             ;; May be a non-delimiter but HyWikiWord ending
+                             ;; punctuation to skip past
                              (skip-chars-backward 
(hywiki-get-buttonize-characters) bol)
                              (setq opoint (point))
                              (goto-char opoint)
@@ -3144,9 +3166,10 @@ non-nil or this will return nil."
                                      ;; No following char
                                      wikiword (string-trim 
(match-string-no-properties 0))))))
 
-                          ;; 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
+                          ;; Handle a non-delimited HyWikiWord reference with
+                          ;; optional #section:Lnum:Cnum; if it is an Org
+                          ;; link, it may optionally have a hy: link-type
+                          ;; prefix.  #section may not contain spaces. Ignore
                           ;; wikiwords preceded by any non-whitespace
                           ;; character, except any of these: "([\"'`'"
                           (t (let ((case-fold-search nil))
@@ -3166,11 +3189,10 @@ non-nil or this will return nil."
                                               end   (match-end 0)
                                               ;; No following char
                                               wikiword (string-trim 
(match-string-no-properties 0)))))))))
-                    ;; If `wikiword' has a #section, ensure there are
-                    ;; no invalid chars
+                    ;; If `wikiword' reference has a #section, ensure there are
+                    ;; no invalid chars.  One set of \n\r characters is 
allowed.
                     (if (and (stringp wikiword) (string-match "#" wikiword))
-                        (string-match "#[^][#()<>{}\"\n\r\f]+\\'" wikiword)
-                      t))
+                        (string-match "#[^][#()<>{}\"\f]+\\'" wikiword)        
               t))
                (if range-flag
                    (progn
                      (list wikiword start end))
@@ -3184,9 +3206,9 @@ non-nil or this will return nil."
   "Return list of potential (HyWikiWord#section:Lnum:Cnum start end).
 Also highlight HyWikiWord as necessary.
 
-If the HyWikiWord is delimited, point must be within the delimiters.
-The delimiters are excluded from start and end.  If not at a
-HyWikiWord, return \\='(nil nil nil).
+If the HyWikiWord reference is delimited, point must be within the
+delimiters.  The delimiters are excluded from start and end.  If not
+at a HyWikiWord, return \\='(nil nil nil).
 
 This works regardless of whether the HyWikiWord has been highlighted
 or not.
@@ -3219,22 +3241,29 @@ 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.
-Any non-nil value returned is a list of (string-matched start-pos end-pos).
-The delimited range must be two lines or less.
+  "Return non-nil if optional POS or point is surrounded by delimiters.
+Any non-nil value returned is a list of (hywikiword-ref start-pos end-pos).
+The delimited range must be two lines or less with point on the first line.
+
+Matching delimiters around anything other than a single HyWikiWord reference
+are ignored.
 
 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 2 t)
-       (let ((range (hargs:delimited "[\[<\(\{]" "[\]\}\)\>]" t t t)))
-         (and range
-              ;; Ensure closing delimiter is a match for the opening one
-              (= (matching-paren (char-before (nth 1 range)))
-                 (char-after (nth 2 range)))
-              range)))))
+    (save-restriction
+      (when (natnump pos)
+       (goto-char pos))
+      ;; Limit balanced pair checks to current through next lines for speed.
+      ;; Point must be either on the opening line.
+      (narrow-to-region (line-beginning-position) (line-end-position 2))
+      (or (hypb:in-string-p nil t)
+         (let ((range (hargs:delimited "[\[<\(\{]" "[\]\}\)\>]" t t t)))
+           (and range
+                ;; Ensure closing delimiter is a match for the opening one
+                (= (matching-paren (char-before (nth 1 range)))
+                   (char-after (nth 2 range)))
+                range))))))
 
 (defun hywiki-word-face-at-p (&optional pos)
   "Non-nil if but at point or optional POS has `hywiki-word-face' property."
diff --git a/test/hargs-tests.el b/test/hargs-tests.el
index 6837258a4a..41b93586c9 100644
--- a/test/hargs-tests.el
+++ b/test/hargs-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:    04-Feb-22 at 23:00:00
-;; Last-Mod:      2-Jun-25 at 23:48:30 by Bob Weiner
+;; Last-Mod:      6-Jul-25 at 15:28:45 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -29,15 +29,15 @@
   (let ((file (make-temp-file "hypb")))
     (unwind-protect
         (progn
-          (ert-simulate-keys "xyz\r"
+          (hy-test-helpers:ert-simulate-keys "xyz\r"
             (should (string= (hargs:get "+I: ") "xyz")))
-          (ert-simulate-keys "xyz\r"
+          (hy-test-helpers:ert-simulate-keys "xyz\r"
             (should (string= (hargs:get "+L: ") "xyz")))
-          (ert-simulate-keys (concat "(\"xyz\" \"" file "\")\r")
+          (hy-test-helpers:ert-simulate-keys (concat "(\"xyz\" \"" file 
"\")\r")
             (should (equal (hargs:get "+M: ") (list "xyz" file))))
-          (ert-simulate-keys "xyz\r"
+          (hy-test-helpers:ert-simulate-keys "xyz\r"
             (should (string= (hargs:get "+V: ") "xyz")))
-          (ert-simulate-keys "xyz\r"
+          (hy-test-helpers:ert-simulate-keys "xyz\r"
             (should (string= (hargs:get "+X: ") "(dir)xyz")))
           (should-error (hargs:get "+A: ") :type 'error))
       (hy-delete-file-and-buffer file))))
@@ -67,5 +67,267 @@
       (should (string= (cadr v) (hargs:sexpression-p)))
       (should (string= (caddr v) (hargs:sexpression-p t))))))
 
+;;; Tests for hargs:delimited
+(ert-deftest hargs-delimited-basic-test ()
+  "Test basic functionality with simple delimiters."
+  (with-temp-buffer
+    (insert "Before [hello world] after")
+    (goto-char 10) ; position inside "hello world"
+    (should (string= (hargs:delimited "[" "]") "hello world"))))
+
+(ert-deftest hargs-delimited-regexp-delimiters-test ()
+  "Test with regexp delimiters."
+  (with-temp-buffer
+    (insert "Before (hello world) after")
+    (goto-char 10) ; position inside "hello world"
+    (should (string= (hargs:delimited "[\[<\(\{]" "[\]\}\)\>]" t t) "hello 
world"))))
+
+(ert-deftest hargs-delimited-multiline-point-first-line-test ()
+  "Test multiline expression with point on first line."
+  (with-temp-buffer
+    (insert "Before [hello\nworld] after")
+    (goto-char 10) ; position in "hello" on first line
+    (should (string= (hargs:delimited "[" "]") "hello world"))))
+
+(ert-deftest hargs-delimited-multiline-point-second-line-test ()
+  "Test multiline expression with point on second line."
+  (with-temp-buffer
+    (insert "Before [hello\nworld] after")
+    (goto-char 15) ; position in "world" on second line
+    (should (string= (hargs:delimited "[" "]") "hello world"))))
+
+(ert-deftest hargs-delimited-escaped-delimiter-test ()
+  "Test that escaped delimiters are ignored."
+  (with-temp-buffer
+    (insert "Before \\[not this\\] [hello world] after")
+    (goto-char 28) ; position inside "hello world"
+    (should (string= (hargs:delimited "[" "]") "hello world"))))
+
+(ert-deftest hargs-delimited-matching-delimiters-test ()
+  "Test proper delimiter matching."
+  (with-temp-buffer
+    (insert "Before [hello) world] after")
+    (goto-char 10) ; position inside, but ) doesn't match [
+    (should (string= (hargs:delimited "[" "]") "hello) world"))))
+
+(ert-deftest hargs-delimited-wrong-matching-delimiters-test ()
+  "Test that wrong delimiter pairs don't match."
+  (with-temp-buffer
+    (insert "Before [hello world) after")
+    (goto-char 10) ; position inside, but ) doesn't match [
+    (should-not (hargs:delimited "[" "]" nil nil))))
+
+(ert-deftest hargs-delimited-list-positions-test ()
+  "Test LIST-POSITIONS-FLAG returns list with positions."
+  (with-temp-buffer
+    (insert "Before [hello world] after")
+    (goto-char 10) ; position inside "hello world"
+    (let ((result (hargs:delimited "[" "]" nil nil t)))
+      (should (listp result))
+      (should (string= (car result) "hello world"))
+      (should (= (nth 1 result) 9)) ; position after [
+      (should (= (nth 2 result) 20))))) ; position before ]
+
+(ert-deftest hargs-delimited-exclude-regexp-test ()
+  "Test EXCLUDE-REGEXP parameter."
+  (with-temp-buffer
+    (insert "Before [excluded] after")
+    (goto-char 10) ; position inside "excluded"
+    (should (null (hargs:delimited "[" "]" nil nil nil "excluded")))))
+
+(ert-deftest hargs-delimited-as-key-none-test ()
+  "Test AS-KEY = 'none returns t."
+  (with-temp-buffer
+    (insert "Before [hello world] after")
+    (goto-char 10) ; position inside "hello world"
+    (should (eq (hargs:delimited "[" "]" nil nil nil nil 'none) t))))
+
+(ert-deftest hargs-delimited-as-key-button-test ()
+  "Test AS-KEY non-nil returns button key format."
+  (with-temp-buffer
+    (insert "Before [hello world] after")
+    (goto-char 10) ; position inside "hello world"
+    (should (string= "hello_world" (hargs:delimited
+                                  "[" "]" nil nil nil nil 'button)))))
+
+(ert-deftest hargs-delimited-normalization-test ()
+  "Test string normalization with extra whitespace."
+  (with-temp-buffer
+    (insert "Before [  hello   world  ] after")
+    (goto-char 12) ; position inside
+    (should (string= (hargs:delimited "[" "]") "  hello   world  "))))
+
+(ert-deftest hargs-delimited-multiline-normalization-test ()
+  "Test multiline string normalization."
+  (with-temp-buffer
+    (insert "Before [hello\n   world test] after")
+    (goto-char 10) ; position inside
+    (should (string= (hargs:delimited "[" "]") "hello world test"))))
+
+(ert-deftest hargs-delimited-no-match-test ()
+  "Test when point is not within delimited region."
+  (with-temp-buffer
+    (insert "Before [hello world] after")
+    (goto-char 5) ; position in "Before"
+    (should (null (hargs:delimited "[" "]")))))
+
+(ert-deftest hargs-delimited-no-end-delimiter-test ()
+  "Test when end delimiter is not found."
+  (with-temp-buffer
+    (insert "Before [hello world after")
+    (goto-char 10) ; position inside
+    (should (null (hargs:delimited "[" "]")))))
+
+(ert-deftest hargs-delimited-angle-brackets-test ()
+  "Test with angle brackets."
+  (with-temp-buffer
+    (insert "Before <hello world> after")
+    (goto-char 10) ; position inside
+    (should (string= (hargs:delimited "<" ">") "hello world"))))
+
+(ert-deftest hargs-delimited-curly-braces-test ()
+  "Test with curly braces."
+  (with-temp-buffer
+    (insert "Before {hello world} after")
+    (goto-char 10) ; position inside
+    (should (string= (hargs:delimited "{" "}") "hello world"))))
+
+(ert-deftest hargs-delimited-parentheses-test ()
+  "Test with parentheses."
+  (with-temp-buffer
+    (insert "Before (hello world) after")
+    (goto-char 10) ; position inside
+    (should (string= (hargs:delimited "(" ")") "hello world"))))
+
+(ert-deftest hargs-delimited-double-quotes-basic-test ()
+  "Test basic functionality with double quotes."
+  (with-temp-buffer
+    (insert "Before \"hello world\" after")
+    (goto-char 12) ; position inside "hello world"
+    (should (string= (hargs:delimited "\"" "\"") "hello world"))))
+
+(ert-deftest hargs-delimited-double-quotes-escaped-test ()
+  "Test double quotes with escaped quotes inside."
+  (with-temp-buffer
+    (insert "Before \"hello \\\"quoted\\\" world\" after")
+    (goto-char 12) ; position inside
+    (should (string= (hargs:delimited "\"" "\"") "hello /\"quoted/\" world"))))
+
+(ert-deftest hargs-delimited-double-quotes-multiline-test ()
+  "Test double quotes with multiline content."
+  (with-temp-buffer
+    (insert "Before \"hello\nworld\" after")
+    (goto-char 12) ; position in "hello" on first line
+    (should (string= (hargs:delimited "\"" "\"") "hello world"))))
+
+(ert-deftest hargs-delimited-double-quotes-multiline-second-line-test ()
+  "Test double quotes with point on second line."
+  (with-temp-buffer
+    (insert "Before \"hello\nworld\" after")
+    (goto-char 17) ; position in "world" on second line
+    (should (string= (hargs:delimited "\"" "\"") "hello world"))))
+
+(ert-deftest hargs-delimited-double-quotes-empty-test ()
+  "Test double quotes with empty content."
+  (with-temp-buffer
+    (insert "\"Before \\\"\\\" after\"")
+    (goto-char 9) ; position inside empty quotes
+    (should (string= (hargs:delimited "\"" "\"") "Before /\"/\" after"))))
+
+(ert-deftest hargs-delimited-double-quotes-whitespace-test ()
+  "Test double quotes with only whitespace."
+  (with-temp-buffer
+    (insert "Before \"   \" after")
+    (goto-char 11) ; position inside whitespace
+    (should (string= (hargs:delimited "\"" "\"") "   "))))
+
+(ert-deftest hargs-delimited-double-quotes-no-match-test ()
+  "Test when point is outside quoted region."
+  (with-temp-buffer
+    (insert "Before \"hello world\" after")
+    (goto-char 5) ; position in "Before"
+    (should (null (hargs:delimited "\"" "\"")))))
+
+(ert-deftest hargs-delimited-double-quotes-no-closing-test ()
+  "Test when closing quote is missing."
+  (with-temp-buffer
+    (insert "Before \"hello world after")
+    (goto-char 12) ; position inside
+    (should (null (hargs:delimited "\"" "\"")))))
+
+(ert-deftest hargs-delimited-double-quotes-multiple-pairs-test ()
+  "Test with multiple quote pairs, should match the one containing point."
+  (with-temp-buffer
+    (insert "Before \"first\" and \"second\" after")
+    (goto-char 24) ; position in "second"
+    (should (string= (hargs:delimited "\"" "\"") "second"))))
+
+(ert-deftest hargs-delimited-double-quotes-list-positions-test ()
+  "Test LIST-POSITIONS-FLAG with double quotes."
+  (with-temp-buffer
+    (insert "Before \"hello world\" after")
+    (goto-char 12) ; position inside "hello world"
+    (let ((result (hargs:delimited "\"" "\"" nil nil t)))
+      (should (listp result))
+      (should (string= (car result) "hello world"))
+      (should (= (nth 1 result) 9)) ; position after opening "
+      (should (= (nth 2 result) 20))))) ; position before closing "
+
+(ert-deftest hargs-delimited-double-quotes-as-key-test ()
+  "Test AS-KEY with double quotes."
+  (with-temp-buffer
+    (insert "Before \"hello world\" after")
+    (goto-char 12) ; position inside "hello world"
+    (should (string= (hargs:delimited "\"" "\"" nil nil nil nil 'button) 
"hello_world"))))
+
+;; New tests for complex regex patterns
+(ert-deftest hargs-delimited-complex-regex-test ()
+  "Test with complex regex patterns that caused hanging."
+  (with-temp-buffer
+    (insert "  hello world  ")
+    (goto-char 5) ; position in "hello"
+    (let ((result (hargs:delimited "\\(  \\|[][()<>;&,@]\\)+"
+                                  "\\(  \\|[][()<>;&,@]\\)+"
+                                  t t t)))
+      (should (listp result))
+      (should (stringp (car result)))
+      (should (string= (car result) "hello world")))))
+
+(ert-deftest hargs-delimited-whitespace-boundary-test ()
+  "Test regex that matches whitespace boundaries."
+  (with-temp-buffer
+    (insert "word1 word2 word3")
+    (goto-char 8) ; position in "word2"
+    (let ((result (hargs:delimited "\\s-+" "\\s-+" t t)))
+      (should (stringp result))
+      (should (string= result "word2")))))
+
+(ert-deftest hargs-delimited-punctuation-boundary-test ()
+  "Test regex that matches punctuation boundaries."
+  (with-temp-buffer
+    (insert "word1,word2;word3")
+    (goto-char 8) ; position in "word2"
+    (let ((result (hargs:delimited "[,;]" "[,;]" t t)))
+      (should (stringp result))
+      (should (string= result "word2")))))
+
+(ert-deftest hargs-delimited-line-boundary-test ()
+  "Test regex that matches line boundaries."
+  (with-temp-buffer
+    (insert "line1\nline2\nline3")
+    (goto-char 8) ; position in "line2"
+    (let ((result (hargs:delimited "^" "$" t t)))
+      (should (stringp result))
+      (should (string= result "line2")))))
+
+(ert-deftest hargs-delimited-zero-width-match-test ()
+  "Test handling of zero-width matches."
+  (with-temp-buffer
+    (insert "hello world")
+    (goto-char 5) ; position in "hello"
+    (let ((result (hargs:delimited "\\b" "\\b" t t)))
+      (should (stringp result))
+      (should (string= result "hello")))))
+
 (provide 'hargs-tests)
 ;;; hargs-tests.el ends here
diff --git a/test/hmouse-drv-tests.el b/test/hmouse-drv-tests.el
index ae06828033..a02046dccb 100644
--- a/test/hmouse-drv-tests.el
+++ b/test/hmouse-drv-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:    28-Feb-21 at 22:52:00
-;; Last-Mod:     10-Jun-25 at 17:44:05 by Mats Lidell
+;; Last-Mod:      6-Jul-25 at 13:02:40 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -190,7 +190,7 @@
   (with-temp-buffer
     (insert "\"/tmp\"\n")
     (goto-char 3)
-    (ert-simulate-keys "TMP\r"
+    (hy-test-helpers:ert-simulate-keys "TMP\r"
       (let ((enable-recursive-minibuffers t))
        (hui:ibut-label-create)
        (should (string= "<[TMP]> - \"/tmp\"\n" (buffer-string)))))))
@@ -200,7 +200,7 @@
   (with-temp-buffer
     (insert "<[LBL]>: \"/tmp\"\n")
     (goto-char 14)
-    (ert-simulate-keys "TMP\r"
+    (hy-test-helpers:ert-simulate-keys "TMP\r"
       (condition-case err
           (hui:ibut-label-create)
         (error
diff --git a/test/hmouse-info-tests.el b/test/hmouse-info-tests.el
index 85a2177ea3..1e650a68c4 100644
--- a/test/hmouse-info-tests.el
+++ b/test/hmouse-info-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:    29-Dec-21 at 09:02:00
-;; Last-Mod:     25-Apr-25 at 19:56:35 by Mats Lidell
+;; Last-Mod:      6-Jul-25 at 13:02:40 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -24,7 +24,7 @@
 
 (ert-deftest hmouse-info-read-index-with-completion ()
   "Read a completion that completes."
-  (ert-simulate-keys "(emacs)regex\t\r"
+  (hy-test-helpers:ert-simulate-keys "(emacs)regex\t\r"
     (should (string= "(emacs)regexp" (Info-read-index-item-name "Prompt: ")))))
 
 (ert-deftest hmouse-info-build-completions-no-match ()
diff --git a/test/hpath-tests.el b/test/hpath-tests.el
index 66bf4edd5b..8e7c9da008 100644
--- a/test/hpath-tests.el
+++ b/test/hpath-tests.el
@@ -393,7 +393,7 @@ See `hpath:line-and-column-regexp'."
   (should-not (string-match hpath:line-and-column-regexp "/foo/bar.org:C1")))
 
 (ert-deftest hpath--hpath:delimited-possible-path ()
-  "Verify delimited path is found in an `ls -R' listings in `shell-mode'."
+  "Verify delimited paths are found in an `ls -R' listing in `shell-mode'."
   (let ((files
          '(("file1.ext file2.ext file3.ext"                   ; Space delimited
             ("file1" "file2" "file3"))
diff --git a/test/hui-tests.el b/test/hui-tests.el
index e60280e48a..5b04cbd065 100644
--- a/test/hui-tests.el
+++ b/test/hui-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:    30-Jan-21 at 12:00:00
-;; Last-Mod:     24-Jun-25 at 23:15:42 by Mats Lidell
+;; Last-Mod:      6-Jul-25 at 15:40:32 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -56,7 +56,7 @@
                   (setenv "HOME" "/tmp")
 
                   (set-buffer gbut-file-buffer)
-                  (ert-simulate-keys (kbd create-gbut)
+                  (hy-test-helpers:ert-simulate-keys (kbd create-gbut)
                     (hact (lambda () (call-interactively 'hui:gbut-create))))
 
                   ;; Create using program
@@ -66,7 +66,7 @@
                   (should (eq (hattr:get (hbut:at-p) 'actype) 
'actypes::link-to-file))
 
                   (goto-char (point-max)) ;; Move past button so does not 
prompt with label
-                  (ert-simulate-keys (kbd edit-gbut)
+                  (hy-test-helpers:ert-simulate-keys (kbd edit-gbut)
                     (hact (lambda () (call-interactively 'hui:gbut-edit))))
 
                   ;; (set-buffer gbut-file-buffer)
@@ -149,7 +149,7 @@
   (with-temp-buffer
     (insert "\"/tmp\"\n")
     (goto-char 3)
-    (ert-simulate-keys "TMP\r"
+    (hy-test-helpers:ert-simulate-keys "TMP\r"
       (hui:ibut-label-create)
       (should (string= "<[TMP]> - \"/tmp\"\n" (buffer-string))))))
 
@@ -158,7 +158,7 @@
   (with-temp-buffer
     (insert "<[LBL]>: \"/tmp\"\n")
     (goto-char 14)
-    (ert-simulate-keys "TMP\r"
+    (hy-test-helpers:ert-simulate-keys "TMP\r"
       (condition-case err
           (hui:ibut-label-create)
         (error
@@ -183,7 +183,7 @@
   (let ((file (make-temp-file "hypb_" nil ".txt")))
     (unwind-protect
         (find-file file)
-        (ert-simulate-keys "label\rwww-url\rwww.hypb.org\r"
+        (hy-test-helpers:ert-simulate-keys "label\rwww-url\rwww.hypb.org\r"
           (hui:ebut-create)
           (hy-test-helpers-verify-hattr-at-p :actype 'actypes::www-url :args 
'("www.hypb.org") :loc file :lbl-key "label"))
       (hy-delete-file-and-buffer file))))
@@ -194,10 +194,10 @@ Ensure modifying the button but keeping the label does 
not create a double label
   (let ((file (make-temp-file "hypb_" nil ".txt")))
     (unwind-protect
         (find-file file)
-        (ert-simulate-keys "label\rwww-url\rwww.hypb.org\r"
+        (hy-test-helpers:ert-simulate-keys "label\rwww-url\rwww.hypb.org\r"
           (hui:ebut-create)
           (hy-test-helpers-verify-hattr-at-p :actype 'actypes::www-url :args 
'("www.hypb.org") :loc file :lbl-key "label"))
-        (ert-simulate-keys "\r\r\r\r"
+        (hy-test-helpers:ert-simulate-keys "\r\r\r\r"
           (hui:ebut-edit "label")
           (hy-test-helpers-verify-hattr-at-p :actype 'actypes::www-url :args 
'("www.hypb.org") :loc file :lbl-key "label")
           (should (string= "<(label)>" (buffer-string)))))
@@ -628,7 +628,7 @@ Ensure modifying the button but keeping the label does not 
create a double label
     (unwind-protect
         (progn
           (find-file file)
-         (ert-simulate-keys "ibut\rlink-to-rfc\r123\r"
+         (hy-test-helpers:ert-simulate-keys "ibut\rlink-to-rfc\r123\r"
            (hact (lambda () (call-interactively 'hui:ibut-create))))
           (should (string= "<[ibut]> - rfc123" (buffer-string))))
       (hy-delete-file-and-buffer file))))
@@ -642,7 +642,7 @@ Ensure modifying the button but keeping the label does not 
create a double label
           (insert "ibut")
           (set-mark (point-min))
           (goto-char (point-max))
-         (ert-simulate-keys "\rlink-to-rfc\r123\r"
+         (hy-test-helpers:ert-simulate-keys "\rlink-to-rfc\r123\r"
            (hact (lambda () (call-interactively 'hui:ibut-create))))
           (should (string= "<[ibut]> - rfc123" (buffer-string))))
       (hy-delete-file-and-buffer file))))
@@ -655,7 +655,7 @@ Ensure modifying the button but keeping the label does not 
create a double label
         (progn
           (find-file file)
           (insert "(sexp)")
-         (ert-simulate-keys "ibut\rlink-to-rfc\r123\r"
+         (hy-test-helpers:ert-simulate-keys "ibut\rlink-to-rfc\r123\r"
            (hact (lambda () (call-interactively 'hui:ibut-create))))
           (should (string= "(sexp); <[ibut]> - rfc123" (buffer-string))))
       (hy-delete-file-and-buffer file))))
@@ -668,7 +668,7 @@ Ensure modifying the button but keeping the label does not 
create a double label
           (find-file file)
           (insert "\"/tmp\"")
           (goto-char 3)
-         (ert-simulate-keys "label\r"
+         (hy-test-helpers:ert-simulate-keys "label\r"
            (hact (lambda () (call-interactively 'hui:ibut-label-create))))
           (should (string= "<[label]> - \"/tmp\"" (buffer-string))))
       (hy-delete-file-and-buffer file))))
@@ -682,7 +682,7 @@ With point on label suggest that ibut for rename."
           (find-file file)
           (insert "<[label]> - rfc123")
           (goto-char 3)
-         (ert-simulate-keys (kbd "M-DEL renamed RET")
+         (hy-test-helpers:ert-simulate-keys (kbd "M-DEL renamed RET")
            (hact (lambda () (call-interactively 'hui:ibut-rename))))
           (should (string= "<[renamed]> - rfc123" (buffer-string))))
       (hy-delete-file-and-buffer file))))
@@ -695,7 +695,7 @@ With point on label suggest that ibut for rename."
           (find-file file)
           (insert "<[label]> - rfc123")
           (goto-char (point-max))
-         (ert-simulate-keys (kbd "label RET M-DEL renamed RET")
+         (hy-test-helpers:ert-simulate-keys (kbd "label RET M-DEL renamed RET")
            (hact (lambda () (call-interactively 'hui:ibut-rename))))
           (should (string= "<[renamed]> - rfc123" (buffer-string))))
       (hy-delete-file-and-buffer file))))
@@ -708,7 +708,7 @@ With point on label suggest that ibut for rename."
           (find-file file)
           (insert "<[label]> - rfc123")
           (goto-char (point-max))
-          (ert-simulate-keys "\r"
+          (hy-test-helpers:ert-simulate-keys "\r"
            (should-error (hui:ibut-rename "notalabel") :type 'error)))
       (hy-delete-file-and-buffer file))))
 
@@ -828,7 +828,7 @@ With point on label suggest that ibut for rename."
           (goto-char (point-max))
           (split-window)
           (find-file filea)
-          (ert-simulate-keys "label\r"
+          (hy-test-helpers:ert-simulate-keys "label\r"
             (hui:ibut-link-directly (get-buffer-window) (get-buffer-window 
(get-file-buffer fileb)) 4))
           (should (string= (buffer-string) (concat "<[label]> - " "\""
                                       (file-name-nondirectory fileb)
@@ -917,7 +917,7 @@ With point on label suggest that ibut for rename."
           (goto-char (point-max))
           (split-window)
           (find-file filea)
-          (ert-simulate-keys "button\r"
+          (hy-test-helpers:ert-simulate-keys "button\r"
             (hui:ebut-link-directly (get-buffer-window)
                                     (get-buffer-window (get-file-buffer 
fileb)))
             (should (string= (buffer-string) "<(button)>"))
@@ -946,7 +946,7 @@ With point on label suggest that ibut for rename."
            (goto-char (1- (point))))
           (split-window)
           (find-file file)
-          (ert-simulate-keys "button\r"
+          (hy-test-helpers:ert-simulate-keys "button\r"
             (hui:ebut-link-directly (get-buffer-window) (get-buffer-window 
dir-buf))
            ;; Implicit link should be the `dir' dired directory,
            ;; possibly minus the final directory '/'.
@@ -979,7 +979,7 @@ With point on label suggest that ibut for rename."
         (mocklet ((gbut:file => global-but-file))
           (delete-other-windows)
           (find-file file)
-          (ert-simulate-keys "button\r"
+          (hy-test-helpers:ert-simulate-keys "button\r"
             (hui:gbut-link-directly t)
             (with-current-buffer (find-buffer-visiting global-but-file)
               (should (string= (buffer-string)
@@ -998,7 +998,7 @@ With point on label suggest that ibut for rename."
         (mocklet ((gbut:file => global-but-file))
           (delete-other-windows)
           (find-file file)
-          (ert-simulate-keys "button\r"
+          (hy-test-helpers:ert-simulate-keys "button\r"
             (hui:gbut-link-directly)
             (with-current-buffer (find-buffer-visiting global-but-file)
               (should (string= (buffer-string) "First\n<(button)>\n"))
diff --git a/test/hy-test-helpers.el b/test/hy-test-helpers.el
index 738e3aa34d..54c5a1f7aa 100644
--- a/test/hy-test-helpers.el
+++ b/test/hy-test-helpers.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:    30-Jan-21 at 12:00:00
-;; Last-Mod:     24-Jun-25 at 10:21:13 by Mats Lidell
+;; Last-Mod:      6-Jul-25 at 15:40:23 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -35,6 +35,18 @@
     (should (= (length possible-types) 1))
     (should (equal first-type type))))
 
+(defmacro hy-test-helpers:ert-simulate-keys (keys &rest body)
+  "Execute BODY with KEYS as pseudo-interactive input.
+Disable `vertico-mode' which can get in the way of standard key
+processing."
+  (declare (debug t) (indent 1))
+  `(if (bound-and-true-p vertico-mode)
+       (unwind-protect
+          (progn (vertico-mode 0)
+                 (ert-simulate-keys ,keys ,@body))
+        (vertico-mode 1))
+     (ert-simulate-keys ,keys ,@body)))
+
 (defun hy-test-helpers:should-last-message (msg captured)
   "Verify MSG is in CAPTURED text."
   (should (string-search msg captured)))
diff --git a/test/hypb-tests.el b/test/hypb-tests.el
index 37c86f9ff2..4a628a61e3 100644
--- a/test/hypb-tests.el
+++ b/test/hypb-tests.el
@@ -3,7 +3,7 @@
 ;; Author:       Mats Lidell <ma...@gnu.org>
 ;;
 ;; Orig-Date:     5-Apr-21 at 18:53:10
-;; Last-Mod:     27-May-25 at 22:01:13 by Bob Weiner
+;; Last-Mod:      6-Jul-25 at 14:49:57 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -115,14 +115,15 @@ See Emacs bug#74042 related to usage of texi2any."
     (goto-line 1) (move-to-column 1)
     ;; First line. Line starts with quote.
     (should-not (hypb:in-string-p 1))
-    (should-not (hypb:in-string-p 2))
+    (should (hypb:in-string-p 2))
     (should (hypb:in-string-p 3))
     (should (hypb:in-string-p 99))
 
     ;; Second line. No quote on the line.
     (goto-line 2)
-    (dotimes (l 5)
-      (should-not (hypb:in-string-p l)))))
+    (should-not (hypb:in-string-p 1))
+    (should (hypb:in-string-p 2))
+    (should (hypb:in-string-p 3))))
 
 ;; This file can't be byte-compiled without the `el-mock' package (because of
 ;; the use of the `with-mock' macro), which is not a dependency of Hyperbole.
diff --git a/test/hywiki-tests.el b/test/hywiki-tests.el
index 56f4527bc0..ef8299be88 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:     24-Jun-25 at 09:36:49 by Mats Lidell
+;; Last-Mod:      6-Jul-25 at 15:39:40 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -902,9 +902,9 @@ Note special meaning of `hywiki-allow-plurals-flag'."
     (unwind-protect
         (progn
           (find-file file)
-          (ert-simulate-keys "\r"
+          (hy-test-helpers:ert-simulate-keys "\r"
             (should-error (hywiki-add-bookmark "")))
-          (ert-simulate-keys "WikiWord\r"
+          (hy-test-helpers:ert-simulate-keys "WikiWord\r"
             (hywiki-add-bookmark "WikiWord")
             (should (equal '(bookmark . "WikiWord")
                           (hywiki-get-referent "WikiWord")))))
@@ -916,7 +916,7 @@ Note special meaning of `hywiki-allow-plurals-flag'."
   (let ((hywiki-directory (make-temp-file "hywiki" t))
        (wikiword "WikiWord"))
     (unwind-protect
-       (ert-simulate-keys "hpath:find\r"
+       (hy-test-helpers:ert-simulate-keys "hpath:find\r"
          (hywiki-add-command wikiword)
          (should (equal '(command . hpath:find)
                         (hywiki-get-referent wikiword))))
@@ -954,7 +954,7 @@ Note special meaning of `hywiki-allow-plurals-flag'."
   "Verify `hywiki-add-info-index'."
   (let ((hywiki-directory (make-temp-file "hywiki" t)))
     (unwind-protect
-        (ert-simulate-keys "files\r"
+        (hy-test-helpers:ert-simulate-keys "files\r"
           (info "emacs")
          (hywiki-add-info-index "WikiWord")
          (should (equal '(info-index . "(emacs)files") (hywiki-get-referent 
"WikiWord"))))
@@ -964,7 +964,7 @@ Note special meaning of `hywiki-allow-plurals-flag'."
   "Verify `hywiki-add-info-node'."
   (let ((hywiki-directory (make-temp-file "hywiki" t)))
     (unwind-protect
-       (ert-simulate-keys "(emacs)\r"
+       (hy-test-helpers:ert-simulate-keys "(emacs)\r"
          (hywiki-add-info-node "WikiWord")
          (should (equal '(info-node . "(emacs)") (hywiki-get-referent 
"WikiWord"))))
       (hy-delete-dir-and-buffer hywiki-directory))))
@@ -974,10 +974,10 @@ Note special meaning of `hywiki-allow-plurals-flag'."
   (let ((hywiki-directory (make-temp-file "hywiki" t)))
     (unwind-protect
        (progn
-         (ert-simulate-keys "ABC\r"
+         (hy-test-helpers:ert-simulate-keys "ABC\r"
            (hywiki-add-key-series "WikiWord")
            (should (equal '(key-series . "{ABC}") (hywiki-get-referent 
"WikiWord"))))
-         (ert-simulate-keys "{ABC}\r"
+         (hy-test-helpers:ert-simulate-keys "{ABC}\r"
            (hywiki-add-key-series "WikiWord")
            (should (equal '(key-series . "{ABC}") (hywiki-get-referent 
"WikiWord")))))
       (hy-delete-dir-and-buffer hywiki-directory))))
@@ -1081,7 +1081,7 @@ up the test."
   "Verify saving and loading a referent keyseries works ."
   (hywiki-tests--referent-test
    (cons 'key-series "{ABC}")
-   (ert-simulate-keys "ABC\r"
+   (hy-test-helpers:ert-simulate-keys "ABC\r"
      (hywiki-add-key-series wiki-referent))))
 
 (ert-deftest hywiki-tests--save-referent-keyseries-use-menu ()
@@ -1114,7 +1114,7 @@ up the test."
   "Verify saving and loading a referent bookmark works."
   (hywiki-tests--referent-test
    (cons 'bookmark wiki-referent)
-   (ert-simulate-keys (concat wiki-referent "\r")
+   (hy-test-helpers:ert-simulate-keys (concat wiki-referent "\r")
      (hywiki-add-bookmark wiki-referent))))
 
 ;; Command
@@ -1127,7 +1127,7 @@ up the test."
   "Verify saving and loading a referent command works."
   (hywiki-tests--referent-test
     (cons 'command #'hywiki-tests--command)
-    (ert-simulate-keys "hywiki-tests--command\r"
+    (hy-test-helpers:ert-simulate-keys "hywiki-tests--command\r"
       (hywiki-add-command wiki-referent))))
 
 (ert-deftest hywiki-tests--save-referent-command-use-menu ()
@@ -1196,7 +1196,7 @@ up the test."
   (hywiki-tests--referent-test
    (cons 'info-index "(emacs)files")
    (save-excursion
-     (ert-simulate-keys "files\r"
+     (hy-test-helpers:ert-simulate-keys "files\r"
        (info "emacs")
        (hywiki-add-info-index wiki-referent)))))
 
@@ -1219,7 +1219,7 @@ up the test."
    (cons 'info-node "(emacs)")
    (save-excursion
      (unwind-protect
-         (ert-simulate-keys "(emacs)\r"
+         (hy-test-helpers:ert-simulate-keys "(emacs)\r"
            (hywiki-add-info-node wiki-referent))
        (kill-buffer "*info*")))))
 

Reply via email to