diff --git a/ChangeLog b/ChangeLog index 25eec058..5b1a2ebd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2026-07-10 Bob Weiner +* hywiki.el (hywiki-word-at-point, hywiki-word-at): Add to doc that point may + be immediately after the HyWikiWord reference and it will be found. + (hywiki-add-denote, hywiki-create-referent-and-display): Update + wikiword insertion logic to never insert within non-whitespace text. + Expand doc string and include return value. + +* hypb.el (hypb:require-package): Add support for alternative package managers + like elpaca that don't show up with a `package-installed-p' check. + * hpath.el (hpath:at-p): Near the top, move (match-string 0 path) call before path is modified, otherwise, with a 1 char path, shrunk to an empty string, match-path will trigger an error; fixes this. diff --git a/hypb.el b/hypb.el index 24a0577b..2c34d3f8 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: 28-Jun-26 at 13:28:33 by Bob Weiner +;; Last-Mod: 10-Jul-26 at 17:16:28 by Bob Weiner ;; ;; SPDX-License-Identifier: GPL-3.0-or-later ;; @@ -1170,18 +1170,22 @@ WINDOW pixelwise." dirs) ;;;###autoload -(defun hypb:require-package (package-name) +(defun hypb:require-package (package) "Prompt user to install, if necessary, and require the Emacs PACKAGE-NAME. PACKAGE-NAME may be a symbol or a string." - (when (stringp package-name) - (setq package-name (intern package-name))) - (unless (symbolp package-name) - (error "(hypb:require-package): package-name must be a symbol or string, not '%s'" package-name)) - (unless (package-installed-p package-name) - (if (y-or-n-p (format "Install package `%s' required by this command?" package-name)) - (package-install package-name) + (when (stringp package) + (setq package (intern package))) + (unless (symbolp package) + (error "(hypb:require-package): package must be a symbol or string, not '%s'" package)) + (unless (or + ;; Allow for alternative package managers like elpaca that don't + ;; show up with a `package-installed-p' check + (require package nil t) + (package-installed-p package)) + (if (y-or-n-p (format "Install package `%s' required by this command?" package)) + (package-install package) (keyboard-quit))) - (require package-name)) + (require package)) ;; Adapted from cl--do-remf in "cl-extra.el" but uses 'equal' for comparisons. ;;;###autoload diff --git a/hywiki.el b/hywiki.el index 290cfd55..f01a5fad 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: 10-Jul-26 at 12:24:52 by Bob Weiner +;; Last-Mod: 10-Jul-26 at 21:05:58 by Bob Weiner ;; ;; SPDX-License-Identifier: GPL-3.0-or-later ;; @@ -1317,34 +1317,45 @@ calling this function." (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. +WIKIWORD to any wikiword at or immediately before point; otherwise, convert +the description from the denote file chosen to be the WIKIWORD and insert +that after any non-whitespace text at point. After successfully adding the link to a denote file, run `hywiki-add-referent-hook'. +Return the WIKIWORD referent if WIKIWORD is of valid format, otherwise +return nil. The referent is a cons of (denote-description . denote-id). + Use `hywiki-get-referent' to determine whether WIKIWORD exists prior to calling this function." - (interactive (list (hywiki-word-at))) + (interactive (list nil)) (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))))) + (let ((at-wikiword-reference (hywiki-word-at))) + (unless (and (stringp wikiword) (not (string-empty-p wikiword))) + (setq wikiword at-wikiword-reference)) + (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 (and (stringp wikiword) (not (string-empty-p wikiword))) + (setq wikiword (hywiki-string-to-wikiword denote-desc))) + (unless (hyperb:stack-frame '(hywiki-create-referent-and-display)) + (unless (equal (hywiki-get-singular-wikiword wikiword) + (hywiki-get-singular-wikiword at-wikiword-reference)) + (if buffer-read-only + (error "(hywiki-add-denote): Read-only buffer; call this with point on: \"%s\"" wikiword) + (skip-syntax-forward "^-") + (unless (or (bolp) (= (char-syntax (preceding-char)) ?\ )) + (insert " ")) + (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)) @@ -1784,16 +1795,21 @@ for WIKIWORD, add a page for it. Use `hywiki-get-referent' to determine whether a HyWikiWord referent or page exists." (interactive (list nil current-prefix-arg)) - (let (at-wikiword-flag) + (let ((at-wikiword-reference (hywiki-word-at))) (unless (stringp wikiword) - (setq wikiword (or (setq at-wikiword-flag (hywiki-word-at)) + (setq wikiword (or at-wikiword-reference (hywiki-word-read-new (format "Add/Edit and display HyWiki %s: " (if current-prefix-arg "referent" "page")))))) - (unless at-wikiword-flag + (unless (equal (hywiki-get-singular-wikiword wikiword) + (hywiki-get-singular-wikiword at-wikiword-reference)) (if buffer-read-only - (error "(hywiki-create-referent-and-display): Since buffer is read-only, this must be used with point on a HyWikiWord") + (error "(hywiki-create-referent-and-display): Read-only buffer; call this with point on: \"%s\"" wikiword) + (skip-syntax-forward "^-") + (unless (or (bolp) (= (char-syntax (preceding-char)) ?\ )) + (insert " ")) (insert wikiword))) + (when (and (not prompt-flag) hywiki-referent-prompt-flag (called-interactively-p 'interactive)) (setq prompt-flag t)) @@ -2946,8 +2962,11 @@ the current page unless they have sections attached." "Highlight each non-Org link HyWiki page#section in the current buffer/region. With optional REGION-START and REGION-END positions or markers (active region interactively), limit highlight adjustment to the region. With -optional SKIP-LOOKUPS-UPDATE-FLAG non-nil, HyWiki lookup tables -should have already been updated and this is skipped. +optional SKIP-LOOKUPS-UPDATE-FLAG non-nil, HyWiki lookup tables should have +already been updated and this is skipped. + +Called by `find-file' without a region to highlight HyWikiWords when a file +buffer is first read in to an Emacs session. Use `hywiki-word-face' to highlight. Do not highlight references to the current page unless they have sections attached. @@ -3159,27 +3178,27 @@ Always exclude minibuffer windows." (window-list frame :no-minibuf)))) (or frames (frame-list)))))) -(defun hywiki-get-existing-page-file (file-stem-name) - "Return existing `hywiki-directory' path from FILE-STEM-NAME or nil. -FILE-STEM-NAME should not contain a directory and may have or may omit +(defun hywiki-get-existing-page-file (reference) + "Return existing `hywiki-directory' path from REFERENCE or nil. +REFERENCE should not contain a directory and may have or may omit `hywiki-file-suffix' and an optional trailing #section. -Checks only that FILE-STEM-NAME is not nil, not an empty string and does +Checks only that REFERENCE is not nil, not an empty string and does not contain a directory path or returns nil." (make-directory hywiki-directory t) - (unless (or (null file-stem-name) - (eq file-stem-name t) ;; HyWikiWord spec - (string-empty-p file-stem-name) - (file-name-directory file-stem-name)) + (unless (or (null reference) + (eq reference t) ;; HyWikiWord spec + (string-empty-p reference) + (file-name-directory reference)) (let (file-name referent section) - ;; Remove any suffix from `file-stem-name' and make it singular - (if (string-match hywiki-word-suffix-regexp file-stem-name) - (setq section (match-string 0 file-stem-name) + ;; Remove any suffix from `reference' and make it singular + (if (string-match hywiki-word-suffix-regexp reference) + (setq section (match-string 0 reference) file-name (hywiki-get-singular-wikiword - (substring file-stem-name 0 (match-beginning 0)))) - (setq file-name file-stem-name)) + (substring reference 0 (match-beginning 0)))) + (setq file-name reference)) (setq referent (hywiki-get-referent file-name)) (when (and (eq (car referent) 'page) ;; The referent replaces the page name with name.org, so can be next. @@ -3187,27 +3206,30 @@ not contain a directory path or returns nil." (file-exists-p file-name)) (concat file-name section))))) -(defun hywiki-get-page-file (file-stem-name) - "Return possibly non-existent `hywiki-directory' path from FILE-STEM-NAME. -FILE-STEM-NAME may be an existing absolute file path; then, return it. -Otherwise, FILE-STEM-NAME should not contain a directory and may have or may -omit `hywiki-file-suffix' and an optional trailing #section. +(defun hywiki-get-page-file (reference) + "Return possibly non-existent `hywiki-directory' path from REFERENCE. +REFERENCE may be an existing absolute file path; then, return it. +Otherwise, REFERENCE should not contain a directory and may have or may +omit `hywiki-file-suffix' and an optional trailing #section, both of which +are left attached to the result returned. So given the input, +WikiWord#section, the result might be: +\"/users/me/hywiki/WikiWord.org#section\". -Checks only that FILE-STEM-NAME is not nil, not an empty string and does +Checks only that REFERENCE is not nil, not an empty string and does not contain a directory path or returns nil." (make-directory hywiki-directory t) - (if (and (stringp file-stem-name) (file-readable-p file-stem-name)) - file-stem-name - (unless (or (null file-stem-name) (string-empty-p file-stem-name) - (file-name-directory file-stem-name)) + (if (and (stringp reference) (file-readable-p reference)) + reference + (unless (or (null reference) (string-empty-p reference) + (file-name-directory reference)) (let (file-name section) - ;; Remove any suffix from `file-stem-name' and make it singular - (if (string-match hywiki-word-suffix-regexp file-stem-name) - (setq section (match-string 0 file-stem-name) + ;; Remove any suffix from `reference' and make it singular + (if (string-match hywiki-word-suffix-regexp reference) + (setq section (match-string 0 reference) file-name (hywiki-get-singular-wikiword - (substring file-stem-name 0 (match-beginning 0)))) - (setq file-name file-stem-name)) + (substring reference 0 (match-beginning 0)))) + (setq file-name reference)) (concat (expand-file-name file-name hywiki-directory) (unless (string-suffix-p hywiki-file-suffix file-name) hywiki-file-suffix) @@ -3967,6 +3989,7 @@ Action Key press; with a prefix ARG, emulate an Assist Key press." (defun hywiki-word-at (&optional range-flag hash-sign-only-flag) "Return potential HyWikiWord and optional #section:Lnum:Cnum at point or nil. +Point may be on or immediately after the HyWikiWord reference. `hywiki-mode' must be enabled or this will return nil. If the HyWikiWord is delimited, point must be within the delimiters. @@ -4266,8 +4289,9 @@ Return t if the highlighted range exists at point and gets moved." (defun hywiki-word-at-point () "Return singular HyWikiWord at point with its suffix stripped or nil. -Point should be on the HyWikiWord itself. Suffix is anything after -the # symbol. +Point may be on or immediately after the HyWikiWord itself. `hywiki-mode' +must be enabled or this will return nil. Suffix is anything after the # +symbol. This does not test whether a referent exists for the HyWikiWord; call `hywiki-referent-exists-p' without an argument for that.