From 36e441a9ffd2c7d492a19ad4a916b7e2d0809b6f Mon Sep 17 00:00:00 2001
From: bw
Edition 9.0.2pre -Printed February 7, 2026. +Printed February 18, 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 -February 7, 2026 @c AUTO-REPLACE-ON-SAVE +February 18, 2026 @c AUTO-REPLACE-ON-SAVE Published by the Free Software Foundation, Inc. @@ -3887,6 +3887,7 @@ upon the referent context in which the Action Key is released. @example Referent Context Link Type ---------------------------------------------------- +HyWikiWord Reference link-to-wikiword Org Roam or Org Id link-to-org-id Global Button link-to-gbut Explicit Button link-to-ebut From bac4fd78fbbae8963b1a6433e7eabdcf6fe17dba Mon Sep 17 00:00:00 2001 From: bwDate: Thu, 19 Feb 2026 01:16:43 -0500 Subject: [PATCH 2/4] hui.el - Eliminate recursive require with 'hywiki --- README.toc.md | 31 +++++++++++++++++++++++++++---- hui.el | 5 +++-- hywiki.el | 4 ++-- kotl/kotl-mode.el | 8 +++++--- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/README.toc.md b/README.toc.md index 18cb88f5..0231bc28 100644 --- a/README.toc.md +++ b/README.toc.md @@ -7,11 +7,10 @@ send us a thank you or a testimonial describing your usage if you like Hyperbole to [rsw@gnu.org](mailto:rsw@gnu.org)]. - - - [GNU Hyperbole 9.0.2pre - The Everyday Hypertextual Information Manager](#gnu-hyperbole-902pre---the-everyday-hypertextual-information-manager) - [Reference Manual](#reference-manual) - [Videos](#videos) + - [Articles](#articles) - [Summary](#summary) - [Installation](#installation) - [Invocation](#invocation) @@ -26,8 +25,6 @@ - [User Quotes](#user-quotes) - [Why was Hyperbole developed?](#why-was-hyperbole-developed) - -  ## Reference Manual @@ -74,6 +71,30 @@ otherwise, skip to the next section. - [Linking personal info with implicit buttons](https://youtu.be/TQ_fG7b1iHI) +## Articles + + - [HyWiki: My Favorite Part of Hyperbole](https://kirankp.com/blog/gnu-hyperbole/) + + - [Hyperbole VisionQuest Part 1](https://github.com/termitereform/JunkPile/blob/master/HyperboleNotes.org) + + - [Hyperbole VisionQuest Part 2](https://github.com/termitereform/JunkPile/blob/master/HyperboleNotes2.org) + + - [A Taste of Hyperbole](https://www.reddit.com/r/emacs/comments/1kty4mb/a_taste_of_hyperbole_automatically_linking_to_org/) + + - [My Understanding of GNU Hyperbole](https://www.reddit.com/r/emacs/comments/nirwpk/my_understanding_of_gnu_hyperbole/) + + - [What does GNU Hyperbole do?](https://tilde.town/~ramin_hal9001/articles/intro-to-hyperbole.html) + + - [John Wiegley - The Philosophy Behind Hyperbole](https://mail.gnu.org/archive/html/hyperbole-users/2019-01/msg00037.html) + + - [Daily ways GNU Hyperbole helps me stay in flow and reduces cognitive load](https://www.reddit.com/r/emacs/comments/jk3cn0/daily_ways_gnu_hyperbole_helps_me_stay_in_flow/) + + - [Doing a Research Project and using GNU Hyperbole's Integrated Features](https://www.reddit.com/r/emacs/comments/1g2184d/doing_a_research_project_and_using_gnu_hyperboles/) + + - [AI-generated Hyperbole Architectural Documentation](https://deepwiki.com/rswgnu/hyperbole) + + - [Hypermedia and Hyperbole](https://www.mgmarlow.com/words/2023-10-26-hyperbole/) + ## Summary `GNU Hyperbole` (pronounced Ga-new Hi-per-bo-lee), or just `Hyperbole`, is @@ -255,6 +276,8 @@ window control menu if it was not already bound prior to Hyperbole's initialization. A long video demonstrating many of HyControl's features is available at https://youtu.be/M3-aMh1ccJk. +## Hyperbole Manual + The above are the best interactive ways to learn about Hyperbole. Hyperbole also includes the Hyperbole Manual, a full reference manual, not a simple introduction. It is included in the "man/" subdirectory diff --git a/hui.el b/hui.el index f818c7ed..3a2f5571 100644 --- a/hui.el +++ b/hui.el @@ -3,7 +3,7 @@ ;; Author: Bob Weiner ;; ;; Orig-Date: 19-Sep-91 at 21:42:03 -;; Last-Mod: 19-Feb-26 at 00:29:40 by Bob Weiner +;; Last-Mod: 19-Feb-26 at 01:08:15 by Bob Weiner ;; ;; SPDX-License-Identifier: GPL-3.0-or-later ;; @@ -27,7 +27,6 @@ (require 'hmail) (require 'hbut) (eval-when-compile (require 'hactypes)) -(eval-when-compile (require 'hywiki)) ;; Because 'hyperbole' requires this too ;;; ************************************************************************ ;;; Public declarations @@ -38,8 +37,10 @@ (defvar completion-to-accept) ; "completion.el" (defvar hyperbole-mode-map) ; "hyperbole.el" +(declare-function actypes::link-to-wikiword "hywiki") (declare-function bookmark-bmenu-bookmark "bookmark") (declare-function hui:menu-choose "hui-mini") +(declare-function hywiki-referent-exists-p "hywiki") (declare-function kcell-view:absolute-reference "kotl/kview") (declare-function kcell-view:idstamp "kotl/kview") (declare-function klink:absolute "kotl/klink") diff --git a/hywiki.el b/hywiki.el index 2b7bacaa..0d7e5cb3 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: 19-Feb-26 at 00:57:14 by Bob Weiner +;; Last-Mod: 19-Feb-26 at 01:08:50 by Bob Weiner ;; ;; SPDX-License-Identifier: GPL-3.0-or-later ;; @@ -144,7 +144,7 @@ (require 'hpath) (require 'hproperty) (require 'hsys-consult) -(eval-when-compile (require 'hui)) ;; For `hui:actype' +(require 'hui) ;; For `hui:actype' (require 'hui-mini) ;; For `hui:menu-act' (require 'hypb) ;; Requires `seq' (require 'outline) ;; For `outline-mode-syntax-table' diff --git a/kotl/kotl-mode.el b/kotl/kotl-mode.el index 76f4b08d..b997d739 100644 --- a/kotl/kotl-mode.el +++ b/kotl/kotl-mode.el @@ -3,7 +3,7 @@ ;; Author: Bob Weiner ;; ;; Orig-Date: 6/30/93 -;; Last-Mod: 19-Jan-26 at 22:34:04 by Mats Lidell +;; Last-Mod: 19-Feb-26 at 01:12:25 by Bob Weiner ;; ;; SPDX-License-Identifier: GPL-3.0-or-later ;; @@ -2491,8 +2491,10 @@ Optional prefix arg RELATIVE-LEVEL means one of the following: 1. when = 0, add as the parent's first child cell (first cell in list); 2. when < 0, add that number of cells as preceding siblings; - 3. when \\='(4) (universal arg, \\`C-u'), add as the first child of the current cell; - 4. when > 0 or nil (meaning 1), add that number of cells as following siblings." + 3. when \\='(4) (universal arg, \\`C-u'), add as the first child of the + current cell; + 4. when > 0 or nil (meaning 1), add that number of cells as following + siblings." (interactive "*P") (unless (or (integerp relative-level) (listp relative-level) ) (error "(kotl-mode:add-cell): `relative-level' must be an integer or a list of integers, not '%s'" relative-level)) From 9d359d983166ff9fba2f4acfd50a204c8f273454 Mon Sep 17 00:00:00 2001 From: bw Date: Thu, 19 Feb 2026 19:32:39 -0500 Subject: [PATCH 3/4] (hywiki-word-is-p): Revert to using all 'string-match' calls This fixes test match-string references. Also fix a number of functions to allow only page name wikiwords. hywiki-add-page - Fix a number of issues where non-page WikiWords were allowed. --- ChangeLog | 16 ++++++++++- hywiki.el | 82 +++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 68 insertions(+), 30 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2725b473..597f9e41 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,18 @@ -2026-02-18 Bob Weiner +2026-02-19 Bob Weiner + +* hywiki.el (hywiki-read-page-reference): Add and use in 'interactive' calls of + several functions. + (hywiki-word-is-p): Revert to using all 'string-match' calls + to prevent any regressions. + (hywiki-page-read): Add to read only existing HyWiki page names. + Not all existing WikiWords have page names, as there are other referent types. + (hywiki-consult-file-and-line): Rename to `hywiki-consult-page-and-line'. + (hywiki-page-exists-p): Add. + (hywiki-format-reference): Fix to accept only existing page references. + (hywiki-read-reference): Delete, use 'hywiki-word-read' instead. + (hywiki-add-page): Fix a number of issues where non-page WikiWords were + allowed. + (hywiki-page-read-new): Prevent selection of non-page HyWikiWords. * hui.el (require 'hywiki): (hui:link-possible-types): Add 'link-to-wikiword' clause. diff --git a/hywiki.el b/hywiki.el index dc04a2aa..b48e1caf 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: 19-Feb-26 at 01:08:50 by Bob Weiner +;; Last-Mod: 19-Feb-26 at 19:29:13 by Bob Weiner ;; ;; SPDX-License-Identifier: GPL-3.0-or-later ;; @@ -945,9 +945,10 @@ Function used to display is \"hywiki-display- \"." (defun hywiki-display-referent (&optional wikiword prompt-flag) "Display HyWiki WIKIWORD referent or a regular file with WIKIWORD nil. Return the WIKIWORD's referent if successfully found or nil otherwise. -The referent is a cons of ( . ). + For further details, see documentation for `hywiki-find-referent'. After successfully finding a referent, run `hywiki-display-referent-hook'." + (interactive (list (hywiki-read-page-reference))) (let ((in-page-flag (null wikiword)) (in-hywiki-directory-flag (hywiki-in-page-p))) (if (or (stringp wikiword) in-hywiki-directory-flag) @@ -1399,16 +1400,15 @@ After successfully adding a page, run `hywiki-add-page-hook'. Use `hywiki-get-referent' to determine whether a HyWiki page exists." (interactive (list (or (hywiki-word-at) - (hywiki-word-read-new "Add/Edit HyWiki page: ")) + (hywiki-page-read-new "Add/Edit HyWiki page: ")) current-prefix-arg)) (if (hywiki-word-is-p page-name) (when (or noninteractive (not (hash-empty-p (hywiki-get-referent-hasht))) (hyperb:stack-frame '(ert-run-test)) (y-or-n-p (concat "Create new HyWiki page `" page-name "'? "))) - (when (match-string-no-properties 2 page-name) - ;; Remove any #section suffix in PAGE-NAME. - (setq page-name (match-string-no-properties 1 page-name))) + ;; Remove any #section suffix in PAGE-NAME. + (setq page-name (hywiki-get-singular-wikiword page-name)) (let* ((page-file (hywiki-get-page-file page-name)) (page-file-readable (file-readable-p page-file)) @@ -1647,7 +1647,7 @@ nil, else return \\='(page . \" \")." (and (or at-tag-flag (hsys-org-at-tags-p)) (or (hywiki-in-page-p) (string-prefix-p "*HyWiki Tags*" (buffer-name))))) -(defun hywiki-consult-file-and-line () +(defun hywiki-consult-page-and-line () "Return a list of the file and line selected by consult or nil. Use `hywiki-insert-reference' with the result of this function to insert a double-quoted HyWikiWord reference at point." @@ -2077,15 +2077,20 @@ This includes the delimiters: (), {}, <>, [] and \"\" (double quotes)." result (list nil nil)))))) +(defun hywiki-read-page-reference () + "With consult package loaded, read a \"file^@line\" string, else a page name." + (interactive) + (if (featurep 'consult) + (hywiki-format-reference (hywiki-consult-page-and-line)) + ;; Without consult, can only complete to a HyWiki page + ;; without a section + (hywiki-page-read "Link to HyWiki page: "))) + ;;;###autoload (defun hywiki-insert-link () - "Insert at point a link to a HyWiki page." + "Insert at point a link to a HyWiki page#section." (interactive "*") - (let ((ref (if (featurep 'consult) - (hywiki-format-reference (hywiki-consult-file-and-line)) - ;; Without consult, can only complete to a WikiWord - ;; without a section - (hywiki-word-read "Link to HyWiki page: ")))) + (let ((ref (hywiki-read-page-reference))) (when ref (insert ref) (skip-chars-backward "\"") @@ -2094,7 +2099,8 @@ This includes the delimiters: (), {}, <>, [] and \"\" (double quotes)." ;;;###autoload (defun hywiki-format-reference (page-and-line) - "Return a HyWikiWord#section reference, PAGE-AND-LINE, from `consult-grep'. + "Return a HyWikiWord#section reference from PAGE-AND-LINE. +Call `hywiki-consult-page-and-line' to generate PAGE-AND-LINE. Add double quotes if the section contains any whitespace after trimming. Return t if PAGE-AND-LINE is a valid list, else nil. If the page name @@ -2103,7 +2109,8 @@ therein is invalid, trigger an error." (cl-destructuring-bind (page line) page-and-line (setq page (file-name-base page)) - (when (not (string-match-p hywiki-word-regexp page)) + (unless (and (string-match-p hywiki-word-regexp page) + (hywiki-page-exists-p page)) (error "(hywiki-format-reference): Invalid HyWiki page name - \"%s\"" page)) ;; Drop '* ' prefix @@ -2115,7 +2122,7 @@ therein is invalid, trigger an error." line)))) (defun hywiki-insert-reference (page-and-line) - "Insert a HyWikiWord#section reference, PAGE-AND-LINE, from `consult-grep'. + "Insert a HyWiki page#section reference from PAGE-AND-LINE. Add double quotes if the section contains any whitespace after trimming. Return t if PAGE-AND-LINE is a valid list, else nil. If the page name @@ -3816,7 +3823,7 @@ Return nil if WORD is a prefixed, typed hy:HyWikiWord, since these are handled by the Org mode link handler." (and (stringp word) (not (string-empty-p word)) (let (case-fold-search) - (and (or (string-match-p hywiki-word-with-optional-suffix-exact-regexp word) + (and (or (string-match hywiki-word-with-optional-suffix-exact-regexp word) ;; For now this next version allows spaces and tabs in ;; the suffix part (eq 0 (string-match @@ -3824,7 +3831,7 @@ these are handled by the Org mode link handler." word))) ;; If has a #section, ensure there are no invalid chars (if (string-match-p "#" word) - (string-match-p "#[^][#()<>{}\"\n\r\f]+\\'" word) + (string-match "#[^][#()<>{}\"\n\r\f]+\\'" word) t))))) (defun hywiki-word-read (&optional prompt) @@ -3843,13 +3850,35 @@ If point is on one, press RET immediately to use that one." (hywiki-get-referent-hasht) nil nil nil nil (hywiki-word-at-point)))) -(defun hywiki-page-read-new (&optional prompt) - "Prompt with completion for and return an existing/new HyWikiWord with a page. +(defun hywiki-page-exists-p (word) + "Return HyWiki WORD iff it is an existing page reference." + (when (eq (car (hywiki-get-referent word)) 'page) + word)) + +(defun hywiki-page-read (&optional prompt) + "Prompt with completion for and return an existing HyWiki page name. If point is on one, press RET immediately to use that one." - (let ((completion-ignore-case t)) - (completing-read (if (stringp prompt) prompt "HyWikiWord page: ") + (let* ((completion-ignore-case t) + (wikiword (hywiki-word-at-point)) + (page (hywiki-page-exists-p wikiword))) + (completing-read (if (stringp prompt) prompt "HyWiki page: ") (hywiki-get-page-list) - nil nil nil nil (hywiki-word-at-point)))) + nil t nil nil (when page wikiword)))) + +(defun hywiki-page-read-new (&optional prompt) + "Prompt with completion for and return an existing/new HyWiki page name. +If point is on one, press RET immediately to use that one." + (let ((completion-ignore-case t) + page) + (while (null page) + (setq page (completing-read + (if (stringp prompt) prompt "HyWiki page: ") + (hywiki-get-page-list) + nil nil nil nil (hywiki-word-at-point))) + ;; Prevent selection of non-page HyWikiWords + (unless (memq (car (hywiki-get-referent page)) '(page nil)) + (setq page nil))) + page)) (defun hywiki-word-set-auto-highlighting (hywiki-from-mode hywiki-to-mode) "Set HyWikiWord auto-highlighting based on HYWIKI-FROM-MODE HYWIKI-TO-MODE. @@ -3966,12 +3995,7 @@ completion or no completion xandidates are returned." (defact link-to-wikiword (reference) "Display the HyWikiword referent matching WikiWord#section REFERENCE." - (interactive (list - (if (featurep 'consult) - (hywiki-format-reference (hywiki-consult-file-and-line)) - ;; Without consult, can only complete to a WikiWord - ;; without a section - (hywiki-word-read "Link to HyWiki page: ")))) + (interactive (list (hywiki-word-read "Link to HyWiki word: "))) (hywiki-find-referent reference)) ;;; ************************************************************************ From 447b83c2ca402bd4285bc3d097ed1ed1bc7c37bb Mon Sep 17 00:00:00 2001 From: bw Date: Thu, 19 Feb 2026 21:41:59 -0500 Subject: [PATCH 4/4] ibtypes::action - Fix to check for angle bracket delimiters. hui:link-possible-types - Fix to include link-to-wikiword only if an existing referent is found. --- ChangeLog | 5 ++ hibtypes.el | 206 ++++++++++++++++++++++++++-------------------------- hui.el | 4 +- 3 files changed, 111 insertions(+), 104 deletions(-) diff --git a/ChangeLog b/ChangeLog index 597f9e41..4d4c3198 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2026-02-19 Bob Weiner +* hui.el (hui:link-possible-types): Fix to include link-to-wikiword only if + an existing referent is found. + +* hibtypes.el (action): Fix to check for angle bracket delimiters. + * hywiki.el (hywiki-read-page-reference): Add and use in 'interactive' calls of several functions. (hywiki-word-is-p): Revert to using all 'string-match' calls diff --git a/hibtypes.el b/hibtypes.el index 61aa356a..1786e178 100644 --- a/hibtypes.el +++ b/hibtypes.el @@ -3,7 +3,7 @@ ;; Author: Bob Weiner ;; ;; Orig-Date: 19-Sep-91 at 20:45:31 -;; Last-Mod: 16-Feb-26 at 18:46:40 by Bob Weiner +;; Last-Mod: 19-Feb-26 at 21:16:16 by Bob Weiner ;; ;; SPDX-License-Identifier: GPL-3.0-or-later ;; @@ -1608,110 +1608,112 @@ first identifier in the expression must be an Elisp variable, action type, function symbol to call or test to execute, i.e. '<'actype-or-elisp-symbol arg1 ... argN '>'. For example, ." - (let ((hbut:max-len 0) - (lbl-key (hattr:get 'hbut:current 'lbl-key)) - (name (hattr:get 'hbut:current 'name)) + (let ((lbl-key (hattr:get 'hbut:current 'lbl-key)) (start-pos (hattr:get 'hbut:current 'lbl-start)) - (end-pos (hattr:get 'hbut:current 'lbl-end)) - (testing-flag (when (bound-and-true-p ert--running-tests) t)) - actype actype-sym action args lbl var-flag) - - ;; Continue only if there if there is a button label and one of: - ;; 1. `ert--running-tests' is non-nil - ;; 2. character after start-delim is not a whitespace character + (end-pos (hattr:get 'hbut:current 'lbl-end))) (when (and lbl-key - (or testing-flag - (not (memq (if (char-after (1+ start-pos)) - (char-syntax (char-after (1+ start-pos))) - 0) - '(?\ ?\>))))) - (setq lbl (ibut:key-to-label lbl-key)) - ;; Handle $ preceding var name in cases where same name is - ;; bound as a function symbol - (when (string-match "\\`\\$" lbl) - (setq var-flag t - lbl (substring lbl 1))) - (setq actype (if (string-match-p " " lbl) (car (split-string lbl)) lbl) - actype-sym (or (actype:elisp-symbol actype) (intern-soft actype)) - ;; Must ignore that (boundp nil) would be t here. - actype (and actype-sym - (or (fboundp actype-sym) (boundp actype-sym) - (special-form-p actype-sym) - (ert-test-boundp actype-sym)) - actype-sym)) - (when actype - ;; For buttons, need to double quote each argument so - ;; 'read' does not change the idstamp 02 to 2. - (when (and (memq actype '(hy hynote)) - (string-match-p " " lbl)) - (setq lbl (replace-regexp-in-string "\"\\(.*\\)\\'" "\\1\"" - (combine-and-quote-strings - (split-string lbl) "\" \"")))) - (setq action (read (concat "(" lbl ")")) - args (cdr action)) - ;; Ensure action uses an fboundp symbol if executing a - ;; Hyperbole actype. - (when (and (car action) (symbolp (car action))) - (setcar action (or (symtable:hyperbole-actype-p (car action)) - (car action)))) - (unless assist-flag - (cond ((and (symbolp actype) (fboundp actype) - (string-match "-p\\'" (symbol-name actype))) - ;; Is a function with a boolean result - (setq actype #'display-boolean - args `(',action))) - ((and (null args) (symbolp actype) (boundp actype) - (or var-flag (not (fboundp actype)))) - ;; Is a variable, display its value as the action - (setq args `(,actype) - actype #'display-variable)) - ((and (null args) (symbolp actype) (ert-test-boundp actype)) - ;; Is an ert-deftest, display the value from executing it - (setq actype #'display-value - args `((hypb-ert-run-test ,lbl)))) - (t - ;; All other expressions, display the action result in the minibuffer - (if (string-match "\\b\\(delete\\|kill\\)-region\\'" - (symbol-name actype-sym)) - ;; With `delete-region' and `kill-region' - ;; actions, if no args, either use any active - ;; region or when none, use the region of the - ;; action button itself, removing it from the - ;; buffer. The latter action is largely used - ;; only in internal HyWiki tests. - (progn (setq actype #'display-value) - (if (= 1 (length action)) ;; No args - (if (use-region-p) - ;; Apply function to the active region - (setq args `((,actype-sym (region-beginning) (region-end)))) - ;; Apply function to region of the action button itself, - ;; including delimiters - (setq args `((,actype-sym ,start-pos - ,end-pos)))) - (setq args `(',action)))) - (if testing-flag - ;; Delete action button after activation when - ;; running an ert test or in a string (so can - ;; test this behavior interactively), - (setq actype #'display-value-and-remove-region - args `(,action ,start-pos ,end-pos)) + (eq (char-after start-pos) ?\<) + (eq (char-before end-pos) ?\>)) + (let ((hbut:max-len 0) + (name (hattr:get 'hbut:current 'name)) + (testing-flag (when (bound-and-true-p ert--running-tests) t)) + actype actype-sym action args lbl var-flag) + + ;; Continue only if there if there is one of: + ;; 1. `ert--running-tests' is non-nil + ;; 2. character after start-delim is not a whitespace character + (when (and (or testing-flag + (not (memq (if (char-after (1+ start-pos)) + (char-syntax (char-after (1+ start-pos))) + 0) + '(?\ ?\>))))) + (setq lbl (ibut:key-to-label lbl-key)) + ;; Handle $ preceding var name in cases where same name is + ;; bound as a function symbol + (when (string-match "\\`\\$" lbl) + (setq var-flag t + lbl (substring lbl 1))) + (setq actype (if (string-match-p " " lbl) (car (split-string lbl)) lbl) + actype-sym (or (actype:elisp-symbol actype) (intern-soft actype)) + ;; Must ignore that (boundp nil) would be t here. + actype (and actype-sym + (or (fboundp actype-sym) (boundp actype-sym) + (special-form-p actype-sym) + (ert-test-boundp actype-sym)) + actype-sym)) + (when actype + ;; For buttons, need to double quote each argument so + ;; 'read' does not change the idstamp 02 to 2. + (when (and (memq actype '(hy hynote)) + (string-match-p " " lbl)) + (setq lbl (replace-regexp-in-string "\"\\(.*\\)\\'" "\\1\"" + (combine-and-quote-strings + (split-string lbl) "\" \"")))) + (setq action (read (concat "(" lbl ")")) + args (cdr action)) + ;; Ensure action uses an fboundp symbol if executing a + ;; Hyperbole actype. + (when (and (car action) (symbolp (car action))) + (setcar action (or (symtable:hyperbole-actype-p (car action)) + (car action)))) + (unless assist-flag + (cond ((and (symbolp actype) (fboundp actype) + (string-match "-p\\'" (symbol-name actype))) + ;; Is a function with a boolean result + (setq actype #'display-boolean + args `(',action))) + ((and (null args) (symbolp actype) (boundp actype) + (or var-flag (not (fboundp actype)))) + ;; Is a variable, display its value as the action + (setq args `(,actype) + actype #'display-variable)) + ((and (null args) (symbolp actype) (ert-test-boundp actype)) + ;; Is an ert-deftest, display the value from executing it (setq actype #'display-value - args `(,action))))))) - - ;; Create implicit button object and store in symbol hbut:current. - (ibut:label-set lbl) - (ibut:create :name name :lbl-key lbl-key :lbl-start start-pos - :lbl-end end-pos :categ 'ibtypes::action :actype actype - :args args) - - ;; Necessary so can return a null value, which actype:act cannot. - (let ((hrule:action - (if (eq hrule:action #'actype:identity) - #'actype:identity - #'actype:eval))) - (if (eq hrule:action #'actype:identity) - `(hact ',actype ,@args) - `(hact ',actype ,@(mapcar #'eval args)))))))) + args `((hypb-ert-run-test ,lbl)))) + (t + ;; All other expressions, display the action result in the minibuffer + (if (string-match "\\b\\(delete\\|kill\\)-region\\'" + (symbol-name actype-sym)) + ;; With `delete-region' and `kill-region' + ;; actions, if no args, either use any active + ;; region or when none, use the region of the + ;; action button itself, removing it from the + ;; buffer. The latter action is largely used + ;; only in internal HyWiki tests. + (progn (setq actype #'display-value) + (if (= 1 (length action)) ;; No args + (if (use-region-p) + ;; Apply function to the active region + (setq args `((,actype-sym (region-beginning) (region-end)))) + ;; Apply function to region of the action button itself, + ;; including delimiters + (setq args `((,actype-sym ,start-pos + ,end-pos)))) + (setq args `(',action)))) + (if testing-flag + ;; Delete action button after activation when + ;; running an ert test or in a string (so can + ;; test this behavior interactively), + (setq actype #'display-value-and-remove-region + args `(,action ,start-pos ,end-pos)) + (setq actype #'display-value + args `(,action))))))) + + ;; Create implicit button object and store in symbol hbut:current. + (ibut:label-set lbl) + (ibut:create :name name :lbl-key lbl-key :lbl-start start-pos + :lbl-end end-pos :categ 'ibtypes::action :actype actype + :args args) + + ;; Necessary so can return a null value, which actype:act cannot. + (let ((hrule:action + (if (eq hrule:action #'actype:identity) + #'actype:identity + #'actype:eval))) + (if (eq hrule:action #'actype:identity) + `(hact ',actype ,@args) + `(hact ',actype ,@(mapcar #'eval args)))))))))) (defun action:help (hbut) "Display documentation for action button at point. diff --git a/hui.el b/hui.el index 3a2f5571..3486e7a8 100644 --- a/hui.el +++ b/hui.el @@ -3,7 +3,7 @@ ;; Author: Bob Weiner ;; ;; Orig-Date: 19-Sep-91 at 21:42:03 -;; Last-Mod: 19-Feb-26 at 01:08:15 by Bob Weiner +;; Last-Mod: 19-Feb-26 at 21:32:21 by Bob Weiner ;; ;; SPDX-License-Identifier: GPL-3.0-or-later ;; @@ -2038,7 +2038,7 @@ Buffer without File link-to-buffer-tmp" lbl-key) (prog1 (delq nil (list (cond ((let ((ref (hywiki-referent-exists-p))) - (list 'link-to-wikiword ref))) + (and ref (list 'link-to-wikiword ref)))) ((and (featurep 'org-id) (cond ((save-excursion (beginning-of-line)