From 8033791910cc4a925349af615a5795b7c6f691d9 Mon Sep 17 00:00:00 2001 From: bw Date: Wed, 22 Jul 2026 23:31:33 -0400 Subject: [PATCH 1/4] hydef - Add for HyWiki glossary entry Action Button use hpath:to-markup-anchor - Allow for Org emphasis characters in org-file#section references. hywiki-get-term-variant-regexp - Fix to be case-sensitive and always split WikiWords on capital letters only. hywiki-get-entry - Obey `regexp-flag' when calling `hyrolo-grep-file'. --- ChangeLog | 15 ++++ hpath.el | 15 +++- hyperbole.el | 19 ++-- hywiki.el | 220 +++++++++++++++++++++++++++------------------ man/hyperbole.texi | 53 ++++++++--- 5 files changed, 211 insertions(+), 111 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6f10d353..2f600d87 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2026-07-22 Bob Weiner + +* man/hyperbole.texi (HyWiki Menu, HyWiki Glossary): Document the ways + to use HyWiki glossary entries. + +* hywiki.el (hywiki-get-term-variant-regexp): Allow the term to be + surrounded by Org emphasis characters. + (hywiki-get-term-variant-regexp): Fix to make case sensitive + so wikiwords are always split on capital letters properly. + hpath.el (hpath:org-normalize-title): Strip any Org emphasis characters. + (hywiki-get-entry): Obey 'regexp-flag' when calling + 'hyrolo-grep-file'. + (hydef): Add macro to use as an Action Button to display HyWiki + glossary definitions. + 2026-07-21 Bob Weiner * hywiki.el (hywiki-get-entry): Fix return of display-buffer string diff --git a/hpath.el b/hpath.el index 399f2f62..a22b5121 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: 16-Jul-26 at 16:57:49 by Bob Weiner +;; Last-Mod: 22-Jul-26 at 15:13:47 by Bob Weiner ;; ;; SPDX-License-Identifier: GPL-3.0-or-later ;; @@ -1754,7 +1754,9 @@ but locational suffixes within the file are utilized." "Ignore HASH when ANCHOR is non-null and move point to ANCHOR string if found. Move point to beginning of buffer if HASH is non-nil and ANCHOR is null. With optional INSTANCE-NUM, go to that instance of ANCHOR from the start -of the buffer." +of the buffer. + +Trigger an error if the instance of the non-null anchor requested is not found." (let ((omin (point-min)) (omax (point-max))) (unwind-protect @@ -2026,7 +2028,8 @@ form is what is returned for PATH." (defun hpath:org-normalize-title (title) "Return title in normalized form. -Strip all priority, leading ':' or '-' separators, and stats from TITLE." +Strip all priority, leading ':' or '-' separators, stats and Org emphasis +characters from TITLE." (when title (let ((clean (copy-sequence title))) ;; Strip leading priority: [#B] or [#2} followed by ':' or '-' surrounded by any whitespace @@ -2035,7 +2038,11 @@ Strip all priority, leading ':' or '-' separators, and stats from TITLE." ;; Matches: "- Title", ": Title", " - Title" (setq clean (string-trim (replace-regexp-in-string "\\`[ \t]*[-:][ \t]+" "" clean))) ;; Strip trailing statistics cookies [1/2] or [50%] - (setq clean (replace-regexp-in-string "\\(?: +\\[[0-9%+/]+\\]\\)+\\'" "" clean))))) + (setq clean (replace-regexp-in-string "\\(?: +\\[[0-9%+/]+\\]\\)+\\'" "" clean)) + ;; Strip *bold*’, ‘/italic/’, ‘_underlined_’, ‘=verbatim=’ and ‘~code~’ + ;; Org emphasis characters + (setq clean (replace-regexp-in-string "\\`[ \t]*[*/_=~]\\(.+\\)[*/_=~]" + "\\1" clean))))) (defun hpath:org-normalize-titles () "Get all buffer Org titles in normalized form. diff --git a/hyperbole.el b/hyperbole.el index 92343f9d..9a3cee20 100644 --- a/hyperbole.el +++ b/hyperbole.el @@ -9,7 +9,7 @@ ;; Maintainer: Robert Weiner ;; Maintainers: Robert Weiner , Mats Lidell ;; Created: 06-Oct-92 at 11:52:51 -;; Last-Mod: 14-Jul-26 at 10:01:48 by Bob Weiner +;; Last-Mod: 22-Jul-26 at 11:15:05 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 @@ -354,20 +354,21 @@ of the commands." ;; f = SELECTED_FRAME (); ;; XSETFRAME (lispy_dummy, f); ;; -;; It seems like the XSETFRAME macro is not properly copying the value of f on initial frame selection under the macOS window system. -;; The problem occurs on other systems as well, e.g. Emacs 25.2 under Windows 7. +;; It seems like the XSETFRAME macro is not properly copying the value of f +;; on initial frame selection under the macOS window system. The problem +;; occurs on other systems as well, e.g. Emacs 25.2 under Windows 7. ;; ;; Hyperbole resolves this problem by setting the ;; `mouse-position-function' variable below to properly set the ;; newly selected frame. -(if (boundp 'mouse-position-function) - (setq mouse-position-function - (lambda (frame-x-dot-y) - "Make `mouse-position' and `mouse-pixel-position' return the selected frame. +(when (boundp 'mouse-position-function) + (setq mouse-position-function + (lambda (frame-x-dot-y) + "Make `mouse-position' and `mouse-pixel-position' return the selected frame. Under macOS and Windows 7 at least, upon initial selection of a new frame, those functions by default still return the prior frame." - (if (consp frame-x-dot-y) (setcar frame-x-dot-y (selected-frame))) - frame-x-dot-y))) + (if (consp frame-x-dot-y) (setcar frame-x-dot-y (selected-frame))) + frame-x-dot-y))) ;; hmouse-drv will load hui-mouse and hmouse-key (mapc #'require '(hsettings hmouse-drv hmouse-sh)) diff --git a/hywiki.el b/hywiki.el index ac2cd9cb..0fcf1a3b 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: 21-Jul-26 at 01:46:11 by Bob Weiner +;; Last-Mod: 22-Jul-26 at 23:17:56 by Bob Weiner ;; ;; SPDX-License-Identifier: GPL-3.0-or-later ;; @@ -1449,7 +1449,7 @@ calling this function." (gbut:act gbut-name)) (defun hywiki-add-glossary-entry (term) - "Add TERM as a new HyWiki glossary entry to be defined." + "Add/edit TERM as a HyWiki glossary entry with a definition." (let ((glossary (hywiki-get-glossary-file)) (hyrolo-date-format "")) ;; don't add a date (if (= 1 (hyrolo-grep (hywiki-get-term-variant-regexp term) @@ -2413,8 +2413,12 @@ therein is invalid, trigger an error." (defun hywiki-get-term-variant-regexp (term) "Return a grouped regexp of the allowed glossary variants for TERM string." - (let (str) - (format "\\(%s\\|%s\\|%s\\|%s\\)" + ;; Allow for term downcased, and/or with spaces between capitalized words + ;; or the whole term capitalized. Also allow the term to be surrounded by + ;; Org emphasis characters. + (let ((str) + (case-fold-search nil)) + (format "[*/_=~]?\\(%s\\|%s\\|%s\\|%s\\)[*/_=~]?" (regexp-quote term) (regexp-quote (downcase term)) (regexp-quote (setq str (hywiki-wikiword-to-string term " "))) @@ -2428,7 +2432,7 @@ Return nil if no match is found. If called interactively or with optional DISPLAY-FLAG non-nil, display a buffer with TERM's definition but don't return it. Get definition from HyWiki's Glossary.org or optional FILE. If the file is not readable or no -matching TERM entry is found, return nil. +matching TERM entry is found, return nil; othewise, return t. If the `consult' package is installed, interactively select and complete the entry to be inserted. @@ -2451,32 +2455,44 @@ top-level headlines are searched. (when (or (not (stringp term)) (string-empty-p term)) (error "(hywiki-get-definition): Invalid `term': `%s'" term)) (let ((glossary (hywiki-get-glossary-file file)) - (term-regexp (hywiki-get-term-variant-regexp term)) - entry) - (setq entry - (cond ((cl-find ?# term) - ;; WikiWord#section or #section - (hywiki-get-entry term-regexp display-flag nil t)) - ((or (hywiki-word-is-p term t) (null file)) - ;; Is a WikiWord or phrase only; match to any of several - ;; forms: WikiWord, wikiword, Wiki Word, wiki word - (when (file-readable-p glossary) - (hywiki-get-entry (concat (if file "" "Glossary#") term-regexp) - display-flag file t))) - (t - (cond ((or (not (stringp file)) (string-empty-p file)) - (error "(hywiki-get-definition): \"%s\" is invalid" file)) - (t - ;; phrase with a file to search - (hywiki-get-entry term-regexp display-flag file t)))))) + entry + index + term-regexp + wikiword) + (cond ((setq index (seq-position term ?#)) + ;; WikiWord#section or #section + (setq wikiword (substring term 0 index) + term (substring term (1+ index)) + term-regexp (hywiki-get-term-variant-regexp term) + file (if (zerop index) + buffer-file-name + (hywiki-get-page-file wikiword)))) + ((or (hywiki-word-is-p term t) (null file)) + ;; Is a WikiWord or phrase only; match to any of several + ;; forms: WikiWord, wikiword, Wiki Word, wiki word -- in + ;; file when given or the Glossary file when not + (when (file-readable-p glossary) + (setq term-regexp (hywiki-get-term-variant-regexp term)) + (unless (and (stringp file) (not (string-empty-p file))) + (setq file glossary)))) + (t + ;; `file' is non-null so try to use that or trigger and error + (when (or (not (stringp file)) (string-empty-p file) + (not (file-readable-p file))) + (error "(hywiki-get-definition): \"%s\" is invalid" file)) + (setq term-regexp (hywiki-get-term-variant-regexp term)))) + + ;; Return and possibly display matching definition + (setq entry (hywiki-get-entry term-regexp display-flag file t)) + (when (stringp entry) ;; Remove * or # prefix from def entry before returning, so can be ;; embedded in other doc (setq entry (substring entry (if (string-match "\\`[*#]+[ \t\n\f]*" entry) (match-end 0) - 0))) - (if display-flag t entry)))) + 0)))) + entry)) (defun hywiki-get-delimited-region () "Immediately before or after a balanced delimiter, return the delimited range. @@ -2529,11 +2545,13 @@ This includes the delimiters: (), {}, <>, [] and \"\" (double quotes)." Return nil if no match is found. If called interactively or with optional DISPLAY-FLAG non-nil, display a -buffer with REFERENCE's definition but don't return it. Get definition from -HyWiki's Glossary.org, optional FILE, or the current buffer for #in-file -references. If the file is not readable or no matching REFERENCE entry is -found, return nil. With optional prefix arg, REGEXP-FLAG, treat REFERENCE -as a regular expression instead of a string. +buffer with REFERENCE's definition but don't return it. If the file is not +readable or no matching REFERENCE entry is found, return nil; othewise, +return t. + +Get definition from HyWiki's Glossary.org, optional FILE, or the current +buffer for #in-file references. With optional prefix arg, REGEXP-FLAG, +treat REFERENCE as a regular expression instead of a string. If the `consult' package is installed, interactively select and complete the entry to be inserted. @@ -2556,7 +2574,7 @@ top-level headlines are searched. (when (or (null reference) (not (stringp reference))) (error "(hywiki-get-entry): Invalid reference: `%s'" reference)) - (let ((buf (current-buffer)) + (let ((hyrolo-display-buffer hywiki-glossary-display-buffer) (buf-file buffer-file-name) (found 0) (word-end (hywiki-word-is-p reference t)) @@ -2566,70 +2584,96 @@ top-level headlines are searched. path-list) (save-window-excursion (with-current-buffer (get-buffer-create hywiki-glossary-display-buffer) - (let ((hyrolo-display-buffer hywiki-glossary-display-buffer)) - ;; (hyrolo--cache-initialize) - (cond ((or consult-flag - (not (string-match-p "#" reference)) - (not word-end)) - (setq phrase "" - entry-to-match reference)) - (word-end - (setq phrase (string-trim (substring reference 0 word-end)) - entry-to-match (unless (= word-end (length reference)) - (string-trim (substring reference (1+ word-end))))))) - ;; If path-list remains nil, then search will be across the whole wiki - (cond ((stringp file) - ;; explicit `file' given - (setq path-list (list (expand-file-name file hywiki-directory)))) - ((and (not consult-flag) (string-match-p "\\`#" reference)) - ;; in-file reference - (setq entry-to-match (substring reference 1) - path-list (if buf-file - (list buf-file) - (user-error "(hywiki-get-entry): #section not allowed in non-file buffer: reference = %s; buffer = %S" - reference buf)))) - ((not (string-empty-p phrase)) - ;; The phrase is a WikiWord; use this as the file to search - (setq path-list (list (expand-file-name - (concat phrase - (unless (string-suffix-p hywiki-file-suffix phrase) - hywiki-file-suffix)) - hywiki-directory))))) - - (unless entry-to-match - (error "(hywiki-get-entry): No `entry-to-match' derivable from \"%s\"" - reference)) - - (save-excursion - (setq found - (if (and consult-flag - (or path-list - ;; Extract `name' from the line-numbered - ;; `consult-grep' match results - (string-match "\\([^ \t\n\r\"'`]*[^ \t\n\r:\"'`0-9]\\): ?\\([1-9][0-9]*\\)[ :]" - reference))) - (hyrolo-grep-file (if path-list (car path-list) (match-string-no-properties 1 reference)) - (regexp-quote (if path-list - entry-to-match - (substring reference (match-end 0)))) - -1 nil t) - (hyrolo-grep (if regexp-flag entry-to-match (regexp-quote entry-to-match)) - -1 - (hyrolo-expand-path-list (or path-list (list hywiki-directory))) - nil t (not display-flag)))))))) + (setq hyrolo-display-buffer hywiki-glossary-display-buffer) + ;; (hyrolo--cache-initialize) + (cond ((or consult-flag + (not (string-match-p "#" reference)) + (not word-end)) + (setq phrase "" + entry-to-match reference)) + (word-end + (setq phrase (string-trim (substring reference 0 word-end)) + entry-to-match (unless (= word-end (length reference)) + (string-trim (substring reference (1+ word-end))))))) + ;; If path-list remains nil, then search will be across the whole wiki + (cond ((stringp file) + ;; explicit `file' given + (setq path-list (list (expand-file-name file hywiki-directory)))) + ((and (not consult-flag) (string-match-p "\\`#" reference)) + ;; in-file reference + (setq entry-to-match (substring reference 1) + path-list (if buf-file + (list buf-file) + (user-error "(hywiki-get-entry): #section not allowed in non-file buffer: reference = %s; buffer = %S" + reference (get-buffer buf-file))))) + ((not (string-empty-p phrase)) + ;; The phrase is a WikiWord; use this as the file to search + (setq path-list (list (expand-file-name + (concat phrase + (unless (string-suffix-p hywiki-file-suffix phrase) + hywiki-file-suffix)) + hywiki-directory))))) + + (unless entry-to-match + (error "(hywiki-get-entry): No `entry-to-match' derivable from \"%s\"" + reference)) + + (save-excursion + (setq found + (if (and consult-flag + (or path-list + ;; Extract `name' from the line-numbered + ;; `consult-grep' match results + (string-match "\\([^ \t\n\r\"'`]*[^ \t\n\r:\"'`0-9]\\): ?\\([1-9][0-9]*\\)[ :]" + reference))) + (hyrolo-grep-file (if path-list (car path-list) (match-string-no-properties 1 reference)) + (funcall (if regexp-flag #'identity #'regexp-quote) + (if path-list + entry-to-match + (substring reference (match-end 0)))) + -1 nil t) + (hyrolo-grep (if regexp-flag entry-to-match (regexp-quote entry-to-match)) + -1 + (hyrolo-expand-path-list (or path-list (list hywiki-directory))) + nil t (not display-flag))))))) (if display-flag - (progn + (if (zerop found) + (progn (beep) + (message "(hywiki-get-entry): No match for `%s' found in `%s'" + reference + (or path-list hywiki-directory)) + nil) + ;; Display even if no entries are found (hyrolo-display-matches) ;; skip past header to the entry - (unless (zerop found) - (hyrolo-to-next-entry))) + (hyrolo-to-next-entry) + t) (unless (zerop found) (with-current-buffer hyrolo-display-buffer (buffer-string)))))) +;;;###autoload +(defmacro hydef (&rest term) + "Display TERM's definition, which may be given as multiple strings or symbols. +All of the following represent the same TERM: ActionKey, \"ActionKey\", +Action Key, action key, and \"action key\", i.e. (hydef action key). + +Use this as a Hyperbole Action Button to hyperlink to an individual HyWiki +definition from ${hywiki-directory}/Glossary.org), i.e. " + `(let ((term-str (mapconcat (lambda (word) + (cond ((symbolp word) (symbol-name word)) + ((stringp word) word) + (t (format "%s" word)))) + ',term " "))) + (when (or (null term-str) (member term-str '("" "t" "nil"))) + (error "(hydef): No term given; must give a term to lookup the definition")) + (hywiki-get-definition term-str t))) + (defun hywiki-get-glossary-file (&optional file) "Return the glossary file for the current HyWiki." - (expand-file-name (or file (concat "Glossary" hywiki-file-suffix)) + (expand-file-name (if (and (stringp file) (not (string-empty-p file))) + file + (concat "Glossary" hywiki-file-suffix)) hywiki-directory)) (defun hywiki-get-glossary-terms () @@ -3881,8 +3925,8 @@ When NO-STATS is non-nil, don't include statistics in square brackets." "\\(?:[ \t]*\\(\\[#.\\]\\)\\)?" ;; title and optional stats "\\(?:[ \t]*\\(%s\\)\\)") - ;; exact title - (regexp-quote title))) + ;; exact title in diff formats + (hywiki-get-term-variant-regexp title))) (defun hywiki-org-get-publish-project () "Return the HyWiki Org publish project, a named set of properties. diff --git a/man/hyperbole.texi b/man/hyperbole.texi index 8ba6bd47..fa438594 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: 20-Jul-26 at 01:29:18 by Bob Weiner +@c Last-Mod: 22-Jul-26 at 23:25:37 by Bob Weiner @c %**start of header (This is for running Texinfo on a region.) @setfilename hyperbole.info @@ -30,7 +30,7 @@ @set txicodequoteundirected @set txicodequotebacktick -@set UPDATED July 20, 2026 +@set UPDATED July 22, 2026 @set UPDATED-MONTH July 2026 @set EDITION 9.0.2pre @set VERSION 9.0.2pre @@ -171,7 +171,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 Edition 9.0.2pre
-Printed July 20, 2026.
+Printed July 22, 2026.
 
   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
