branch: externals/hyperbole
commit c605e7d38512bb21efe1a56592893095a0420799
Author: bw <[email protected]>
Commit: bw <[email protected]>
hywiki.el - Add `hywiki-file' ibtype to display non-HyWikiWord files
This allows activation of wiki word-like hyperlinks (with optional
#section) for other Org notes files that don't follow wiki word naming
conventions, e.g. my-notes-file.org, once they are placed in
`hywiki-directory'.
Also fix `hywiki-word-at' to use 'hywiki-word-with-optional-section-regexp'
instead of 'hywiki-word-regexp' so handles sections properly.
Improve hywiki.el Commentary by immediately explaining how to use it and
summarizing the ibtypes it adds.
---
ChangeLog | 20 ++++++
hywiki.el | 194 ++++++++++++++++++++++++++++++++++-----------------
test/hywiki-tests.el | 6 +-
3 files changed, 154 insertions(+), 66 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 0dc444b2e7..aa71363878 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2024-06-22 Bob Weiner <[email protected]>
+
+* hywiki.el (hywiki-active-in-current-buffer-p): Fix to highlight HyWikiWords
+ in 'kotl-mode' which is a special class buffer.
+ (Commentary): Update this documentation, focusing on use.
+
+2024-06-21 Bob Weiner <[email protected]>
+
+* hywiki.el (hywiki-word-at): Fix to use
'hywiki-word-with-optional-section-regexp'
+ instead of 'hywiki-word-regexp' so handles sections properly.
+ (hywiki-word-highlight-flag): Improve documentation.
+ (hywiki-get-files, hywiki-get-file-stem-list, hywiki-find-file):
+ Add these functions to find non-HyWikiWord files in `hywiki-directory' when
+ referenced by stem name, e.g. Action key on Non-Wiki-Word displays
+ Non-Wiki-Word.org.
+ (hywiki-file): Add ibtype to display non-HyWikiWord files in
+ hywiki-directory'.
+ (hywiki-get-page-file): Allow name to include 'hywiki-file-suffix'
+ for non-HyWikiWord files. Also, rename to 'hywiki-get-file'.
+
2024-06-20 Mats Lidell <[email protected]>
* test/hywiki-tests.el (hywiki-tests--at-wikiword-finds-word-and-section)
diff --git a/hywiki.el b/hywiki.el
index e80eaa1fb7..57ac0d7076 100644
--- a/hywiki.el
+++ b/hywiki.el
@@ -14,34 +14,35 @@
;;; Commentary:
;;
-;; This is Hyperbole's markup-free personal Wiki system for
-;; note-taking and automatic wiki word hyperlinking.
-
-;; A `HyWikiWord' is a low-priority Hyperbole implicit button type
-;; (named hywiki-word) that starts with a capitalized letter and
-;; contains only upper and lowercase letters. Such words
-;; automatically link to `HyWiki pages', which are Org mode files
-;; with HyWikiWord names (the page name) plus a ".org" suffix, stored
-;; within the directory given by `hywiki-directory'. Such links are
-;; activated with a press of the Action Key {M-RET} within the link.
+;; This is Hyperbole's markup-free personal Wiki system for note-taking
+;; and automatic wiki word highlighting and hyperlinking. It uses Org
+;; mode for note taking and adds automatic hyperlinking of HyWikiWords
+;; within Org files in `hywiki-directory' (default = "~/hywiki"), where
+;; a HyWikiWord is a capitalized word that contains upper and lowercase
+;; letters only and has a corresponding HyWikiWord.org wiki page file
+;; below `hywiki-directory'. HyWikiWords require no delimiters.
+;;
+;; HyWikiWords are also recognized in text buffers after the global
+;; minor mode, `hywiki-mode' is enabled via {M-x hywiki-mode RET}. To
+;; create or jump to a HyWiki page, simply type out a potential
+;; HyWikiWord or move point onto one and press the Action Key {M-RET}.
+;; This will create the associated page if it does not exist. This
+;; also highlights any other instances of HyWikiWords across all
+;; visible Emacs windows. HyWiki is built for scalability and has been
+;; tested to be performant with 10,000 HyWikiWords.
;;
;; Once Hyperbole has been loaded and activated, HyWikiWords (with or
;; without delimiters) are automatically highlighted and active in
;; the following contexts:
;; - HyWiki page buffers;
-;; - non-special text buffers when `hywiki-mode' is enabled;
-;; - comments of programming buffers when `hywiki-mode' is enabled.
+;; - non-special text buffers, when `hywiki-mode' is enabled;
+;; - comments of programming buffers, when `hywiki-mode' is enabled.
;;
;; As HyWikiWords are typed, highlighting occurs after a trailing
;; whitespace or punctuation character is added, or when an opening
;; or closing parenthesis or curly brace is added to surround the
-;; HyWikiWord.
-;;
-;; To create a new HyWiki page or to jump to one, simply type a
-;; HyWikiWord in a valid context and then press the Action Key on it.
-;; If the associated page exists, jump to it. If it doesn't, create
-;; it and display its empty buffer for editing. editing. Highlight
-;; all visible Instances of the associated HyWikiWord as well.
+;; HyWikiWord. Since Org links use square brackets and Org targets
+;; use angle brackets, HyWikiWords within these delimiters are ignored.
;;
;; You can also create Org links to HyWikiWords in any non-special text
;; buffer by surrounding them with double square brackets and the
@@ -54,26 +55,18 @@
;; created, set `hsys-org-enable-smart-keys' to `t' so that
;; Hyperbole's Action Key does the right thing in this context.
;;
-;; HyWiki pages are created in `hywiki-directory'. Within such
-;; pages, HyWikiWords (the names of HyWiki pages) work without the need
-;; for any delimiters. Simply type them out, e.g. Emacs and if a
-;; page exists for the word, it is
-;; - a HyWiki page file is read in
-;; - a whitespace character, ')', '}', or Org-mode punctuation/symbol
-;; character is inserted following a HyWiki word
-;; - the Action Key is pressed to activate a HyWiki word button.
-;;
-;; HyWiki links can also link to a section headline within a page by
-;; simply following the page name with a '#' character and then the
-;; section headline name. For example, if your Emacs page has a
-;; "Major Modes" section, then either Emacs#Major-Modes or
-;; [[hy:Emacs#Major Modes]] will work as a link to that section.
-;; Note that without the square bracket delimiters, you must convert
-;; spaces in section names to '-' characters. As long as the page
-;; exists, section links are highlighted regardless of whether
-;; associated sections exist or not.
+;; HyWikiWord links can also link to a section headline within a page
+;; by simply following the page name with a '#' character and then the
+;; section headline name. For example, if your Emacs page has a "Major
+;; Modes" section, then either Emacs#Major-Modes or [[hy:Emacs#Major
+;; Modes]] will work as a link to that section. Note that without the
+;; square bracket delimiters, you must convert spaces in section names
+;; to '-' characters. As long as the page exists, section links are
+;; highlighted regardless of whether associated sections exist or not.
+;; When activating a link with a section reference, you will get an
+;; error if the section does not exist.
;;
-;; The custom setting, `hywiki-word-highlight-flag' (default = 't),
+;; The custom setting, `hywiki-word-highlight-flag' (default = t),
;; means HyWikiWords will be auto-highlighted within HyWiki pages.
;; Outside of such pages, `hywiki-mode' must also be enabled for such
;; auto-highlighting.
@@ -82,9 +75,24 @@
;; a list of major modes to exclude from HyWikiWord auto-highlighting
;; and recognition.
;;
-;; The custom setting, `hywiki-highlight-all-in-prog-modes' (default =
-;; '(lisp-interaction-mode)), is a list of programming major modes to
-;; highlight HyWikiWords outside of comments.
+;; Within programming modes, HyWikiWords are highlighted/hyperlinked
+;; within comments only. For programming modes in which you want
+;; HyWikiWords recognized everywhere, add them to the custom setting,
+;; `hywiki-highlight-all-in-prog-modes' (default =
+;; '(lisp-interaction-mode)).
+;;
+;; HyWiki adds two implicit button types to Hyperbole:
+;; `hywiki-word' creates and displays HyWikiWord pages;
+;; `hywiki-file' displays existing `hywiki-directory' non-HyWikiWord
+;; Org files that have been added manually. For example, if you
+;; add the file, my-file.org, there, you would be able to jump to it
+;; by adding 'my-file' anywhere that HyWikiWords are recognized. It
+;; won't be highlighted as it isn't a HyWikiWord but it behaves
+;; similarly when activated.
+;;
+;; These are the lowest priority implicit button types so they trigger
+;; only when other types are not recognized first. The hywiki-word
+;; type is recognized ahead of the hywiki-file type.
;;; Code:
;;; ************************************************************************
@@ -193,7 +201,7 @@ Otherwise, this prefix is not needed and HyWiki word Org
links
override standard Org link lookups. See \"(org)Internal Links\".")
(defvar-local hywiki-page-flag nil
- "Set to t when find file if the buffer file is a HyWiki page, else nil.
+ "Set to t after a `find-file' of a HyWiki page file, else nil.
The file must be below `hywiki-directory'.
For reference, this is set when `window-buffer-change-functions' calls
@@ -372,6 +380,21 @@ See the Info documentation at \"(hyperbole)HyWiki\".
;;; Public Implicit Button and Action Types
;;; ************************************************************************
+(defun hywiki-file-stem-start-end-at ()
+ "Return (file-stem start-pos end-pos) if on a `hywiki-directory' file stem.
+Otherwise, return (nil nil nil)."
+ (or (hpath:delimited-possible-path nil t)
+ (list nil nil nil)))
+
+(defib hywiki-file ()
+ "When on a HyWiki file name stem, display the file and its optional section."
+ (cl-destructuring-bind (file-stem-name start end)
+ (hywiki-file-stem-start-end-at)
+ (when (and file-stem-name
+ (file-readable-p (hywiki-get-file file-stem-name)))
+ (ibut:label-set file-stem-name start end)
+ (hact 'hywiki-find-file file-stem-name))))
+
(defib hywiki-word ()
"When on a HyWiki word, display its page and optional section."
(let ((page-name (hywiki-word-at)))
@@ -379,10 +402,31 @@ See the Info documentation at \"(hyperbole)HyWiki\".
(ibut:label-set page-name (match-beginning 0) (match-end 0))
(hact 'hywiki-find-page page-name))))
+(defun hywiki-find-file (file-stem-name)
+ "Display an existing non-HyWikiWord FILE-STEM-NAME from `hywiki-directory'.
+Return the absolute path to any file successfully found, else nil.
+
+After successfully finding a file and reading it into a buffer, run
+`hywiki-find-file-hook'."
+ (interactive (list (completing-read "Find HyWiki file: "
+ (hywiki-get-file-stem-list))))
+ (when (stringp file-stem-name)
+ (let ((file (hywiki-get-file file-stem-name))
+ section)
+ (when (file-readable-p file)
+ (setq section (when (string-match "#" file-stem-name)
+ (substring file-stem-name (match-beginning 0))))
+ (when file
+ (hpath:find (concat file section))
+ (hywiki-maybe-highlight-page-names)
+ (run-hooks 'hywiki-find-file-hook)
+ file)))))
+
(defun hywiki-find-page (&optional page-name prompt-flag)
"Display HyWiki PAGE-NAME or a regular file with PAGE-NAME nil.
-Return the absolute path to any page successfully found; nil if failed
-or if displaying a regular file.
+Return the absolute path to any page successfully found; nil if
+failed or if displaying a regular file (read in via a `find-file'
+call)
By default, create any non-existent page. With optional
PROMPT-FLAG t, prompt to create if non-existent. If PROMPT-FLAG
@@ -392,8 +436,6 @@ successfully finding a page and reading it into a buffer,
run
(interactive (list (completing-read "Find HyWiki page: "
(hywiki-get-page-list))))
(let ((in-page-flag (null page-name))
(in-hywiki-directory-flag (hywiki-in-page-p)))
- ;; If called from `find-file-hook' without a page-name and outside
- ;; hywiki-directory, just find as a regular file.
(if (or (stringp page-name) in-hywiki-directory-flag)
(progn
(when in-page-flag
@@ -424,7 +466,10 @@ successfully finding a page and reading it into a buffer,
run
(hywiki-maybe-highlight-page-names)
(run-hooks 'hywiki-find-page-hook)
page-file)))
- ;; Next line highlights only if buffer was not previously highlighted
+ ;; When called from `find-file-hook' without a page-name and outside
+ ;; hywiki-directory, just find as a regular file and use next line
+ ;; to highlight HyWikiWords only if buffer was not previously
+ ;; highlighted.
(hywiki-maybe-highlight-page-names))))
;;; ************************************************************************
@@ -435,7 +480,8 @@ successfully finding a page and reading it into a buffer,
run
"Return non-nil if HyWiki word links are active in the current buffer."
(and hywiki-word-highlight-flag
(not (minibuffer-window-active-p (selected-window)))
- (not (eq (get major-mode 'mode-class) 'special))
+ (or (derived-mode-p 'kotl-mode)
+ (not (eq (get major-mode 'mode-class) 'special)))
(not (apply #'derived-mode-p hywiki-exclude-major-modes))
(or hywiki-mode (hywiki-in-page-p))))
@@ -479,11 +525,11 @@ Use `hywiki-get-page' to determine whether a HyWiki page
exists."
(defun hywiki-word-at ()
"Return HyWiki word and optional #section at point or nil if not on one.
-A call to `hywiki-active-in-current-buffer-p' must return non-nil or
-this will return nil.
+Does not test whether or not a page exists for the HyWiki word; use
+`hywiki-get-page' for that.
-Does not test whether or not a page exists for the HyWiki word.
-Use `hywiki-get-page' to determine whether a HyWiki page exists."
+A call to `hywiki-active-in-current-buffer-p' must return non-nil or
+this will return nil."
(when (hywiki-active-in-current-buffer-p)
(let ((wikiword (ibut:label-p t "[[" "]]")))
(if wikiword
@@ -499,24 +545,23 @@ Use `hywiki-get-page' to determine whether a HyWiki page
exists."
wikiword))
;; Handle a HyWiki word with optional #section; if it is an Org
;; link, it may optionally have a hy: link-type prefix.
+ ;; Ignore wikiwords preceded by any non-whitespace
+ ;; character, except any of these: "([\"'`'"
(save-excursion
(let ((case-fold-search nil))
(skip-chars-backward "-_*#[:alnum:]")
- ;; Ignore wikiwords preceded by any non-whitespace
- ;; character, except any of these: (["'`'
(when (hywiki-maybe-at-wikiword-beginning)
(cond ((looking-at hywiki--word-and-buttonize-character-regexp)
(string-trim
(buffer-substring-no-properties (match-beginning 0)
(1- (match-end 0)))))
- ((looking-at (concat hywiki-word-regexp "\\'"))
+ ((looking-at (concat
hywiki-word-with-optional-section-regexp "\\'"))
;; No following char
(string-trim
(buffer-substring-no-properties (match-beginning 0)
(match-end 0))))))))))))
;;;###autoload
-
(defun hywiki-maybe-dehighlight-page-names (&optional region-start region-end)
"Deighlight any highlighted HyWiki page names in a HyWiki buffer/region.
With optional REGION-START and REGION-END positions (active region
@@ -817,7 +862,7 @@ the current page unless they have sections attached."
(defun hywiki-in-page-p ()
"Return non-nil if the current buffer is a HyWiki page.
If this is a HyWiki page and `hywiki-word-highlight-flag' is non-nil
-(the default), also enable auto-highlighting of HyWiki words as they
+\(the default), also enable auto-highlighting of HyWiki words as they
are typed in the buffer."
(or hywiki-page-flag
(when (string-prefix-p (expand-file-name hywiki-directory)
@@ -839,6 +884,23 @@ to determine whether a HyWiki word page exists."
(file-name-sans-extension (file-name-nondirectory
(or buffer-file-name (buffer-name)))))
+(defun hywiki-get-files ()
+ "Return the list of existing HyWiki files ending with `hywiki-file-suffix'.
+This includes both HyWiki page files and others. File names returned are
+relative to `hywiki-directory'."
+ (when (stringp hywiki-directory)
+ (make-directory hywiki-directory t)
+ (when (file-readable-p hywiki-directory)
+ (directory-files
+ hywiki-directory nil
+ (concat "^[^#]+" (regexp-quote hywiki-file-suffix) "$")))))
+
+(defun hywiki-get-file-stem-list ()
+ "Return the list of existing HyWiki files sans their `hywiki-file-suffix'.
+This includes both HyWiki page files and others. Stems returned are
+relative to `hywiki-directory'."
+ (mapcar #'file-name-sans-extension (hywiki-get-files)))
+
(defun hywiki-get-page (page-name)
"Return the absolute path of HyWiki PAGE-NAME or nil if it does not exist."
(if (and (stringp page-name) (not (string-empty-p page-name))
@@ -850,15 +912,21 @@ to determine whether a HyWiki word page exists."
(or (hash-get page-name (hywiki-get-page-hasht))
;; If page exists but not yet in lookup hash table, add it.
- (when (file-readable-p (hywiki-get-page-file page-name))
+ (when (file-readable-p (hywiki-get-file page-name))
(hywiki-add-page page-name))))
(user-error "(hywiki-get-page): Invalid page name: '%s'; must be
capitalized, all alpha" page-name)))
-(defun hywiki-get-page-file (page-name)
- "Return possibly non-existent file name for PAGE NAME.
-No validation of PAGE-NAME is done."
+(defun hywiki-get-file (file-stem-name)
+ "Return possibly non-existent path in `hywiki-directory' from FILE-STEM-NAME.
+No validation of FILE-STEM-NAME is done."
(make-directory hywiki-directory t)
- (concat (expand-file-name page-name hywiki-directory) hywiki-file-suffix))
+ ;; Remove any #section from `file-stem-name'
+ (setq file-stem-name (if (string-match "#" file-stem-name)
+ (substring file-stem-name 0 (match-beginning 0))
+ file-stem-name))
+ (if (string-suffix-p hywiki-file-suffix file-stem-name)
+ (expand-file-name file-stem-name hywiki-directory)
+ (concat (expand-file-name file-stem-name hywiki-directory)
hywiki-file-suffix)))
(defun hywiki-get-page-files ()
"Return the list of existing HyWiki page file names.
@@ -892,7 +960,7 @@ Use `hywiki-get-page' to determine whether a HyWiki page
exists."
;; Remove any #section suffix in PAGE-NAME.
(setq page-name (match-string-no-properties 1 page-name)))
- (let ((page-file (hywiki-get-page-file page-name))
+ (let ((page-file (hywiki-get-file page-name))
(pages-hasht (hywiki-get-page-hasht)))
(unless (file-readable-p page-file)
;; Create any parent dirs necessary to create empty file
diff --git a/test/hywiki-tests.el b/test/hywiki-tests.el
index 168ab6b256..fda0abd831 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: 20-Jun-24 at 09:44:36 by Mats Lidell
+;; Last-Mod: 22-Jun-24 at 00:47:02 by Bob Weiner
;;
;; SPDX-License-Identifier: GPL-3.0-or-later
;;
@@ -102,9 +102,9 @@
;; Section with dash
(goto-char (point-max))
- (insert "-section")
+ (insert "-subsection")
(goto-char 4)
- (should (string= "WikiWord#section-section" (hywiki-word-at))))
+ (should (string= "WikiWord#section-subsection" (hywiki-word-at))))
(hywiki-mode -1)
(hy-delete-dir-and-buffer hywiki-directory))))