Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
2026-07-10 Bob Weiner <rsw@gnu.org>

* hywiki.el (hywiki-referent-menu): Add Denote support.
(hywiki-add-denote, hywiki-display-denote, hywiki-string-to-wikiword)
hywiki-denote-file-to-wikiword, hywiki-denote-id-to-wikiword): Add
these functions.
(hywiki-create-referent-and-display): If point is not on 'wikiword'
when called, then insert it. If buffer is read-only in this case, trigger
an error.

2026-07-07 Bob Weiner <rsw@gnu.org>

* hsys-youtube.el (hsys-youtube-end-format): YouTube no longer allows end times or the
Expand Down
8 changes: 4 additions & 4 deletions hactypes.el
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
;; Author: Bob Weiner
;;
;; Orig-Date: 23-Sep-91 at 20:34:36
;; Last-Mod: 28-Jun-26 at 09:48:58 by Bob Weiner
;; Last-Mod: 10-Jul-26 at 12:29:32 by Bob Weiner
;;
;; SPDX-License-Identifier: GPL-3.0-or-later
;;
Expand Down Expand Up @@ -536,11 +536,11 @@ the .info suffix in the format with parentheses."
(id-info string)
(hypb:error "(link-to-Info-node): Invalid Info node: `%s'" string)))

(defact link-to-ibut (name-key &optional key-src point)
"Activate implicit button given by NAME-KEY, optional KEY-SRC and POINT.
(defact link-to-ibut (name-key &optional key-src _point)
"Activate implicit button given by NAME-KEY, optional KEY-SRC and _POINT.
NAME-KEY must be a normalized key for an ibut <[name]>.
KEY-SRC defaults to the current buffer's file or if there is no
attached file, then to its buffer name. POINT defaults to the
attached file, then to its buffer name. _POINT defaults to the
current point.

When the button with this action type is created, point must be
Expand Down
35 changes: 20 additions & 15 deletions hbut.el
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
;; Author: Bob Weiner
;;
;; Orig-Date: 18-Sep-91 at 02:57:09
;; Last-Mod: 25-Jun-26 at 17:06:59 by Bob Weiner
;; Last-Mod: 10-Jul-26 at 12:26:12 by Bob Weiner
;;
;; SPDX-License-Identifier: GPL-3.0-or-later
;;
;; Copyright (C) 1991-2025 Free Software Foundation, Inc.
;; Copyright (C) 1991-2026 Free Software Foundation, Inc.
;; See the "HY-COPY" file for license information.
;;
;; This file is part of GNU Hyperbole.
Expand Down Expand Up @@ -82,10 +82,21 @@ Use the function, (hbut:max-len), to read the proper value.")
;; Move up internal defconst to appear before their use
(defconst ebut:label-start "<("
"String matching the start of a Hyperbole explicit hyper-button.")

(defconst ebut:label-end ")>"
"String matching the end of a Hyperbole explicit hyper-button.")

(defconst ibut:label-start "<["
"String matching the start of a Hyperbole implicit button optional name.")
(defconst ibut:label-end "]>"
"String matching the end of a Hyperbole implicit button optional name.")

(defconst hbut:label-delimiters-regexp
(format (concat "%s[^][()<>\"]+\\([\n\r][^][()<>\"]*\\)?%s"
"\\|%s[^][()<>\"]+\\([\n\r][^][()<>\"]*\\)?%s")
(regexp-quote ibut:label-start) (regexp-quote ibut:label-end)
(regexp-quote ebut:label-start) (regexp-quote ebut:label-end))
"Regular expression matching ibut names and ebut text/labels.")

(defconst hbut:instance-sep ":"
"String of one character, separates an ebut label from its instance num.")

Expand Down Expand Up @@ -2172,9 +2183,6 @@ If a new button is created, store its attributes in the symbol,
[&optional ["&optional" arg &rest arg]]
&optional ["&rest" arg])))

(defvar ibut:label-start)
(defvar ibut:label-end)