-July 20, 2026 @c AUTO-REPLACE-ON-SAVE
+July 22, 2026 @c AUTO-REPLACE-ON-SAVE
 
 
   Published by the Free Software Foundation, Inc.
@@ -5155,15 +5155,37 @@ reference is highlighted but no referent is displayed).  Defer
 referent creation until the first activation of the HyWikiWord, at
 which point the HyWiki RefType menu is displayed for selection.
 
-@cindex menu item, HyWiki Glossary
+@cindex menu item, HyWiki glossarY
 @cindex HyWiki Glossary reftype
 @cindex HyWikiWord definition
 @cindex definition, HyWikiWord
 @findex hywiki-get-definition
+@anchor{HyWiki Glossary}
 @item Glossary
-Add a HyWikiWord that displays its own definition from the HyWiki's
-Glossary.org file.  See the documentation string for
-@code{hywiki-get-definition} for more detail.
+Add or edit the definition of a HyWikiWord that displays its own
+definition from the HyWiki's Glossary.org file.
+
+A HyWiki can contain a Glossary.org file with heading titles that
+represent terms associated with the HyWiki.  The body of each heading
+section is the definition of the term.  Terms can consist of multiple
+words and do not have to be HyWikiWords but may be.
+
+@noindent
+There are three ways to work with HyWiki glossary terms:
+
+@enumerate
+@item Use a @dfn{hydef} Action Button to display the term's definition.
+For example, @samp{} or @samp{}
+
+@item Create a HyWikiWord with a glossary referent type.
+With @code{hywiki-mode} active, {M-0 M-RET y} or {C-h h h c y} will
+turn the wikiword at point into or will prompt you for a wikiword name
+whose referent displays the definition for the wikiword.
+
+@item Programmatically display a glossary entry.
+Call @code{(hywiki-get-definition "term" t) to display the entry.
+@end MyNewWord enumerate
+
 @end table
 
 @vindex hywiki-directory
@@ -8833,12 +8855,23 @@ publishes/exports an entire HyWiki to HTML for display on the web.
 See the documentation for its implicit button types,
 @code{hywiki-word} and @code{hywiki-existing-word}.
 
+@cindex glossary, HyWiki
+@cindex definition, HyWikiWord
+@cindex HyWikiWord definition
+@item HyWiki Glossary
+A HyWiki can contain a Glossary.org file with heading titles that
+represent terms associated with the HyWiki.  The body of each heading
+section is the definition of the term.  Terms can consist of multiple
+words and do not have to be HyWikiWords but may be.
+
+@xref{HyWiki Glossary}, for more details.
+
 @item HyWikiWord
 A @dfn{HyWikiWord}, or just wikiword, is a PascalCase word that starts
 with a capital letter and contains upper and lowercase letters only
 and has an associated referent (a link or an action).  The default,
-most common referent type, is a @dfn{HyWiki Page}, an Org file with the
-wikiword's name and a @file{.org} suffix that lives in
+most common referent type, is a @dfn{HyWiki Page}, an Org file with
+the wikiword's name and a @file{.org} suffix that lives in
 @code{hywiki-directory}.
 
 HyWikiWords are automatically highlighted and turned into hyperlinks

From 3c79ceb73e4ca720de9b9c93f42fa0adbb18c9d2 Mon Sep 17 00:00:00 2001
From: bw 
Date: Wed, 22 Jul 2026 23:50:02 -0400
Subject: [PATCH 2/4] test/hy-string-tests.el - Add to begin testing
 `hypb:in-string-p'

---
 ChangeLog               |  2 +
 test/MANIFEST           |  1 +
 test/demo-tests.el      |  4 +-
 test/hy-string-tests.el | 97 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 102 insertions(+), 2 deletions(-)
 create mode 100644 test/hy-string-tests.el

diff --git a/ChangeLog b/ChangeLog
index 7891ab90..86af9b57 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
 2026-07-22  Bob Weiner  
 
+* test/hy-string-tests.el: Add to start 'hypb:in-string-p' testing.
+
 * man/hyperbole.texi (HyWiki Menu, HyWiki Glossary): Document the ways
     to use HyWiki glossary entries.
 
diff --git a/test/MANIFEST b/test/MANIFEST
index 444cd43d..12da5c0f 100644
--- a/test/MANIFEST
+++ b/test/MANIFEST
@@ -19,6 +19,7 @@ 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
+hy-string-tests.el      - test whether point is inside or outside of a string
 hy-test-coverage.el     - provide test coverage information
 hy-test-dependencies.el - Hyperbole test dependencies
 hy-test-helpers.el      - unit test helpers
diff --git a/test/demo-tests.el b/test/demo-tests.el
index 7587e246..8c5f0c88 100644
--- a/test/demo-tests.el
+++ b/test/demo-tests.el
@@ -1,9 +1,9 @@
 ;;; demo-tests.el --- unit tests from examples in the DEMO         -*- lexical-binding: t; -*-
-
+;;
 ;; Author:       Mats Lidell 
 ;;
 ;; Orig-Date:    30-Jan-21 at 12:00:00
-;; Last-Mod:     16-Jun-26 at 22:09:58 by Bob Weiner
+;; Last-Mod:     22-Jul-26 at 23:49:19 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
diff --git a/test/hy-string-tests.el b/test/hy-string-tests.el
new file mode 100644
index 00000000..a24dce5b
--- /dev/null
+++ b/test/hy-string-tests.el
@@ -0,0 +1,97 @@
+;;; hy-string-tests.el --- test whether point is inside or outside of a string    -*- lexical-binding: t; -*-
+;;
+;; Author:       Bob Weiner
+;;
+;; Orig-Date:    22-Jul-26 at 23:41:29
+;; Last-Mod:     22-Jul-26 at 23:49:34 by Bob Weiner
+;;
+;; SPDX-License-Identifier: GPL-3.0-or-later
+;;
+;; Copyright (C) 2026  Free Software Foundation, Inc.
+;; See the "HY-COPY" file for license information.
+;;
+;; This file is part of GNU Hyperbole.
+
+;;; Commentary:
+
+;; Test point location relative to string start and end locations.
+
+;;; Code:
+
+;;; ************************************************************************
+;;; Other required Elisp libraries
+;;; ************************************************************************
+
+(require 'cl-lib) ;; For `cl-incf'
+(require 'hypb)   ;; For `hypb:in-string-p'
+
+;; Sample use of next function
+;; (debug-in-string "double-quotes" "str")
+;; (debug-in-string "double-with-single" "' st' 'r' ")
+;; (debug-in-string "python-triple-multi-line" "\"\"\"\n str\n\"\"\"" 'python-mode)
+
+;;; ************************************************************************
+;;; Public functions
+;;; ************************************************************************
+
+(defun debug-in-string (test-name str &optional mode)
+  "With TEST-NAME for each char in STR, print results of whether in the string.
+STR, including delimiters, is inserted into a blank buffer for testing.
+With optional major MODE, a function, that mode is enabled prior to testing the string."
+  (interactive sStr to test: \")
+  (with-temp-buffer
+    (when mode (funcall mode))
+    (insert "\"" str "\"")
+    (with-help-window (format "*%s Results*" (capitalize test-name))
+      (prin1 str)
+      (when mode
+        (princ " - ")
+        (princ (cond ((symbolp mode) (symbol-name mode))
+                     ((stringp mode) mode))))
+      (terpri)
+      (terpri)
+      (goto-char (point-min))
+      (let ((len (+ (length str) 2))
+            (i 1)
+            hypb-in-str
+            ppss-in-str
+            str-start
+            foll-quote)
+        (while (/= i (point-max))
+          (goto-char i)
+          (setq hypb-in-str (hypb:in-string-p)     ;; Hyperbole in-string test
+                ppss-in-str (nth 3 (syntax-ppss))  ;; Emacs in-string test
+                str-start   (nth 8 (syntax-ppss))  ;; Char that starts this string, if any
+                foll-quote  (nth 5 (syntax-ppss))) ;; t if following a quote char
+          (princ
+           (format "%s Pos %2d, char '%c', in-str hypb=%3S %3S=ppss, str-start=%3S, following-quote=%3S"
+                   (if (or (and hypb-in-str ppss-in-str)
+                           (and (not hypb-in-str) (not ppss-in-str)))
+                       "."
+                     "F")
+                   i (following-char)
+                   hypb-in-str ppss-in-str str-start foll-quote
+                   ;; Hyperbole in-string test
+                   (hypb:in-string-p)
+                   ;; Emacs in-string test; any non-nil value is the
+                   ;; character that will terminate the string, or t if the
+                   ;; string should be terminated by a generic string
+                   ;; delimiter
+                   (nth 3 (syntax-ppss))
+                   ;; Character address of start of comment or string;
+                   ;; nil if not in one
+                   (nth 8 (syntax-ppss))
+                   ;; t if following a quote char
+                   (nth 5 (syntax-ppss))
+                   ;; Sixth arg COMMENTSTOP non-nil means stop after the
+                   ;; start of a comment. If it is the symbol
+                   ;; ‘syntax-table’, stop after the start of a comment or a
+                   ;; string, or after end of a comment or a string.
+                   ))
+          (terpri)
+          (cl-incf i))))))
+
+
+(provide 'hy-string-tests)
+
+;;; hy-string-tests.el ends here

From 05e395810da39753f8433e07464ace244ad2836d Mon Sep 17 00:00:00 2001
From: bw 
Date: Thu, 23 Jul 2026 00:20:45 -0400
Subject: [PATCH 3/4] hkey-help - Conditionalize HyWikiWord glossary entry on
 non-nil ref

(hywiki-get-entry - Strip file header when returning definition as
a string, as that is all should be desired.
---
 ChangeLog          |  8 ++++++++
 hmouse-drv.el      | 41 +++++++++++++++++++++--------------------
 hywiki.el          |  8 ++++++--
 man/hyperbole.texi | 12 ++++++------
 4 files changed, 41 insertions(+), 28 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 86af9b57..f354662c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2026-07-23  Bob Weiner  
+
+* hywiki.el (hywiki-get-entry): Strip file header when returning
+    definition as a string, as that is all should be desired.
+
+* hmouse-drv.el (hkey-help): Conditionalize HyWikiWord glossary entry
+    definition output on a non-nil 'lbl-key', i.e. non-nil reference.
+
 2026-07-22  Bob Weiner  
 
 * test/hy-string-tests.el: Add to start 'hypb:in-string-p' testing.
diff --git a/hmouse-drv.el b/hmouse-drv.el
index cfe0de44..a200733c 100644
--- a/hmouse-drv.el
+++ b/hmouse-drv.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    04-Feb-90
-;; Last-Mod:     20-Jul-26 at 01:47:30 by Bob Weiner
+;; Last-Mod:     23-Jul-26 at 00:17:46 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -1185,15 +1185,15 @@ documentation is found."
 
 		    ;; Print Hyperbole button attributes
 		    (when (memq cmd-sym '(hui:hbut-act hui:hbut-help))
-		      (let* ;; (lbl-key (hattr:get 'hbut:current 'lbl-key))
-			  ((categ (hattr:get 'hbut:current 'categ))
-			   (attributes (nthcdr 2 (hattr:list 'hbut:current)))
-			   (but-def-symbol (htype:def-symbol
-					    (if (eq categ 'explicit) actype categ)))
-                           (wikiword-referent
-                            (when (eq (htype:def-symbol actype) 'link-to-wikiword)
-                              (hywiki-get-referent
-                               (hattr:get 'hbut:current 'lbl-key)))))
+		      (let* ((lbl-key (hattr:get 'hbut:current 'lbl-key))
+			     (categ (hattr:get 'hbut:current 'categ))
+			     (attributes (nthcdr 2 (hattr:list 'hbut:current)))
+			     (but-def-symbol (htype:def-symbol
+					      (if (eq categ 'explicit) actype categ)))
+                             (wikiword-referent
+                              (when (eq (htype:def-symbol actype) 'link-to-wikiword)
+                                (hywiki-get-referent
+                                 (hattr:get 'hbut:current 'lbl-key)))))
 
                         (when wikiword-referent
                           (hattr:set 'hbut:current 'referent-type
@@ -1219,16 +1219,17 @@ documentation is found."
 			;;   (hypb:remove-from-plist attributes 'action))
 			(hattr:report attributes)
 
-                        ;; Need to save and restore 'hbut:current here since
-                        ;; hywiki-get-definition overwrites it
-                        (unwind-protect
-                            (progn (hattr:copy 'hbut:current 'saved-but)
-                                   (setq def (hywiki-get-definition
-			                      (ibut:key-to-label (hattr:get 'hbut:current 'lbl-key))))
-                                   (when def
-                                     (terpri)
-                                     (princ def)))
-                          (hattr:copy 'saved-but 'hbut:current))
+                        (when lbl-key
+                          (unwind-protect
+                              ;; Need to save and restore 'hbut:current here
+                              ;; since hywiki-get-definition overwrites it
+                              (progn (hattr:copy 'hbut:current 'saved-but)
+                                     (setq def (hywiki-get-definition
+			                        (ibut:key-to-label lbl-key)))
+                                     (when (stringp def)
+                                       (terpri)
+                                       (princ def)))
+                            (hattr:copy 'saved-but 'hbut:current)))
 
 			(unless (or assisting
 				    (eq categ 'explicit)
diff --git a/hywiki.el b/hywiki.el
index 0fcf1a3b..b925d9ac 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-Jul-26 at 23:17:56 by Bob Weiner
+;; Last-Mod:     23-Jul-26 at 00:10:03 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -2650,7 +2650,11 @@ top-level headlines are searched.
           t)
       (unless (zerop found)
         (with-current-buffer hyrolo-display-buffer
-          (buffer-string))))))
+          (save-excursion
+            (goto-char (point-min))
+            ;; skip past header to the entry
+            (hyrolo-to-next-entry)
+          (buffer-substring (point) (point-max))))))))
 
 ;;;###autoload
 (defmacro hydef (&rest term)
diff --git a/man/hyperbole.texi b/man/hyperbole.texi
index fa438594..7812c45a 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:     22-Jul-26 at 23:25:37 by Bob Weiner
+@c Last-Mod:     22-Jul-26 at 23:56:16 by Bob Weiner
 
 @c %**start of header (This is for running Texinfo on a region.)
 @setfilename hyperbole.info
@@ -5178,13 +5178,13 @@ There are three ways to work with HyWiki glossary terms:
 For example, @samp{} or @samp{}
 
 @item Create a HyWikiWord with a glossary referent type.
-With @code{hywiki-mode} active, {M-0 M-RET y} or {C-h h h c y} will
-turn the wikiword at point into or will prompt you for a wikiword name
-whose referent displays the definition for the wikiword.
+With @code{hywiki-mode} active, @bkbd{M-0 M-RET y} or @bkbd{C-h h h c
+y} will turn the wikiword at point into or will prompt you for a
+wikiword name whose referent displays the definition for the wikiword.
 
 @item Programmatically display a glossary entry.
-Call @code{(hywiki-get-definition "term" t) to display the entry.
-@end MyNewWord enumerate
+Call @code{(hywiki-get-definition "term" t)} to display the entry.
+@end enumerate
 
 @end table
 

From d9f216b399c9679fc454458a0c9dc70dcc57fe13 Mon Sep 17 00:00:00 2001
From: bw 
Date: Thu, 23 Jul 2026 11:41:20 -0400
Subject: [PATCH 4/4] hywiki-display-glossary-entry - Don't display if creating
 the entry

hywiki-get-definition, hywiki-get-entry - Fix tests by returning nil
if first are sent is a non-string or an empty string, rather than
triggering an error.
---
 ChangeLog            |   6 +
 hywiki.el            | 268 ++++++++++++++++++++++---------------------
 test/hywiki-tests.el |   2 +-
 3 files changed, 144 insertions(+), 132 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index f354662c..8dc5d02c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,12 @@
 
 * hywiki.el (hywiki-get-entry): Strip file header when returning
     definition as a string, as that is all should be desired.
+            (hywiki-get-definition, hywiki-get-entry): Change so just
+    returns nil if first arg is sent as a non-string or an empty string
+    rather than triggering an error.
+            (hywiki-display-glossary-entry): Don't display the entry if in
+    the middle of a 'hywiki-create-referent-and-display' call since that
+    displays the entry source buffer already.
 
 * hmouse-drv.el (hkey-help): Conditionalize HyWikiWord glossary entry
     definition output on a non-nil 'lbl-key', i.e. non-nil reference.
diff --git a/hywiki.el b/hywiki.el
index b925d9ac..f964176a 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:     23-Jul-26 at 00:10:03 by Bob Weiner
+;; Last-Mod:     23-Jul-26 at 11:38:51 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -1461,14 +1461,20 @@ calling this function."
                ;; Skip past file header
                (hyrolo-to-next-entry)
                (hyrolo-edit-entry))
-      ;; add a new entry
+      ;; add a new definition entry using the original term, not any
+      ;; wikiword transformed version
       (hyrolo-add term glossary)))
+  ;; Connect wikiword version of term to the glossary definition
   (hywiki-add-referent (hywiki-string-to-wikiword term)
                        (cons 'glossary-entry term)))
 
 (defun hywiki-display-glossary-entry (_wikiword term)
   "Display any HyWiki glossary definition for TERM."
-  (hywiki-get-definition term t))
+  ;; Don't display the entry if in the middle of a
+  ;; `hywiki-create-referent-and-display' call since that displays the entry
+  ;; source buffer already.
+  (unless (hyperb:stack-frame '(hywiki-create-referent-and-display))
+    (hywiki-get-definition term t)))
 
 (defun hywiki-add-hyrolo (wikiword)
   "Make WIKIWORD search and display `hyrolo-file-list' matches.
@@ -2427,7 +2433,8 @@ therein is invalid, trigger an error."
 ;;;###autoload
 (defun hywiki-get-definition (term &optional display-flag file)
   "Return or display the HyWiki glossary definition string for TERM.
-Return nil if no match is found.
+Return nil if TERM is not a string, if TERM is the empty string or no match
+is found.
 
 If called interactively or with optional DISPLAY-FLAG non-nil, display a
 buffer with TERM's definition but don't return it.  Get definition from
@@ -2452,47 +2459,46 @@ top-level headlines are searched.
   (interactive (list (hywiki-completing-read-glossary-term
                       "HyWiki glossary definition of: ")
                      nil t))
-  (when (or (not (stringp term)) (string-empty-p term))
-    (error "(hywiki-get-definition): Invalid `term': `%s'" term))
-  (let ((glossary (hywiki-get-glossary-file file))
-        entry
-        index
-        term-regexp
-        wikiword)
-    (cond ((setq index (seq-position term ?#))
-           ;; WikiWord#section or #section
-           (setq wikiword (substring term 0 index)
-                 term (substring term (1+ index))
-                 term-regexp (hywiki-get-term-variant-regexp term)
-                 file (if (zerop index)
-                          buffer-file-name
-                        (hywiki-get-page-file wikiword))))
-          ((or (hywiki-word-is-p term t) (null file))
-           ;; Is a WikiWord or phrase only; match to any of several
-           ;; forms: WikiWord, wikiword, Wiki Word, wiki word -- in
-           ;; file when given or the Glossary file when not
-           (when (file-readable-p glossary)
-             (setq term-regexp (hywiki-get-term-variant-regexp term))
-             (unless (and (stringp file) (not (string-empty-p file)))
-               (setq file glossary))))
-          (t
-           ;; `file' is non-null so try to use that or trigger and error
-           (when (or (not (stringp file)) (string-empty-p file)
-                     (not (file-readable-p file)))
-             (error "(hywiki-get-definition): \"%s\" is invalid" file))
-           (setq term-regexp (hywiki-get-term-variant-regexp term))))
-
-    ;; Return and possibly display matching definition
-    (setq entry (hywiki-get-entry term-regexp display-flag file t))
-
-    (when (stringp entry)
-      ;; Remove * or # prefix from def entry before returning, so can be
-      ;; embedded in other doc
-      (setq entry (substring entry (if (string-match "\\`[*#]+[ \t\n\f]*"
-                                                     entry)
-                                       (match-end 0)
-                                     0))))
-    entry))
+  (when (and (stringp term) (not (string-empty-p term)))
+    (let ((glossary (hywiki-get-glossary-file file))
+          entry
+          index
+          term-regexp
+          wikiword)
+      (cond ((setq index (seq-position term ?#))
+             ;; WikiWord#section or #section
+             (setq wikiword (substring term 0 index)
+                   term (substring term (1+ index))
+                   term-regexp (hywiki-get-term-variant-regexp term)
+                   file (if (zerop index)
+                            buffer-file-name
+                          (hywiki-get-page-file wikiword))))
+            ((or (hywiki-word-is-p term t) (null file))
+             ;; Is a WikiWord or phrase only; match to any of several
+             ;; forms: WikiWord, wikiword, Wiki Word, wiki word -- in
+             ;; file when given or the Glossary file when not
+             (when (file-readable-p glossary)
+               (setq term-regexp (hywiki-get-term-variant-regexp term))
+               (unless (and (stringp file) (not (string-empty-p file)))
+                 (setq file glossary))))
+            (t
+             ;; `file' is non-null so try to use that or trigger an error
+             (when (or (not (stringp file)) (string-empty-p file)
+                       (not (file-readable-p file)))
+               (error "(hywiki-get-definition): \"%s\" is invalid" file))
+             (setq term-regexp (hywiki-get-term-variant-regexp term))))
+
+      ;; Return and possibly display matching definition
+      (setq entry (hywiki-get-entry term-regexp display-flag file t))
+
+      (when (stringp entry)
+        ;; Remove * or # prefix from def entry before returning, so can be
+        ;; embedded in other doc
+        (setq entry (substring entry (if (string-match "\\`[*#]+[ \t\n\f]*"
+                                                       entry)
+                                         (match-end 0)
+                                       0))))
+      entry)))
 
 (defun hywiki-get-delimited-region ()
   "Immediately before or after a balanced delimiter, return the delimited range.
@@ -2542,7 +2548,8 @@ This includes the delimiters: (), {}, <>, [] and \"\" (double quotes)."
 ;;;###autoload
 (defun hywiki-get-entry (reference &optional display-flag file regexp-flag)
   "Return a string of the first HyWiki entry headline containing REFERENCE.
-Return nil if no match is found.
+Return nil if REFERENCE is not a string, if REFERENCE is the empty string or
+no match is found.
 
 If called interactively or with optional DISPLAY-FLAG non-nil, display a
 buffer with REFERENCE's definition but don't return it.  If the file is not
@@ -2550,8 +2557,11 @@ readable or no matching REFERENCE entry is found, return nil; othewise,
 return t.
 
 Get definition from HyWiki's Glossary.org, optional FILE, or the current
-buffer for #in-file references.  With optional prefix arg, REGEXP-FLAG,
-treat REFERENCE as a regular expression instead of a string.
+buffer for #in-file references.  Trigger an error if an invalid non-nil FILE
+argument is sent.
+
+With optional prefix arg, REGEXP-FLAG, treat REFERENCE as a regular
+expression instead of a string.
 
 If the `consult' package is installed, interactively select and complete
 the entry to be inserted.
@@ -2569,92 +2579,88 @@ top-level headlines are searched.
 |------------------+------+---------------+----------------------------------|"
   (interactive (list (hywiki-read-headline-regexp "Return")
 		     current-prefix-arg))
-  (when (and (stringp reference) (string-empty-p reference))
-    (setq reference nil))
-  (when (or (null reference) (not (stringp reference)))
-    (error "(hywiki-get-entry): Invalid reference: `%s'" reference))
-
-  (let ((hyrolo-display-buffer hywiki-glossary-display-buffer)
-        (buf-file buffer-file-name)
-        (found 0)
-        (word-end (hywiki-word-is-p reference t))
-        (consult-flag (and (called-interactively-p 'interactive) (hsys-consult-active-p)))
-        (phrase "")
-        entry-to-match
-        path-list)
-    (save-window-excursion
-      (with-current-buffer (get-buffer-create hywiki-glossary-display-buffer)
-        (setq hyrolo-display-buffer hywiki-glossary-display-buffer)
-        ;; (hyrolo--cache-initialize)
-	(cond ((or consult-flag
-                   (not (string-match-p "#" reference))
-                   (not word-end))
-               (setq phrase ""
-                     entry-to-match reference))
-              (word-end
-               (setq phrase (string-trim (substring reference 0 word-end))
-                     entry-to-match (unless (= word-end (length reference))
-                                      (string-trim (substring reference (1+ word-end)))))))
-        ;; If path-list remains nil, then search will be across the whole wiki
-        (cond ((stringp file)
-               ;; explicit `file' given
-               (setq path-list (list (expand-file-name file hywiki-directory))))
-              ((and (not consult-flag) (string-match-p "\\`#" reference))
-               ;; in-file reference
-               (setq entry-to-match (substring reference 1)
-                     path-list (if buf-file
-                                   (list buf-file)
-                                 (user-error "(hywiki-get-entry): #section not allowed in non-file buffer: reference = %s; buffer = %S"
-                                             reference (get-buffer buf-file)))))
-              ((not (string-empty-p phrase))
-               ;; The phrase is a WikiWord; use this as the file to search
-               (setq path-list (list (expand-file-name
-                                      (concat phrase
-                                              (unless (string-suffix-p hywiki-file-suffix phrase)
-                                                hywiki-file-suffix))
-                                      hywiki-directory)))))
-
-        (unless entry-to-match
-          (error "(hywiki-get-entry): No `entry-to-match' derivable from \"%s\""
-                 reference))
-
-        (save-excursion
-          (setq found
-	        (if (and consult-flag
-                         (or path-list
-                             ;; Extract `name' from the line-numbered
-                             ;; `consult-grep' match results
-		             (string-match "\\([^ \t\n\r\"'`]*[^ \t\n\r:\"'`0-9]\\): ?\\([1-9][0-9]*\\)[ :]"
-				           reference)))
-		    (hyrolo-grep-file (if path-list (car path-list) (match-string-no-properties 1 reference))
-				      (funcall (if regexp-flag #'identity #'regexp-quote)
-                                               (if path-list
-                                                   entry-to-match
-                                                 (substring reference (match-end 0))))
-				      -1 nil t)
-	          (hyrolo-grep (if regexp-flag entry-to-match (regexp-quote entry-to-match))
-                               -1
-                               (hyrolo-expand-path-list (or path-list (list hywiki-directory)))
-                               nil t (not display-flag)))))))
-    (if display-flag
-        (if (zerop found)
-            (progn (beep)
-                   (message "(hywiki-get-entry): No match for `%s' found in `%s'"
-                            reference
-                            (or path-list hywiki-directory))
-                   nil)
-          ;; Display even if no entries are found
-          (hyrolo-display-matches)
-          ;; skip past header to the entry
-          (hyrolo-to-next-entry)
-          t)
-      (unless (zerop found)
-        (with-current-buffer hyrolo-display-buffer
+  (when (and (stringp reference) (not (string-empty-p reference)))
+    (let ((hyrolo-display-buffer hywiki-glossary-display-buffer)
+          (buf-file buffer-file-name)
+          (found 0)
+          (word-end (hywiki-word-is-p reference t))
+          (consult-flag (and (called-interactively-p 'interactive) (hsys-consult-active-p)))
+          (phrase "")
+          entry-to-match
+          path-list)
+      (save-window-excursion
+        (with-current-buffer (get-buffer-create hywiki-glossary-display-buffer)
+          (setq hyrolo-display-buffer hywiki-glossary-display-buffer)
+          ;; (hyrolo--cache-initialize)
+	  (cond ((or consult-flag
+                     (not (string-match-p "#" reference))
+                     (not word-end))
+                 (setq phrase ""
+                       entry-to-match reference))
+                (word-end
+                 (setq phrase (string-trim (substring reference 0 word-end))
+                       entry-to-match (unless (= word-end (length reference))
+                                        (string-trim (substring reference (1+ word-end)))))))
+          ;; If path-list remains nil, then search will be across the whole wiki
+          (cond ((stringp file)
+                 ;; explicit `file' given
+                 (setq path-list (list (expand-file-name file hywiki-directory))))
+                ((and (not consult-flag) (string-match-p "\\`#" reference))
+                 ;; in-file reference
+                 (setq entry-to-match (substring reference 1)
+                       path-list (if buf-file
+                                     (list buf-file)
+                                   (user-error "(hywiki-get-entry): #section not allowed in non-file buffer: reference = %s; buffer = %S"
+                                               reference (get-buffer buf-file)))))
+                ((not (string-empty-p phrase))
+                 ;; The phrase is a WikiWord; use this as the file to search
+                 (setq path-list (list (expand-file-name
+                                        (concat phrase
+                                                (unless (string-suffix-p hywiki-file-suffix phrase)
+                                                  hywiki-file-suffix))
+                                        hywiki-directory)))))
+
+          (unless entry-to-match
+            (error "(hywiki-get-entry): No `entry-to-match' derivable from \"%s\""
+                   reference))
+
           (save-excursion
-            (goto-char (point-min))
+            (setq found
+	          (if (and consult-flag
+                           (or path-list
+                               ;; Extract `name' from the line-numbered
+                               ;; `consult-grep' match results
+		               (string-match "\\([^ \t\n\r\"'`]*[^ \t\n\r:\"'`0-9]\\): ?\\([1-9][0-9]*\\)[ :]"
+				             reference)))
+		      (hyrolo-grep-file (if path-list (car path-list) (match-string-no-properties 1 reference))
+				        (funcall (if regexp-flag #'identity #'regexp-quote)
+                                                 (if path-list
+                                                     entry-to-match
+                                                   (substring reference (match-end 0))))
+				        -1 nil t)
+	            (hyrolo-grep (if regexp-flag entry-to-match (regexp-quote entry-to-match))
+                                 -1
+                                 (hyrolo-expand-path-list (or path-list (list hywiki-directory)))
+                                 nil t (not display-flag)))))))
+      (if display-flag
+          (if (zerop found)
+              (progn (beep)
+                     (message "(hywiki-get-entry): No match for `%s' found in `%s'"
+                              reference
+                              (or path-list hywiki-directory))
+                     nil)
+            ;; Display even if no entries are found
+            (hyrolo-display-matches)
             ;; skip past header to the entry
             (hyrolo-to-next-entry)
-          (buffer-substring (point) (point-max))))))))
+            t)
+        (unless (zerop found)
+          (with-current-buffer hyrolo-display-buffer
+            (save-excursion
+              (goto-char (point-min))
+              ;; skip past header to the entry
+              (hyrolo-to-next-entry)
+              (buffer-substring (point) (point-max)))))))))
 
 ;;;###autoload
 (defmacro hydef (&rest term)
diff --git a/test/hywiki-tests.el b/test/hywiki-tests.el
index 19f80dba..c219ba5c 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:     21-Jul-26 at 22:30:31 by Mats Lidell
+;; Last-Mod:     23-Jul-26 at 11:38:53 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;