(defun ibut:delete (&optional but-sym)
"Delete Hyperbole implicit button based on optional BUT-SYM.
If it is a named button, delete all occurrences in the buffer; otherwise, delete
Expand Down Expand Up @@ -3031,12 +3039,6 @@ Return the symbol for the button if found, else nil."
(when (ibut:is-p ibut)
(hattr:get ibut 'categ)))

;;; ------------------------------------------------------------------------
(defconst ibut:label-start "<["
"String matching the start of a Hyperbole implicit button optional name.")
(defconst ibut:label-end "]>"
"String matching the end of a Hyperbole implicit button optional name.")

;;; ========================================================================
;;; ibtype class - Implicit button types
;;; ========================================================================
Expand Down Expand Up @@ -3133,9 +3135,12 @@ regular expression. Hyperbole automatically creates a doc string
for the type but you can override this by providing an optional
DOC string.

TEXT-REGEXP must match to the text found between a button's delimiters
in order for this type to activate. The matched text is applied
to LINK-EXPR to produce the link's referent, which is then displayed.
TEXT-REGEXP must match to part of the text found between a button's
delimiters in order for this type to activate; to ensure it matches
to the full text, start the REGEXP with \"\\`\" and end it with
\"\\'\", to match to the start and end of string. The matched text
is applied to LINK-EXPR to produce the link's referent, which is then
displayed.

LINK-EXPR may be:
(1) a brace-delimited key series;
Expand Down
137 changes: 114 additions & 23 deletions hywiki.el
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
;; Author: Bob Weiner
;;
;; Orig-Date: 21-Apr-24 at 22:41:13
;; Last-Mod: 28-Jun-26 at 18:53:13 by Bob Weiner
;; Last-Mod: 10-Jul-26 at 12:24:52 by Bob Weiner
;;
;; SPDX-License-Identifier: GPL-3.0-or-later
;;
Expand Down Expand Up @@ -170,9 +170,9 @@

(declare-function Info-current-filename-sans-extension "hui-mouse")
(declare-function Info-read-index-item-name "hui-mouse")
(declare-function activities-completing-read "activities" (:prompt prompt :default default))
(declare-function activities-new "activities" (name))
(declare-function activities-resume "activities" (activity :resetp resetp))
(declare-function activities-completing-read "ext:activities" (:prompt prompt :default default))
(declare-function activities-new "ext:activities" (name))
(declare-function activities-resume "ext:activities" (activity :resetp resetp))
(declare-function bookmark-completing-read "bookmark" (prompt &optional default))
(declare-function bookmark-location "bookmark" (bookmark-name-or-record))
(declare-function consult--async-command "ext:consult")
Expand All @@ -183,6 +183,11 @@
(declare-function consult--async-throttle "ext:consult")
(declare-function consult--lookup-member "ext:consult")
(declare-function consult--read "ext:consult")
(declare-function denote-file-prompt "ext:denote")
(declare-function denote-get-link-description "ext:denote")
(declare-function denote-get-path-by-id "ext:denote")
(declare-function denote-open-or-create "ext:denote")
(declare-function denote-retrieve-filename-identifier "ext:denote")
(declare-function hsys-org-at-tags-p "hsys-org")
(declare-function hyperbole-mode "hyperbole")
(declare-function hyrolo-fgrep "hyrolo")
Expand Down Expand Up @@ -1107,6 +1112,9 @@ After successfully finding a referent, run `hywiki-display-referent-hook'."
"Add a HyWikiWord that jumps to an Emacs bookmark.")
'("Command" (hywiki-add-command hkey-value)
"Add a HyWikiWord that runs an Emacs command or Hyperbole action type.")
(when (fboundp #'denote-open-or-create)
'("Denote" (hywiki-add-denote hkey-value)
"Add a HyWikiWord that jumps to a Denote note stored by ID."))
'("Elisp" (hywiki-add-elisp hkey-value)
"Add a HyWikiWord that evaluates an Elisp sexpression.")
'("Find" (hywiki-add-find hkey-value)
Expand Down Expand Up @@ -1307,6 +1315,54 @@ calling this function."
(t (error "(hywiki-display-command): Unbound referent command, '%s'"
command))))

(defun hywiki-add-denote (wikiword)
"Make WIKIWORD display a denote file when the `denote' package is available.

When called interactively or with WIKIWORD nil or the empty string, then set
WIKIWORD to any wikiword at point; otherwise, convert the description from
the denote file chosen to a wikiword.

After successfully adding the link to a denote file, run
`hywiki-add-referent-hook'.

Use `hywiki-get-referent' to determine whether WIKIWORD exists prior to
calling this function."
(interactive (list (hywiki-word-at)))
(hypb:require-package 'denote)
(let* ((denote-file (denote-file-prompt
nil
(if (stringp wikiword)
(format "Link `%s' HyWikiWord to denote" wikiword)
;; Will use denote file description as `wikiword'
"Add HyWikiWord denote link to")
nil t))
(denote-desc (denote-get-link-description denote-file))
(denote-id (denote-retrieve-filename-identifier denote-file)))
(unless (or (stringp wikiword) (string-empty-p wikiword))
(setq wikiword (hywiki-string-to-wikiword denote-desc)))
(unless (equal wikiword (hywiki-get-singular-wikiword (hywiki-word-at)))
(if buffer-read-only
(error "(hywiki-add-denote): Since buffer is read-only, this must be used with point on a HyWikiWord")
(insert wikiword)))
(hywiki-add-referent wikiword (cons 'denote (cons denote-desc denote-id)))))

(defun hywiki-display-denote (_wikiword denote-desc-and-id)
(let ((denote-desc (car denote-desc-and-id))
(denote-id (cdr denote-desc-and-id))
denote-file)
(cond ((not (stringp denote-id))
(error "(hywiki-display-denote): `denote-id' must be a string, not`%s'"
denote-id))
((and (setq denote-file (denote-get-path-by-id denote-id))
(file-readable-p denote-file))
(hpath:find denote-file))
((not (stringp denote-file))
(error "(hywiki-display-denote): denote file not found for desc: \"%s\", id: \"%s\""
denote-desc denote-id))
(t ;; denote-file not readable
(error "(hywiki-display-denote): Unreadable demote file: \"%s\""
denote-file)))))

(defun hywiki-add-elisp (wikiword)
"Make WIKIWORD evaluate a prompted for Elisp sexpression and return it.

Expand Down Expand Up @@ -1452,8 +1508,9 @@ calling this function."

(defun hywiki-add-org-id (wikiword)
"Make WIKIWORD display an Org file or headline with an Org id.
Point must be in the buffer with the id. If no id exists, it is created.
Return the referent created with the form: \\='(org-id . <id-string>).
Point must be within the entry with with the id. If no id exists, it is
created. Return the referent created with the form: \\='(org-id
. <id-string>).

If WIKIWORD is invalid, trigger an error if called interactively
or return nil if not.
Expand Down Expand Up @@ -1622,9 +1679,8 @@ After successfully adding the spec, run `hywiki-add-referent-hook'."
This replaces any existing referent the WIKIWORD may have.

With either `hywiki-referent-prompt-flag' set or optional prefix
REF-TYPE-FLAG, prompt for and choose a typed referent, otherwise, create
and/or display a HyWiki page. See `hywiki-referent-menu' for valid referent
types.
REF-TYPE-FLAG, prompt for and choose a typed referent, otherwise, create a
HyWiki page. See `hywiki-referent-menu' for valid referent types.

Use `hywiki-get-referent' to test for and retrieve an existing HyWikiWord
referent."
Expand Down Expand Up @@ -1727,21 +1783,27 @@ for WIKIWORD, add a page for it.

Use `hywiki-get-referent' to determine whether a HyWikiWord referent
or page exists."
(interactive (list (or (hywiki-word-at)
(hywiki-word-read-new
(interactive (list nil current-prefix-arg))
(let (at-wikiword-flag)
(unless (stringp wikiword)
(setq wikiword (or (setq at-wikiword-flag (hywiki-word-at))
(hywiki-word-read-new
(format "Add/Edit and display HyWiki %s: "
(if current-prefix-arg "referent" "page"))))
current-prefix-arg))
(when (and (not prompt-flag) hywiki-referent-prompt-flag
(called-interactively-p 'interactive))
(setq prompt-flag t))
(let* ((normalized-word (hywiki-get-singular-wikiword wikiword))
(referent (hywiki-find-referent wikiword prompt-flag)))
(cond (referent)
((hywiki-word-is-p normalized-word)
(when (hywiki-add-page normalized-word)
(hywiki-display-page normalized-word)))
(t (user-error "(hywiki-create-referent-and-display): Invalid HyWikiWord: '%s'; must be capitalized, all alpha" wikiword)))))
(if current-prefix-arg "referent" "page"))))))
(unless at-wikiword-flag
(if buffer-read-only
(error "(hywiki-create-referent-and-display): Since buffer is read-only, this must be used with point on a HyWikiWord")
(insert wikiword)))
(when (and (not prompt-flag) hywiki-referent-prompt-flag
(called-interactively-p 'interactive))
(setq prompt-flag t))
(let* ((normalized-word (hywiki-get-singular-wikiword wikiword))
(referent (hywiki-find-referent wikiword prompt-flag)))
(cond (referent)
((hywiki-word-is-p normalized-word)
(when (hywiki-add-page normalized-word)
(hywiki-display-page normalized-word)))
(t (user-error "(hywiki-create-referent-and-display): Invalid HyWikiWord: '%s'; must be capitalized, all alpha" wikiword))))))

(defun hywiki-display-page (&optional wikiword file-name)
"Display an optional WIKIWORD page and return the page file.
Expand Down Expand Up @@ -2020,6 +2082,26 @@ Use `hywiki-get-referent' to determine whether a HyWiki page exists."
"\[\(\{\<\"'`\t\n\r\f "))
(or (char-before) 0)))

(defun hywiki-denote-file-to-wikiword (denote-file)
"Return a hywikiword from the denote description associated with DENOTE-FILE."
(interactive
(list (denote-file-prompt nil "HyWiki denote file: "
nil t)))
(if denote-file
(hywiki-string-to-wikiword
(denote-get-link-description denote-file))
(error "(hywiki-denote-file-to-wikiword): Denote file not found: \"%s\""
denote-file)))

(defun hywiki-denote-id-to-wikiword (denote-id)
"Return a hywikiword from the denote description associated with DENOTE-ID."
(let ((denote-file (denote-get-path-by-id denote-id)))
(if denote-file
(hywiki-string-to-wikiword
(denote-get-link-description denote-file))
(error "(hywiki-denote-id-to-wikiword): Denote file not found for id: \"%s\""
denote-id))))

(defun hywiki-directory-edit ()
"Edit HyWiki pages in current `hywiki-directory'.
Use `dired' unless `action-key-modeline-buffer-id-function' is set to
Expand Down Expand Up @@ -3805,6 +3887,15 @@ contains no spaces."
(concat file (hpath:dashes-to-spaces-markup-anchor section)))
link)))

(defun hywiki-string-to-wikiword (str)
"Convert a string to a single PascalCase HyWikiWord.
Removes only whitespace, dashes and underscores. Capitalizes
each term in the string."
(unless (stringp str)
(error "(hywiki-string-to-wikiword): `str' must be a string, not `%s'" str))
(let ((words (split-string str "[-_ \t\n\r\f]+" t split-string-default-separators)))
(apply #'concat (mapcar #'capitalize words))))

(defun hywiki-strip-org-link (link-str)
"Return the hy:HyWikiWord#section part of an Org link string.
Strip any square bracket delimiters, description and leading or
Expand Down
Loading