branch: externals/hyperbole
commit 3338f25119fb5c927a312e24df884b7fbd40d292
Merge: 17969221cf 0aecf85c7a
Author: Robert Weiner <r...@gnu.org>
Commit: GitHub <nore...@github.com>

    Merge branch 'master' into use-compose-mail-for-mail-address-ibut
---
 ChangeLog            | 125 +++++++++++
 Makefile             |   8 +-
 hact.el              |   3 +-
 hargs.el             |   4 +-
 hbut.el              |   4 +-
 hib-kbd.el           |   8 +-
 hmouse-tag.el        |   6 +-
 hpath.el             |   4 +-
 hsys-org.el          |  11 +-
 hypb.el              |  12 +-
 hyrolo.el            |  17 +-
 hywiki.el            | 601 ++++++++++++++++++++++++++++++++++-----------------
 test/hywiki-tests.el | 186 +++++++++++++---
 13 files changed, 724 insertions(+), 265 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 91c8aa866f..e3f2b530c7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,130 @@
+2024-06-22  Mats Lidell  <ma...@gnu.org>
+
+* test/hywiki-tests.el
+    (hywiki-tests--get-page-list-when-new-wiki-directory): Verify cache is
+    empty for a new hywiki-directory.
+
+* Makefile (dockerized-update): Target to update (pull) the Emacs docker
+    image.
+    (dockerized): Copy source to docker so not local workspace is affected
+    when running targets in the docker environment.
+
+2024-06-22  Bob Weiner  <r...@gnu.org>
+
+* hyrolo.el (hyrolo-org-mode): Fix Org mode breakage with Emacs 30 and Org 9.7
+    and up by removing internal variable ref in
+    'org-fold-core-set-folding-spec-property' call and using 'org-link symbol
+    instead.
+
+* 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  <r...@gnu.org>
+
+* 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  <ma...@gnu.org>
+
+* test/hywiki-tests.el (hywiki-tests--at-wikiword-finds-word-and-section)
+    (hywiki-tests--maybe-at-wikiword-beginning, hywiki-tests--in-page-p)
+    (hywiki-tests--active-in-current-buffer-p)
+    (hywiki-tests--directory-get-mod-time)
+    (hywiki-tests--directory-modified-p, hywiki-tests--get-page-list)
+    (hywiki-tests--get-page-list-multiple-words): Add hywiki tests.
+
+2024-06-19  Bob Weiner  <r...@gnu.org>
+
+* test/hywiki-tests.el (hywiki-tests--face-property-for-wikiword-with-wikipage,
+                        hywiki-tests--no-face-property-for-no-wikipage): Basic
+    improvements.
+
+* hywiki.el (hywiki-highlight-page-name): Ensure either 'hywiki-mode'
+    or (hywiki-in-page-p) is true and not in the minibuffer.
+            (hywiki-buttonize-character-commands,
+             hywiki-buttonize-non-character-commands): Move most checks to
+    'hywiki-highlight-page-name'.
+            (hywiki-page-flag): Add as internal buffer-local flag set when
+    current buffer is a HyWiki page.
+            (hywiki-highlight-page-name): Rename all such prefixed functions to
+    'hywiki-maybe-highlight-page-name'.
+            (hywiki-active-in-current-buffer-p): Exclude minibuffer.
+           (hywiki-maybe-highlight-page-name): Test with
+    'hywiki-active-in-current-buffer-p'.
+            (hywiki-dehighlight-page-names): Rename to
+    'hywiki-maybe-dehighlight-page-names'.
+            (hywiki-mode): Remove auto-HyWikiWord highlighting/dehighlighting 
from
+    the minor mode and associate it with the setting of 
'hywiki-word-highlight-flag'
+    so that the same hooks can be used for HyWikiWord page highlighting as are 
used
+    in all buffers when 'hywiki-mode' is enabled.
+            (defib hywiki-word):
+            (hywiki-find-page): Move call of (hywiki-maybe-highlight-page-name 
t)
+    here from the defib since may need to create the page before highlighting 
will
+    work properly.
+            (hywiki-maybe-highlight-page-name): Skip back over buttonize-chars 
only
+    when 'on-page-name' is nil.  Also, remove sanity check line which fails 
when
+    called from control-key cmds like C-o (open-line):
+      (eq (char-before) last-command-event) ;; Sanity check
+            (hywiki-word-at): Fix doc to explain when this returns non-nil.
+            (hywiki-maybe-highlight-page-names): Fix setting of 
hywiki--start/end
+    and prevent infinite looping due to wrong positions.
+            (hywiki-word-highlight-flag-changed): Fix remove-hook from
+    'post-command-hook' to remove the correct function.
+
+2024-06-17  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki-mode): Require 'hyperbole.
+            (find-file-hook): Remove 'hywiki-find-page hook and just highlight 
when
+    any frame window changes what buffer it displays.
+            (hywiki-buttonize-character-commands,
+             hywiki-buttonize-non-character-commands): Do this only if not in 
an
+    active minibuffer window.
+
+2024-06-16  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki--buttonize-characters): Remove setting from `hywiki-mode' 
and
+    set when hywiki library is loaded.
+            (hywiki--word-and-buttonize-character-regexp): Add.
+           (hywiki-highlight-page-name, hywiki-word-at,
+            hywiki-highlight-page-names) Use above regexp.
+            (hywiki--buttonize-character-regexp): Add and use in
+    'hywiki--word-and-buttonize-character-regexp'.
+
+2024-06-09  Bob Weiner  <r...@gnu.org>
+
+* hywiki.el (hywiki-word-highlight-flag-changed): Disable 'hywiki-mode'
+    when disabling this global flag.
+            (hywiki-at-wikiword): Rename to 'hywiki-word-at' for consistency.
+           (hywiki-mode): When enabling, enable `hywiki-word-highlight-flag' 
too.
+           (hywiki-word-with-optional-section-exact-regexp): Fix doc to reflect
+    that regexp allows spaces and tabs.
+            (hywiki-buffer-highlighted-state): Add to skip HyWikiWord 
highlighting/
+    dehighlighting per buffer if already done.  Set it in
+    'hywiki-maybe-highlight-page-names' and 
'hywiki-maybe-dehighlight-page-names'.
+
+2024-06-08  Bob Weiner  <r...@gnu.org>
+
+* hypb.el (hypb:split-seq-into-sublists): Add for use with hywiki.
+
+* hywiki.el (hywiki-grep-tags): Fix so `org-redo-cmd' works properly.
+
 2024-06-02  Bob Weiner  <r...@gnu.org>
 
+* hywiki.el (hywiki--pages-directory): Add to track changes in
+    'hywiki-directory'.
+    (hywiki-make-pages-hasht, hywiki-get-page-hasht): Use above new
+    variable to rebuild hash table whenever directory changes.
+
 * hyperbole.el (hyperbole--disable-mode): Add disabling of 'hywiki-mode'.
 
 * hywiki.el (hywiki-active-in-current-buffer-p): Exclude buffers whose
diff --git a/Makefile b/Makefile
index b72306f74e..0c8e564b79 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 # Author:       Bob Weiner
 #
 # Orig-Date:    15-Jun-94 at 03:42:38
-# Last-Mod:     19-May-24 at 10:58:02 by Bob Weiner
+# Last-Mod:     22-Jun-24 at 11:35:21 by Mats Lidell
 #
 # Copyright (C) 1994-2023  Free Software Foundation, Inc.
 # See the file HY-COPY for license information.
@@ -563,7 +563,11 @@ DOCKER_VERSION = master-ci
 endif
 
 dockerized:
-       docker run -v $$(pwd):/hyperbole -it silex/emacs:${DOCKER_VERSION} bash 
-c "make -C hyperbole ${DOCKER_TARGETS}"
+       docker run -v $$(pwd):/hypb -it silex/emacs:${DOCKER_VERSION} bash -c 
"cp -a /hypb /hyperbole && make -C hyperbole ${DOCKER_TARGETS}"
+
+# Update the docker image for the specified version of Emacs
+dockerized-update:
+       docker pull silex/emacs:${DOCKER_VERSION}
 
 # Run with coverage. Run tests given by testspec and monitor the
 # coverage for the specified file.
diff --git a/hact.el b/hact.el
index 3e66e7d477..553c0d4366 100644
--- a/hact.el
+++ b/hact.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    18-Sep-91 at 02:57:09
-;; Last-Mod:     23-May-24 at 23:18:43 by Bob Weiner
+;; Last-Mod:     22-Jun-24 at 22:50:10 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -31,6 +31,7 @@
 (declare-function hbut:is-p "hbut")
 (declare-function hpath:absolute-arguments "hpath")
 (declare-function hypb:indirect-function "hypb")
+(declare-function hargs:read-match "hargs")
 
 ;;; ************************************************************************
 ;;; Public variables
diff --git a/hargs.el b/hargs.el
index 114742cc47..58a39c4ff6 100644
--- a/hargs.el
+++ b/hargs.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    31-Oct-91 at 23:17:35
-;; Last-Mod:     29-May-24 at 00:57:17 by Bob Weiner
+;; Last-Mod:     22-Jun-24 at 22:53:41 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -253,7 +253,7 @@ button key (no spaces)."
 (defun hargs:delimited-p (start-delim end-delim
                          &optional start-regexp-flag end-regexp-flag
                          list-positions-flag exclude-regexp)
-  "Call `hargs:delimited' with its `as-key' arg set to 'none.
+  "Call `hargs:delimited' with its `as-key' arg set to `none'.
 See `hargs:delimited' for full documentation."
   (hargs:delimited start-delim end-delim start-regexp-flag
                   end-regexp-flag list-positions-flag exclude-regexp 'none))
diff --git a/hbut.el b/hbut.el
index 5acf3bc783..501d92a11d 100644
--- a/hbut.el
+++ b/hbut.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    18-Sep-91 at 02:57:09
-;; Last-Mod:     25-May-24 at 16:30:50 by Bob Weiner
+;; Last-Mod:     23-Jun-24 at 00:11:37 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -1229,7 +1229,7 @@ of point when desired.
 
 Caller must have used (ibut:at-p) to create hbut:current prior to
 calling this function.  When KEY-SRC is given, this set's
-hbut:current's 'loc attribute to KEY-SRC."
+hbut:current's \\='loc attribute to KEY-SRC."
   (if buffer
       (if (bufferp buffer)
          (set-buffer buffer)
diff --git a/hib-kbd.el b/hib-kbd.el
index 00a408bcd8..9d93b9e0db 100644
--- a/hib-kbd.el
+++ b/hib-kbd.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    22-Nov-91 at 01:37:57
-;; Last-Mod:     18-Feb-24 at 11:39:41 by Mats Lidell
+;; Last-Mod:     23-Jun-24 at 00:04:17 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -105,7 +105,7 @@ Return t if the sequence appears to be valid, else nil."
   "Execute a key series (series of key sequences) around point.
 The key series is delimited by curly braces, {}.  Key sequences
 should be in human readable form, e.g. {C-x C-b}, or what
-`key-description' returns.  Forms such as {\C-b}, {\^b}, and {^M}
+`key-description' returns.  Forms such as {\\`C-b'}, {\\`^b'}, and {\\`^M'}
 will not be recognized.
 
 Any key sequence within the series must be a string of one of the following:
@@ -260,8 +260,8 @@ With optional prefix arg FULL, display full documentation 
for command."
 When STR is a curly-brace {} delimited key series, a
 non-delimited, normalized form is returned, else nil.  Key
 sequences should be in human readable form, e.g. {\\`C-x' \\`C-b'}, or
-what `key-description' returns.  Forms such as {\\`C-b'}, {\^b}, and
-{^M} will not be recognized.
+what `key-description' returns.  Forms such as {\\`C-b'}, {\\`^b'}, and
+{\\`^M'} will not be recognized.
 
 Any key sequence within the series must be a string of one of the following:
   a Hyperbole minibuffer menu item key sequence,
diff --git a/hmouse-tag.el b/hmouse-tag.el
index a836235dcf..6fb7d3ffe6 100644
--- a/hmouse-tag.el
+++ b/hmouse-tag.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    24-Aug-91
-;; Last-Mod:     14-Apr-24 at 21:27:25 by Bob Weiner
+;; Last-Mod:     22-Jun-24 at 22:58:03 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -1022,7 +1022,7 @@ It assumes that its caller has already checked that the 
key was pressed in an
 appropriate buffer and has moved the cursor to the selected buffer.
 
 First, it tries to display the IDENTIFIER definition with
-the current 'xref' backend, which may be `eglot' or `etags' in which case
+the current `xref' backend, which may be `eglot' or `etags' in which case
 Hyperbole walks up the current directory tree to find the nearest TAGS
 file.
 
@@ -1501,7 +1501,7 @@ See the \"${hyperb:dir}/smart-clib-sym\" script for more 
information."
   "Jump to the single definition of TAG or list definition locations.
 If NEXT is non-nil, jump to the next definition.  Optional
 LIST-OF-TAGS-TABLES are the tags tables to use when
-`xref-find-definitions' is called in a context where the 'etags'
+`xref-find-definitions' is called in a context where the `etags'
 backend is used."
   (when next (setq tag nil))
   (let* ((tags-table-list (or list-of-tags-tables
diff --git a/hpath.el b/hpath.el
index d4abba08ae..e687b39590 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:     18-May-24 at 19:06:22 by Bob Weiner
+;; Last-Mod:     23-Jun-24 at 00:09:03 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -2168,7 +2168,7 @@ point ends within the narrowed region."
        (narrow-to-region omin omax)))))
 
 (defun hpath:trim (path)
-  "Return PATH with any [\" \t\n\r] characters trimmed from its start and end."
+  "Return PATH with any [\" \\t\\n\\r] characters trimmed from its start and 
end."
   ;; Trim only matching starting and ending quoted double quotes (must
   ;; be a single line string).
   (setq path (string-trim path))
diff --git a/hsys-org.el b/hsys-org.el
index f736c45d2a..11dbde4471 100644
--- a/hsys-org.el
+++ b/hsys-org.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:     2-Jul-16 at 14:54:14
-;; Last-Mod:     29-May-24 at 00:55:19 by Bob Weiner
+;; Last-Mod:     22-Jun-24 at 23:43:08 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -45,6 +45,7 @@
 ;;; ************************************************************************
 
 (declare-function consult-grep "ext:consult")
+(declare-function consult-ripgrep "ext:consult")
 
 (defcustom hsys-org-consult-grep-func
   (cond ((executable-find "rg")
@@ -56,6 +57,7 @@
 
 (defvar hyperbole-mode-map)             ; "hyperbole.el"
 (defvar org--inhibit-version-check)     ; "org-macs.el"
+(defvar hywiki-org-link-type-required)  ; "hywiki.el"
 
 (declare-function org-babel-get-src-block-info "org-babel")
 (declare-function org-fold-show-context "org-fold")
@@ -71,6 +73,7 @@
 (declare-function hkey-either "hmouse-drv")
 
 (declare-function find-library-name "find-func")
+(declare-function hyperb:stack-frame "hversion.el")
 
 ;;;###autoload
 (defcustom hsys-org-enable-smart-keys 'unset
@@ -416,10 +419,10 @@ or is looking for an Org link in another buffer type."
            ;; `hywiki-org-link-type-required' is non-nil.  Otherwise,
            ;; return nil from this function and let ibtypes handle this
            ;; as a HyWiki word.
-           (if (fboundp 'hywiki-at-wikiword)
-               (if (hywiki-at-wikiword)
+           (if (fboundp 'hywiki-word-at)
+               (if (hywiki-word-at)
                    (when (or hywiki-org-link-type-required
-                             (hyperb:stack-frame '(hywiki-at-wikiword)))
+                             (hyperb:stack-frame '(hywiki-word-at)))
                      in-org-link)
                  in-org-link)
              in-org-link)))))))
diff --git a/hypb.el b/hypb.el
index c35f4a0da9..34a67d26a9 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:     18-May-24 at 18:00:28 by Mats Lidell
+;; Last-Mod:      8-Jun-24 at 19:54:44 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -21,7 +21,7 @@
 
 ;; Load Org here for `org-fold-show-all'.
 (eval-and-compile (mapc #'require '(compile hversion hact locate
-                                   cl-lib org package)))
+                                   cl-lib org package seq)))
 
 ;;; ************************************************************************
 ;;; Public declarations
@@ -942,6 +942,14 @@ Syntax tables are char-tables whose values are encoded as 
raw
 descriptors."
   (aset (or syntax-table (syntax-table)) char raw-descriptor))
 
+(defun hypb:split-seq-into-sublists (seq size)
+  "Split a sequence SEQ into sublists of length SIZE, preserving item order."
+  (let (result)
+    (while (> (length seq) 0)
+      (push (seq-into (seq-take seq size) 'list) result)
+      (setq seq (seq-drop seq size)))
+    (nreverse result)))
+
 (defun hypb:straight-package-plist (pkg-string)
   "Return package info for a straight.el built package with name PKG-STRING.
 The package info is a property list of package-name,
diff --git a/hyrolo.el b/hyrolo.el
index 063adc7dff..de5e3a9321 100644
--- a/hyrolo.el
+++ b/hyrolo.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:     7-Jun-89 at 22:08:29
-;; Last-Mod:     29-May-24 at 00:57:28 by Bob Weiner
+;; Last-Mod:     22-Jun-24 at 22:19:36 by Bob Weiner
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -135,6 +135,7 @@
 ;; Forward declarations
 (defvar consult-grep-args)
 (defvar consult-ripgrep-args)
+(defvar consult-async-split-style)
 (defvar google-contacts-expire-time)
 (defvar google-contacts-history)
 (defvar google-contacts-query-string)
@@ -3136,17 +3137,19 @@ Any non-nil value returned is a cons of (<entry-name> . 
<entry-source>)."
 
   (when (featurep 'org-fold) ;; newer Org versions
     (setq org-fold-core-style 'overlays) ;; Make compatible with reveal minor 
mode
-    (when (and org-link-descriptive
-               (eq org-fold-core-style 'overlays))
-      (hypb:add-to-invisibility-spec '(org-link)))
+    (hypb:add-to-invisibility-spec '(org-link))
     (org-fold-initialize (or (and (stringp org-ellipsis) (not (equal "" 
org-ellipsis)) org-ellipsis)
                              "..."))
     (make-local-variable 'org-link-descriptive)
     (when (eq org-fold-core-style 'overlays)
       (hypb:add-to-invisibility-spec '(org-hide-block . t)))
-    (if org-link-descriptive
-       (org-fold-core-set-folding-spec-property (car 
org-link--link-folding-spec) :visible nil)
-      (org-fold-core-set-folding-spec-property (car 
org-link--link-folding-spec) :visible t)))
+    (org-fold-core-set-folding-spec-property
+     (if (boundp 'org-link--link-folding-spec)
+        ;; Org pre-9.7
+        (car org-link--link-folding-spec)
+       ;; Org 9.7 and up
+       (caar org-fold-core--specs))
+     :visible (not org-link-descriptive)))
 
   (setq-local hyrolo-entry-regexp "^\\(\\*+\\)\\([ \t\n\r]+\\)"
              hyrolo-hdr-and-entry-regexp (concat hyrolo-hdr-prefix-regexp 
hyrolo-entry-regexp)
diff --git a/hywiki.el b/hywiki.el
index 2e7d7fddff..89ca51790c 100644
--- a/hywiki.el
+++ b/hywiki.el
@@ -1,9 +1,9 @@
-;;; hywiki.el --- Hyperbole's auto-wikiword note-taking system   -*- 
lexical-binding: t -*-
+;;; hywiki.el --- Hyperbole's auto-wikiword note-taking system     -*- 
lexical-binding: t -*-
 ;;
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    21-Apr-24 at 22:41:13
-;; Last-Mod:      2-Jun-24 at 11:52:44 by Bob Weiner
+;; Last-Mod:     23-Jun-24 at 00:12:37 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -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:
 ;;; ************************************************************************
@@ -96,6 +104,7 @@
 (require 'hbut)       ;; For `hbut:syntax-table'
 (require 'hasht)
 (require 'hpath)
+(require 'hypb)
 (require 'hui-em-but)
 (require 'outline)    ;; For `outline-mode-syntax-table'
 
@@ -107,6 +116,7 @@
 ;;; Public declarations
 ;;; ************************************************************************
 
+(defvar org-agenda-buffer-tmp-name)  ;; "org-agenda.el"
 (declare-function org-link-store-props "ol" (&rest plist))
 
 ;;; ************************************************************************
@@ -114,9 +124,19 @@
 ;;; ************************************************************************
 
 (defcustom hywiki-word-highlight-flag t
-  "HyWiki highlights non-Org link HyWikiWords only when this is non-nil.
-Outside of HyWiki pages, `hywiki-mode' must also be enabled for
-auto-HyWikiWord highlighting."
+  "The default, non-nil value treats HyWikiWords in HyWiki pages as hyperlinks.
+A nil value disables HyWikiWord hyperlink buttons in both HyWiki
+pages and all other buffers (since it also disables `hywiki-mode').
+
+Outside of HyWiki pages, the global minor mode `hywiki-mode' must be
+manually enabled for auto-HyWikiWord highlighting; programmatically,
+use `(hywiki-mode 1) to enable it.
+
+Use `hywiki-active-in-current-buffer-p' to determine if HyWikiWord
+hyperlinks are currently active in a buffer or not.
+
+Regardless of this flag, HyWikiWords in Org links and targets are not
+highlighted nor treated as hyperlinks; they are handled normally by Org."
   :type 'boolean
   :initialize #'custom-initialize-default
   :group 'hyperbole-hywiki)
@@ -143,9 +163,16 @@ Use nil for no HyWiki mode indicator."
 (defvar hywiki-directory '"~/hywiki/"
   "Directory in which to find HyWiki page files.")
 
+(defvar-local hywiki-buffer-highlighted-state nil
+  "State of HyWikiWords highlighting in the associated buffer.
+\\='h means the buffer was already highlighted;
+\\='d means the buffer was dehighlighted;
+nil means no full buffer highlighting has occurred.")
+
 (defvar hywiki-non-character-commands
   '(;; Org mode
     org-cycle                         ;; TAB
+    org-open-line                     ;; C-o
     org-return                        ;; RET, \r
     org-return-and-maybe-indent       ;; C-j, \n
     ;; Markdown mode
@@ -155,6 +182,7 @@ Use nil for no HyWiki mode indicator."
     ;; Global
     newline                           ;; RET, \r
     newline-and-indent                ;; RET, \r
+    open-line                         ;; C-o
     quoted-insert                     ;; C-q
     )
   "Commands that insert characters but whose input events do not
@@ -173,6 +201,13 @@ Presently, there are no key bindings; this is for future 
use.")
 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 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
+`hywiki-maybe-highlight-page-names' which calls `hywiki-in-page-p'.")
+
 (defconst hywiki-word-regexp
   "\\<\\([[:upper:]][[:alpha:]]+\\)\\>"
   "Regexp that matches a HyWiki word only.")
@@ -186,15 +221,16 @@ non-# and non-whitespace characters.")
 (defconst hywiki-word-with-optional-section-regexp
   (concat hywiki-word-regexp hywiki-word-section-regexp "?")
   "Regexp that matches a HyWiki word with an optional #section.
-Section may not contain spaces or square brackets.  Use '-' to
+Section may not contain whitespace or square brackets.  Use '-' to
 substitute for spaces in the section/headline name.  Grouping 1 is
 the HyWiki word and grouping 2 is the #section with the # included.")
 
 (defconst hywiki-word-with-optional-section-exact-regexp
   (concat "\\`" hywiki-word-regexp "\\(#[^][\n\r\f]+\\)?\\'")
   "Exact match regexp for a HyWiki word with an optional #section.
-Section may not contain spaces or square brackets.  Use '-' to
-substitute for spaces in the section/headline name.  Grouping 1 is
+The section may contain spaces or tabs but not square brackets;
+it is preferable, however, to substitute '-' for whitespace in
+the section/headline name to simplify recognition.  Grouping 1 is
 the HyWiki word and grouping 2 is the #section with the # included.")
 
 (defface hywiki--word-face
@@ -215,9 +251,17 @@ the HyWiki word and grouping 2 is the #section with the # 
included.")
 ;;; Private variables
 ;;; ************************************************************************
 
-(defvar hywiki--buttonize-characters nil
+;; Must be set after `hywiki-get-buttonize-characters' is defined
+(defconst hywiki--buttonize-characters nil
   "String of single character keys bound to 
`hywiki-buttonize-character-commands'.
-Each such key self-inserts before highlighting any prior HyWiki word.")
+Each such key self-inserts before highlighting any prior HyWiki word
+in `hywiki-mode'.")
+
+(defconst hywiki--buttonize-character-regexp nil
+  "Regexp matching a single separating character following a HyWiki word.")
+
+(defconst hywiki--word-and-buttonize-character-regexp
+  "Regexp matching HyWikiWord#section plus a valid word separating character.")
 
 (defvar hywiki--directory-mod-time 0
   "Last mod time for `hywiki-directory' or 0 if the value has not been read.")
@@ -234,11 +278,12 @@ Each such key self-inserts before highlighting any prior 
HyWiki word.")
     st)
   "Standard syntax table for Org mode buffers with HyWiki support.")
 
+(defvar hywiki--pages-directory nil)
 (defvar hywiki--pages-hasht nil)
 
 ;; Globally set these values to avoid using 'let' with stack allocations
-;; within `hywiki-highlight-page-name' frequently.
-(defvar hywiki--any-page-regexp nil)
+;; within `hywiki-maybe-highlight-page-name' frequently.
+(defvar hywiki--any-page-regexp-list nil)
 (defvar hywiki--buts nil)
 (defvar hywiki--but-end nil)
 (defvar hywiki--but-start nil)
@@ -256,17 +301,16 @@ Each such key self-inserts before highlighting any prior 
HyWiki word.")
 (defun hywiki-buttonize-character-commands ()
   "Turn any HyWikiWord before point into a highlighted Hyperbole button.
 Triggered by `post-self-insert-hook' for self-inserting characters."
-  (when (and hywiki-word-highlight-flag
-            (characterp last-command-event)
+  (when (and (characterp last-command-event)
             (cl-find last-command-event hywiki--buttonize-characters))
-    (hywiki-highlight-page-name)))
+    (hywiki-maybe-highlight-page-name)))
 
 (defun hywiki-buttonize-non-character-commands ()
   "Turn any HyWikiWord before point into a highlighted Hyperbole button.
-Triggered by `pre-command-hook' for non-character-commands, e.g. return."
-  (when (and hywiki-word-highlight-flag
-            (memq this-command hywiki-non-character-commands))
-    (hywiki-highlight-page-name)))
+Triggered by `post-command-hook' for non-character-commands, e.g.
+return/newline."
+  (when (memq this-command hywiki-non-character-commands)
+    (hywiki-maybe-highlight-page-name)))
 
 (defun hywiki-get-buttonize-characters ()
   "Return a string of Org self-insert keys that have punctuation/symbol 
syntax."
@@ -319,51 +363,80 @@ See the Info documentation at \"(hyperbole)HyWiki\".
       ;; enable mode
       (progn
        ;; Need hyperbole-mode
-       (if (boundp 'hyperbole-mode)
-           (unless hyperbole-mode (hyperbole-mode 1))
-         (error "(hywiki-mode): `hyperbole-mode' must be defined before 
invoking `hywiki-mode'"))
+       (require 'hyperbole)
+       (unless hyperbole-mode
+         (hyperbole-mode 1))
        (unless hywiki-mode-map
           (setq hywiki-mode-map (make-sparse-keymap)))
-            ;; Self-insert punct/sym keys that trigger wiki-word
-            ;; highlighting via `hywiki-buttonize-character-commands'
-            ;; in `hywiki-mode'.
-       (unless hywiki--buttonize-characters
-         (setq hywiki--buttonize-characters
-               (concat " \t\r\n()<>[]{}'" (hywiki-get-buttonize-characters))))
-       (add-hook 'post-self-insert-hook 'hywiki-buttonize-character-commands)
-       (add-hook 'pre-command-hook 'hywiki-buttonize-non-character-commands 
95))
+       ;; Next line triggers a call to 
`hywiki-maybe-highlight-page-names-in-frame'
+       (set-variable 'hywiki-word-highlight-flag t))
     ;; disable mode
-    (remove-hook 'post-self-insert-hook 'hywiki-buttonize-character-commands)
-    (remove-hook 'pre-command-hook 'hywiki-buttonize-character-commands))
-  (hywiki-highlight-page-names-in-frame (selected-frame)))
+    ;; Dehighlight HyWikiWords in this buffer when 'hywiki-mode' is
+    ;; disabled and this is not a HyWiki page buffer. If this is a
+    ;; HyWiki page buffer, then dehighlight when
+    ;; `hywiki-word-highlight-flag' is nil.
+    (hywiki-maybe-highlight-page-names-in-frame t)))
 
 ;;; ************************************************************************
 ;;; 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-at-wikiword)))
+  (let ((page-name (hywiki-word-at)))
     (when page-name
       (ibut:label-set page-name (match-beginning 0) (match-end 0))
-      (hywiki-highlight-page-name t)
       (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
-is 'exists, return nil unless the page already exists.  After
+is \\='exists, return nil unless the page already exists.  After
 successfully finding a page and reading it into a buffer, run
 `hywiki-find-page-hook'."
   (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, do nothing (just finding a regular file).
     (if (or (stringp page-name) in-hywiki-directory-flag)
        (progn
          (when in-page-flag
@@ -387,11 +460,18 @@ successfully finding a page and reading it into a buffer, 
run
                                        (hywiki-add-page page-name)))
                                  (hywiki-add-page page-name)))))
            (when page-file
+             ;; Ensure highlight any page name at point in case called as a
+             ;; Hyperbole action type
+             (hywiki-maybe-highlight-page-name t)
              (unless in-page-flag (hpath:find (concat page-file section)))
-             (hywiki-highlight-page-names)
+             (hywiki-maybe-highlight-page-names)
              (run-hooks 'hywiki-find-page-hook)
              page-file)))
-      (hywiki-highlight-page-names))))
+      ;; 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))))
 
 ;;; ************************************************************************
 ;;; Public functions
@@ -399,8 +479,10 @@ successfully finding a page and reading it into a buffer, 
run
 
 (defun hywiki-active-in-current-buffer-p ()
   "Return non-nil if HyWiki word links are active in the current buffer."
-  (and (not (eq (get major-mode 'mode-class) 'special))
-       hywiki-word-highlight-flag
+  (and hywiki-word-highlight-flag
+       (not (minibuffer-window-active-p (selected-window)))
+       (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))))
 
@@ -442,10 +524,13 @@ Use `hywiki-get-page' to determine whether a HyWiki page 
exists."
   (when (or (bolp) (cl-find (char-before) "\(\{\<\"'`\t\n\r\f "))
     t))
 
-(defun hywiki-at-wikiword ()
+(defun hywiki-word-at ()
   "Return HyWiki word and optional #section at point or nil if not on one.
-Does not test whether or not a page exists for the HyWiki word.
-Use `hywiki-get-page' to determine whether a HyWiki page exists."
+Does not test whether or not a page exists for the HyWiki word; use
+`hywiki-get-page' for that.
+
+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
@@ -461,26 +546,36 @@ 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: (["'`'
-           (and (hywiki-maybe-at-wikiword-beginning)
-                (looking-at hywiki-word-with-optional-section-regexp)
-                (string-trim (match-string-no-properties 0)))))))))
+           (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-with-optional-section-regexp "\\'"))
+                    ;; No following char
+                    (string-trim
+                     (buffer-substring-no-properties (match-beginning 0)
+                                                     (match-end 0))))))))))))
 
 ;;;###autoload
-(defun hywiki-dehighlight-page-names (&optional region-start region-end)
+(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
 interactively), limit dehighlighting to the region."
   (interactive (when (use-region-p) (list (region-beginning) (region-end))))
-  (unless (hywiki-active-in-current-buffer-p)
+  (unless (or (eq hywiki-buffer-highlighted-state 'd)
+             (hywiki-active-in-current-buffer-p))
     (hproperty:but-clear-all-in-list
      (hproperty:but-get-all-in-region (or region-start (point-min))
                                      (or region-end (point-max))
-                                     'face hywiki-word-face))))
+                                     'face hywiki-word-face))
+    (unless (or region-start region-end)
+      (setq hywiki-buffer-highlighted-state 'd))))
 
 (defun hywiki-directory-get-mod-time ()
   "Return the last mod time for `hywiki-directory' or 0."
@@ -497,26 +592,36 @@ interactively), limit dehighlighting to the region."
       (/= hywiki--directory-mod-time (hywiki-directory-get-mod-time))))
 
 ;;;###autoload
-(defun hywiki-grep-tags (&optional todo-only)
+(defun hywiki-grep-tags (&optional todo-only grep-buffer-name)
   "Prompt for colon-separated Org tags and display matching HyWiki page 
sections.
-With optional prefix arg TODO-ONLY, limit matches to HyWiki Org todo items 
only."
+With optional prefix arg TODO-ONLY, limit matches to HyWiki Org
+todo items only.  With optional GREP-BUFFER-NAME, use that rather
+than the default, \"*HyWiki Tags*\"."
   (interactive "P")
   (require 'org-agenda)
   (let* ((org-agenda-files (list hywiki-directory))
-        (org-agenda-buffer-name "*HyWiki Tags*")
+        (org-agenda-buffer-name (or grep-buffer-name "*HyWiki Tags*"))
         ;; `org-tags-view' is mis-written to require setting this next
-        ;; tmp-name or it will not properly name the displayed buffer
+        ;; tmp-name or it will not properly name the displayed buffer.
         (org-agenda-buffer-tmp-name org-agenda-buffer-name))
-    ;; This prompts for the tags to match
-    (org-tags-view todo-only)))
+    ;; This prompts for the tags to match and uses `org-agenda-files'.
+    (org-tags-view todo-only)
+    (when (equal (buffer-name) org-agenda-buffer-name)
+      ;; Set up {C-u r} redo cmd
+      (let (buffer-read-only)
+       (put-text-property (point-min) (point-max) 'org-redo-cmd
+                          `(hywiki-grep-tags
+                              ,todo-only
+                              ,org-agenda-buffer-name)))
+      (forward-line 2))))
 
 (defun hywiki-highlight-on-yank (_prop-value start end)
   "Used in `yank-handled-properties' called with START and END pos of the 
text."
-  (hywiki-highlight-page-names start end))
+  (hywiki-maybe-highlight-page-names start end))
 
 ;;;###autoload
-(defun hywiki-highlight-page-name (&optional on-page-name)
-  "Highlight any non-Org link HyWiki page#section one character before point.
+(defun hywiki-maybe-highlight-page-name (&optional on-page-name)
+  "Highlight any non-Org link HyWiki page#section at or one char before point.
 With optional ON-PAGE-NAME non-nil, assume point is within the page or
 section name.
 
@@ -524,16 +629,15 @@ If in a programming mode, must be within a comment.
 Use `hywiki-word-face' to highlight.  Does not highlight references to
 the current page unless they have sections attached."
   (interactive)
-  (when (and hywiki-word-highlight-flag
+  (when (and (hywiki-active-in-current-buffer-p)
             (if (and (derived-mode-p 'prog-mode)
                      (not (apply #'derived-mode-p 
hywiki-highlight-all-in-prog-modes)))
                 ;; Non-nil if match is inside a comment
                 (nth 4 (syntax-ppss))
               t)
             (or on-page-name
-                (and (eq (char-before) last-command-event) ; Sanity check
-                     (cl-find (char-syntax last-command-event)
-                              " _()<>$.\"'")))
+                (cl-find (char-syntax last-command-event)
+                         " _()<>$.\"'"))
              (not executing-kbd-macro)
              (not noninteractive))
     (with-syntax-table hbut:syntax-table
@@ -558,13 +662,13 @@ the current page unless they have sections attached."
                         (hproperty:but-clear-all-in-list
                          (hproperty:but-get-all-in-region sexp-start sexp-end 
'face hywiki-word-face))))))
                  ((memq (char-before) '(?\( ?\{))
-                  ;; Highlight any HyWikiWords within parens or braces.
+                  ;; Highlight any HyWikiWords within parens or braces
                   (ignore-errors
                     (goto-char (1- (point)))
                     (let* ((sexp-start (point))
                            (sexp-end (scan-sexps sexp-start 1)))
                       (when sexp-end
-                        (hywiki-highlight-page-names sexp-start sexp-end)))))
+                        (hywiki-maybe-highlight-page-names sexp-start 
sexp-end)))))
                  ((memq (char-before) '(?\] ?\>))
                   ;; Clear any HyWikiWord highlighting within square or
                   ;; angle brackets, as this may be a link or target.
@@ -575,15 +679,16 @@ the current page unless they have sections attached."
                         (hproperty:but-clear-all-in-list
                          (hproperty:but-get-all-in-region sexp-start sexp-end 
'face hywiki-word-face))))))
                  ((memq (char-before) '(?\) ?\}))
-                  ;; Highlight any HyWikiWords within parens or braces.
+                  ;; Highlight any HyWikiWords within parens or braces
                   (ignore-errors
                     (let* ((sexp-end (point))
                            (sexp-start (scan-sexps sexp-end -1)))
                       (when sexp-start
-                        (hywiki-highlight-page-names sexp-start 
sexp-end))))))))
+                        (hywiki-maybe-highlight-page-names sexp-start 
sexp-end))))))))
 
-       ;; May be a closing delimiter that we have to skip past
-       (skip-chars-backward (regexp-quote hywiki--buttonize-characters))
+       (unless on-page-name
+         ;; May be a closing delimiter that we have to skip past
+         (skip-chars-backward (regexp-quote hywiki--buttonize-characters)))
        ;; Skip past HyWikiWord or section
        (skip-syntax-backward "^-$()<>._\"\'")
        (skip-chars-backward "-_*#[:alpha:]")
@@ -593,11 +698,11 @@ the current page unless they have sections attached."
              hywiki--save-org-link-type-required hywiki-org-link-type-required
              hywiki-org-link-type-required t)
        (if (and (hywiki-maybe-at-wikiword-beginning)
-                (looking-at hywiki-word-with-optional-section-regexp)
+                (looking-at hywiki--word-and-buttonize-character-regexp)
                 (progn
                   (setq hywiki--page-name (match-string-no-properties 1)
                         hywiki--start (match-beginning 0)
-                        hywiki--end   (match-end 0))
+                        hywiki--end   (1- (match-end 0)))
                   (and (hywiki-get-page hywiki--page-name)
                        ;; Ignore wikiwords preceded by any non-whitespace 
character
                        ;; (or (bolp) (memq (preceding-char) '(?\  ?\t)))
@@ -631,7 +736,7 @@ the current page unless they have sections attached."
                                            'face hywiki-word-face)))))))
 
 ;;;###autoload
-(defun hywiki-highlight-page-names (&optional region-start region-end)
+(defun hywiki-maybe-highlight-page-names (&optional region-start region-end)
   "Highlight each non-Org link HyWiki page#section in a buffer/region.
 With optional REGION-START and REGION-END positions (active region
 interactively), limit highlighting to the region.
@@ -640,71 +745,106 @@ Use `hywiki-word-face' to highlight.  Do not highlight 
references to
 the current page unless they have sections attached.
 
 Dehighlight buffers other than HyWiki pages when `hywiki-mode' is
-disabled.  Highlight/dehighlight HyWiki page buffers when 
`hywiki-word-highlight-flag'
-is changed."
+disabled.  Highlight/dehighlight HyWiki page buffers when
+`hywiki-word-highlight-flag' is changed."
   (interactive (when (use-region-p) (list (region-beginning) (region-end))))
   ;; Avoid doing any lets for efficiency.
   ;; Highlight HyWiki words in buffers where `hywiki-mode' is enabled
   ;; or with attached files below `hywiki-directory'.
   (if (hywiki-active-in-current-buffer-p)
-      (unwind-protect
-         (save-excursion
-           (save-restriction
-             (when (or (null hywiki--any-page-regexp)
-                       (hywiki-directory-modified-p))
-               ;; Compute this expensive regexp only if `hywiki-directory' mod 
time has changed.
-               (setq hywiki--any-page-regexp (regexp-opt 
(hywiki-get-page-list) 'words)
-                     hywiki--directory-mod-time 
(hywiki-directory-get-mod-time)))
-             (setq hywiki--save-case-fold-search case-fold-search
-                   case-fold-search nil
-                   hywiki--save-org-link-type-required 
hywiki-org-link-type-required
-                   hywiki-org-link-type-required t
-                   hywiki--current-page (hywiki-get-buffer-page-name))
-             (if (and region-start region-end)
-                 (narrow-to-region region-start region-end)
-               (widen))
-             (goto-char (point-min))
-             (let ((highlight-in-comments-only
-                    (and (derived-mode-p 'prog-mode)
-                         (not (apply #'derived-mode-p 
hywiki-highlight-all-in-prog-modes)))))
-               (while (re-search-forward hywiki--any-page-regexp nil t)
-                 (when (if highlight-in-comments-only
-                           ;; Non-nil if match is inside a comment
-                           (nth 4 (syntax-ppss))
-                         t)
-                   (setq hywiki--start (match-beginning 0)
-                         hywiki--end   (match-end 0))
-                   (save-excursion
-                     (goto-char hywiki--start)
-                     (if (or (hargs:delimited-p "\\[" "\\]" t t t)
-                             (hargs:delimited-p "<" ">" t t t))
-                         ;; Clear any HyWikiWord highlighting that may
-                         ;; just be a part of a larger square brackets or
-                         ;; angle brackets delimited text with multiple words.
-                         (hproperty:but-clear-all-in-list
-                          (hproperty:but-get-all-in-region hywiki--start 
hywiki--end
-                                                           'face 
hywiki-word-face))
-                       ;; Otherwise, highlight any HyWikiWord found, including
-                       ;; any #section.
-                       (when (hywiki-maybe-at-wikiword-beginning)
-                         (with-syntax-table hbut:syntax-table
-                           (skip-syntax-forward "^-\)$\>._\"\'"))
-                         (skip-chars-forward "-_*#[:alnum:]")
-                         (setq hywiki--end (point))
-                         ;; Don't highlight current-page matches unless they
-                         ;; include a #section.
-                         (unless (string-equal hywiki--current-page
-                                               (buffer-substring-no-properties 
hywiki--start hywiki--end))
-                           (hproperty:but-add hywiki--start hywiki--end 
hywiki-word-face))))))))))
-       (setq case-fold-search hywiki--save-case-fold-search
-             hywiki-org-link-type-required 
hywiki--save-org-link-type-required))
-
-    ;; Otherwise, dehighlight buffers other than HyWiki pages when
-    ;; 'hywiki-mode' is disabled. Dehighlight HyWiki page
-    ;; buffers when `hywiki-word-highlight-flag' is disabled.
-    (hywiki-dehighlight-page-names region-start region-end)))
-
-(defun hywiki-highlight-page-names-in-frame (frame)
+      (unless (eq hywiki-buffer-highlighted-state 'h)
+       (unwind-protect
+           (save-excursion
+             (save-restriction
+               (when (or (null hywiki--any-page-regexp-list)
+                         (hywiki-directory-modified-p))
+                 ;; Compute these expensive regexps (matching 50
+                 ;; hywiki words at a time) only if `hywiki-directory'
+                 ;; mod time has changed.
+                 (setq hywiki--any-page-regexp-list
+                       (mapcar (lambda (page-sublist)
+                                 (concat (regexp-opt page-sublist 'words)
+                                         hywiki--buttonize-character-regexp))
+                               (hypb:split-seq-into-sublists
+                                (hywiki-get-page-list) 50))
+                       hywiki--directory-mod-time 
(hywiki-directory-get-mod-time)))
+               (setq hywiki--save-case-fold-search case-fold-search
+                     case-fold-search nil
+                     hywiki--save-org-link-type-required 
hywiki-org-link-type-required
+                     hywiki-org-link-type-required t
+                     hywiki--current-page (hywiki-get-buffer-page-name))
+               (if (and region-start region-end)
+                   (narrow-to-region region-start region-end)
+                 (widen))
+               (dolist (hywiki-words-regexp hywiki--any-page-regexp-list)
+                 (goto-char (point-min))
+                 (let ((highlight-in-comments-only
+                        (and (derived-mode-p 'prog-mode)
+                             (not (apply #'derived-mode-p 
hywiki-highlight-all-in-prog-modes)))))
+                   (while (re-search-forward hywiki-words-regexp nil t)
+                     (when (if highlight-in-comments-only
+                               ;; Non-nil if match is inside a comment
+                               (nth 4 (syntax-ppss))
+                             t)
+                       (setq hywiki--start (match-beginning 1)
+                             hywiki--end   (match-end 1))
+                       (save-excursion
+                         (goto-char hywiki--start)
+                         ;; Otherwise, highlight any HyWikiWord found, 
including
+                         ;; any #section.
+                         (when (hywiki-maybe-at-wikiword-beginning)
+                           (with-syntax-table hbut:syntax-table
+                             (skip-syntax-forward "^-\)$\>._\"\'"))
+                           (skip-chars-forward "-_*#[:alnum:]")
+                           (setq hywiki--end (point))
+                           ;; Don't highlight current-page matches unless they
+                           ;; include a #section.
+                           (unless (string-equal hywiki--current-page
+                                                 
(buffer-substring-no-properties hywiki--start hywiki--end))
+                             (hproperty:but-add hywiki--start hywiki--end 
hywiki-word-face))))))))
+
+               (let (str-start-end)
+                 (goto-char (point-min))
+                 (while (search-forward "[" nil t)
+                   (when (setq str-start-end (hargs:delimited-p "[" "]" nil 
nil t))
+                     (setq hywiki--start (nth 1 str-start-end)
+                           hywiki--end   (nth 2 str-start-end))
+                     ;; Clear any HyWikiWord highlighting that may
+                     ;; just be a part of a larger square brackets
+                     ;; delimited text with multiple words.
+                     (hproperty:but-clear-all-in-list
+                      (hproperty:but-get-all-in-region hywiki--start 
hywiki--end
+                                                       'face hywiki-word-face))
+                     (goto-char (min (1+ hywiki--end) (point-max)))))
+
+                 (goto-char (point-min))
+                 (while (search-forward "<" nil t)
+                   (when (setq str-start-end (hargs:delimited-p "<" ">" nil 
nil t))
+                     (setq hywiki--start (nth 1 str-start-end)
+                           hywiki--end   (nth 2 str-start-end))
+                     ;; Clear any HyWikiWord highlighting that may
+                     ;; just be a part of a larger angle brackets
+                     ;; delimited text with multiple words.
+                     (hproperty:but-clear-all-in-list
+                      (hproperty:but-get-all-in-region hywiki--start 
hywiki--end
+                                                       'face hywiki-word-face))
+                     (goto-char (min (1+ hywiki--end) (point-max))))))
+
+               (unless (and region-start region-end
+                            (or (/= region-start (point-min))
+                                (/= region-end   (point-max))))
+                 (setq hywiki-buffer-highlighted-state 'h))))
+         (setq case-fold-search hywiki--save-case-fold-search
+               hywiki-org-link-type-required 
hywiki--save-org-link-type-required))
+       )
+
+    ;; Otherwise, dehighlight HyWikiWords in this buffer when
+    ;; 'hywiki-mode' is disabled and this is not a HyWiki page
+    ;; buffer. If this is a HyWiki page buffer, then dehighlight
+    ;; when `hywiki-word-highlight-flag' is nil.
+    (hywiki-maybe-dehighlight-page-names region-start region-end)))
+
+(defun hywiki-maybe-highlight-page-names-in-frame (frame)
   "Highlight all non-Org link HyWiki page names displayed in FRAME.
 If FRAME is t, then highlight in all windows across all frames, even
 invisible ones.
@@ -717,13 +857,18 @@ the current page unless they have sections attached."
        ;; Display buffer before `normal-mode' triggers possibly
        ;; long-running font-locking
        (sit-for 0.1)
-       (hywiki-highlight-page-names)))
+       (hywiki-maybe-highlight-page-names)))
    nil frame))
 
 (defun hywiki-in-page-p ()
-  "Return non-nil if the current buffer is a hywiki page."
-  (string-prefix-p (expand-file-name hywiki-directory)
-                  (or buffer-file-name "")))
+  "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
+are typed in the buffer."
+  (or hywiki-page-flag
+      (when (string-prefix-p (expand-file-name hywiki-directory)
+                            (or buffer-file-name ""))
+       (setq hywiki-page-flag t))))
 
 (defun hywiki-is-wikiword (word)
   "Return non-nil if WORD is a HyWiki word and optional #section.
@@ -740,6 +885,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))
@@ -751,15 +913,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.
@@ -773,7 +941,9 @@ These must end with `hywiki-file-suffix'."
 
 (defun hywiki-get-page-hasht ()
   "Return hash table of existing HyWiki pages."
-  (or hywiki--pages-hasht (hywiki-make-pages-hasht)))
+  (if (equal hywiki--pages-directory hywiki-directory)
+      (or hywiki--pages-hasht (hywiki-make-pages-hasht))
+    (hywiki-make-pages-hasht)))
 
 (defun hywiki-get-page-list ()
   (hash-map #'cdr (hywiki-get-page-hasht)))
@@ -791,7 +961,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
@@ -806,14 +976,15 @@ Use `hywiki-get-page' to determine whether a HyWiki page 
exists."
         (page-elts (mapcar (lambda (file)
                              (cons file (file-name-sans-extension 
(file-name-nondirectory file))))
                            page-files)))
-    (setq hywiki--pages-hasht (hash-make page-elts))))
+    (setq hywiki--pages-directory hywiki-directory
+         hywiki--pages-hasht (hash-make page-elts))))
 
 (eval-and-compile
   '(when (featurep 'company)
      (defun hywiki-company-hasht-backend (command &optional _arg &rest ignored)
        "A `company-mode` backend that completes from the keys of a hash table."
        (interactive (list 'interactive))
-       (when (hywiki-at-wikiword)
+       (when (hywiki-word-at)
         (pcase command
           ('interactive (company-begin-backend 'company-hash-table-backend))
           ('prefix (company-grab-word))
@@ -835,8 +1006,8 @@ Use `hywiki-get-page' to determine whether a HyWiki page 
exists."
 
 (defun hywiki-org-link-store ()
   "Store a link to a HyWiki word at point, if any."
-  (when (hywiki-at-wikiword)
-    (let* ((page-name (hywiki-at-wikiword))
+  (when (hywiki-word-at)
+    (let* ((page-name (hywiki-word-at))
           (link (concat
                  (when hywiki-org-link-type-required
                    (concat hywiki-org-link-type ":"))
@@ -853,10 +1024,6 @@ Use `hywiki-get-page' to determine whether a HyWiki page 
exists."
                            :follow #'hywiki-find-page
                            :store #'hywiki-org-link-store))
 
-(add-hook 'find-file-hook #'hywiki-find-page t)
-(add-to-list 'window-buffer-change-functions
-            'hywiki-highlight-page-names-in-frame nil 'eq)
-
 (defun hywiki-word-highlight-flag-changed (symbol set-to-value operation 
_where)
   "Watch function for variable ``hywiki-word-highlight-flag'.
 Function is called with 4 arguments: (SYMBOL SET-TO-VALUE OPERATION WHERE).
@@ -864,18 +1031,48 @@ Highlight/dehighlight HyWiki page names across all 
frames on change."
   (unless (memq operation '(let unlet)) ;; not setting global valNue
     (set symbol set-to-value)
     (if set-to-value
-       (add-to-list 'yank-handled-properties
-                    '(hywiki-word-face . hywiki-highlight-on-yank))
+       ;; enabled
+       (progn (add-hook 'post-self-insert-hook 
'hywiki-buttonize-character-commands)
+              (add-hook 'post-command-hook     
'hywiki-buttonize-non-character-commands 95)
+              (add-to-list 'yank-handled-properties
+                           '(hywiki-word-face . hywiki-highlight-on-yank))
+              (hywiki-maybe-highlight-page-names-in-frame t))
+      ;; disabled
+      (remove-hook 'post-self-insert-hook 'hywiki-buttonize-character-commands)
+      (remove-hook 'post-command-hook     
'hywiki-buttonize-non-character-commands)
+      (hywiki-mode 0) ;; also dehighlights HyWiki words outside of HyWiki pages
       (setq yank-handled-properties
            (delete '(hywiki-word-face . hywiki-highlight-on-yank)
-                   'yank-handled-properties)))
-    (hywiki-highlight-page-names-in-frame t)))
+                   yank-handled-properties)))))
+
+;;; ************************************************************************
+;;; Private initializations
+;;; ************************************************************************
+
+;; Must be set after `hywiki-get-buttonize-characters' is defined
+(unless hywiki--buttonize-characters
+  (setq hywiki--buttonize-characters
+       (concat "[]()<>{} \t\r\n'" (hywiki-get-buttonize-characters))
+       hywiki--buttonize-character-regexp
+       (concat "[]["
+               (regexp-quote (substring hywiki--buttonize-characters 2))
+               "]")
+       hywiki--word-and-buttonize-character-regexp
+       (concat hywiki-word-with-optional-section-regexp
+               hywiki--buttonize-character-regexp)))
+
+;;; ************************************************************************
+;;; Public initializations
+;;; ************************************************************************
 
 (add-variable-watcher 'hywiki-word-highlight-flag
                      'hywiki-word-highlight-flag-changed)
 
-;; Sets `yank-handled-properties'
+;; Sets HyWiki page auto-HyWikiWord highlighting and `yank-handled-properties'
 (hywiki-word-highlight-flag-changed 'hywiki-word-highlight-flag
                                    hywiki-word-highlight-flag 'set nil)
 
+(add-to-list 'window-buffer-change-functions
+            #'hywiki-maybe-highlight-page-names-in-frame nil 'eq)
+
 (provide 'hywiki)
diff --git a/test/hywiki-tests.el b/test/hywiki-tests.el
index b4c8d87112..99f3c01dda 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:      1-Jun-24 at 16:16:00 by Mats Lidell
+;; Last-Mod:     22-Jun-24 at 18:56:31 by Mats Lidell
 ;;
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 ;;
@@ -24,18 +24,17 @@
 
 (ert-deftest hywiki-tests--hywiki-add-page--adds-file-in-wiki-folder ()
   "Verify add page creates file in wiki folder and sets hash table."
-  (let ((hsys-org-enable-smart-keys t)
-        (hywiki-directory (make-temp-file "hywiki" t))
-        (hywiki--pages-hasht nil))
+  (let* ((hsys-org-enable-smart-keys t)
+         (hywiki-directory (make-temp-file "hywiki" t))
+        (hywiki-page-file (expand-file-name "WikiWord.org" hywiki-directory)))
     (unwind-protect
-        (progn
-          (mocklet (((make-empty-file (expand-file-name "WikiWord.org" 
hywiki-directory) t) => t))
-            (should (string= (expand-file-name "WikiWord.org" hywiki-directory)
-                             (hywiki-add-page "WikiWord"))))
+        (mocklet (((make-empty-file (expand-file-name "WikiWord.org" 
hywiki-directory) t) => t))
+          (should (string= hywiki-page-file
+                           (hywiki-add-page "WikiWord")))
           ;; Verify hash table is updated
           (with-mock
             (not-called hywiki-add-page)
-            (should (string= (expand-file-name "WikiWord.org" hywiki-directory)
+            (should (string= hywiki-page-file
                              (hywiki-get-page "WikiWord")))))
       (hy-delete-dir-and-buffer hywiki-directory))))
 
@@ -45,8 +44,7 @@
   ;; added error cleanup till later if it is even needed!? No file
   ;; should be created so only happens on error!? (If this is
   ;; considered an error case that is.)
-  (let ((hywiki-directory (make-temp-file "hywiki" t))
-        (hywiki--pages-hasht nil))
+  (let ((hywiki-directory (make-temp-file "hywiki" t)))
     (unwind-protect
         (should-error (hywiki-add-page "notawikiword"))
       (hy-delete-dir-and-buffer hywiki-directory))))
@@ -56,7 +54,6 @@
   (defvar wikifile)
   (let ((hsys-org-enable-smart-keys t)
         (hywiki-directory (make-temp-file "hywiki" t))
-        (hywiki--pages-hasht nil)
         (wikifile (make-temp-file "wikifile")))
     (hywiki-mode -1)
     (unwind-protect
@@ -70,45 +67,171 @@
 (ert-deftest hywiki-tests--not-a-wikiword-unless-in-hywiki-mode ()
   "Verify WikiWord is not a WikiWord unless in `hywiki-mode'."
   (let ((hsys-org-enable-smart-keys t)
-        (hywiki-directory (make-temp-file "hywiki" t))
-        (hywiki--pages-hasht nil))
+        (hywiki-directory (make-temp-file "hywiki" t)))
     (unwind-protect
         (with-temp-buffer
+          (hywiki-mode 0)
           (insert "WikiWord")
           (goto-char 4)
-          (hywiki-mode -1)
-          (should-not (hywiki-at-wikiword))
+          (should-not (hywiki-word-at))
+          (hywiki-mode 1)
+          (should (string= "WikiWord" (hywiki-word-at))))
+      (hywiki-mode 0)
+      (hy-delete-dir-and-buffer hywiki-directory))))
+
+(ert-deftest hywiki-tests--at-wikiword-finds-word-and-section ()
+  "Verify `hywiki-word-at' finds WikiWord and section if available."
+  (let ((hywiki-directory (make-temp-file "hywiki" t)))
+    (unwind-protect
+        (with-temp-buffer
           (hywiki-mode)
-          (should (string= "WikiWord" (hywiki-at-wikiword))))
+          (insert "WikiWord")
+          (goto-char 4)
+          (should (string= "WikiWord" (hywiki-word-at)))
+
+          ;; Section
+          (goto-char (point-max))
+          (insert "#section")
+          (goto-char 4)
+          (should (string= "WikiWord#section" (hywiki-word-at)))
+
+          ;; Section with dash
+          (goto-char (point-max))
+          (insert "-subsection")
+          (goto-char 4)
+          (should (string= "WikiWord#section-subsection" (hywiki-word-at))))
       (hywiki-mode -1)
       (hy-delete-dir-and-buffer hywiki-directory))))
 
+(ert-deftest hywiki-tests--maybe-at-wikiword-beginning ()
+  "Verify `hywiki-maybe-at-wikiword-beginning' identifies if maybe at 
beginning of WikiWord."
+  (with-temp-buffer
+    (insert "WikiWord")
+    (goto-char 1)
+    (should (hywiki-maybe-at-wikiword-beginning))
+    (goto-char 2)
+    (should-not (hywiki-maybe-at-wikiword-beginning)))
+  (dolist (acceptable-char '("(" "{" "<" "\"" "'" "`" "        " " " "
" "" " "))
+    (with-temp-buffer
+      (insert (format "%sWikiWord" acceptable-char))
+      (goto-char 2)
+      (should (hywiki-maybe-at-wikiword-beginning)))))
+
+(ert-deftest hywiki-tests--in-page-p ()
+  "Verify `hywiki-in-page-p' identifies a page in and outside of the wiki 
directory."
+  (let* ((hywiki-directory (make-temp-file "hywiki" t))
+         (wiki-page (hywiki-add-page "WikiWord"))
+         (no-wiki-page (make-temp-file "hypb")))
+    (unwind-protect
+        (progn
+          (with-current-buffer (find-file-noselect no-wiki-page)
+            (should-not (hywiki-in-page-p)))
+          (with-current-buffer (find-file-noselect wiki-page)
+            (should (hywiki-in-page-p))))
+      (hy-delete-files-and-buffers (list no-wiki-page wiki-page))
+      (hy-delete-dir-and-buffer hywiki-directory))))
+
+(ert-deftest hywiki-tests--active-in-current-buffer-p ()
+  "Verify `hywiki-active-in-current-buffer-p'."
+  (let* ((hywiki-directory (make-temp-file "hywiki" t))
+         (wiki-page (hywiki-add-page "WikiWord"))
+         (hywiki-word-highlight-flag t))
+    (unwind-protect
+        (with-current-buffer (find-file-noselect wiki-page)
+          (should (hywiki-active-in-current-buffer-p))
+          (let ((hywiki-word-highlight-flag nil))
+            (should-not (hywiki-active-in-current-buffer-p)))
+          (let ((hywiki-exclude-major-modes (list 'org-mode)))
+            (should-not (hywiki-active-in-current-buffer-p)))
+          (mocklet ((hywiki-in-page-p => nil))
+            (should-not (hywiki-active-in-current-buffer-p)))
+          (dired-mode)
+          (should-not (hywiki-active-in-current-buffer-p)))
+      (hy-delete-file-and-buffer wiki-page)
+      (hy-delete-dir-and-buffer hywiki-directory))))
+
+(ert-deftest hywiki-tests--directory-get-mod-time ()
+  "Verify `hywiki-directory-get-mod-time'."
+  (mocklet ((file-readable-p => nil))
+    (should (= 0 (hywiki-directory-get-mod-time))))
+  (mocklet ((file-readable-p => t)
+            (file-attributes => '(t 0 0 0 nil (100 100 100 100) nil 0 
"drwxr-xr-x" t 0 0)))
+    (should (= 6553700 (hywiki-directory-get-mod-time)))))
+
+(ert-deftest hywiki-tests--directory-modified-p ()
+  "Verify `hywiki-directory-modified-p'."
+  (let ((hywiki--directory-mod-time 0))
+    (should (hywiki-directory-modified-p)))
+  (let ((hywiki--directory-mod-time 2))
+    (mocklet ((hywiki-directory-get-mod-time => 2))
+      (should-not (hywiki-directory-modified-p)))
+    (mocklet ((hywiki-directory-get-mod-time => 1))
+      (should (hywiki-directory-modified-p)))))
+
+(ert-deftest hywiki-tests--get-page-list ()
+  "Verify `hywiki-get-page-list' returns one WikiWord."
+  (let* ((hywiki-directory (make-temp-file "hywiki" t))
+         (wiki-page (hywiki-add-page "WikiWord")))
+    (unwind-protect
+        (progn
+          (should (equal '("WikiWord") (hywiki-get-page-list)))
+          (should (equal wiki-page (hywiki-add-page "WikiWord")))
+          (should (equal '("WikiWord") (hywiki-get-page-list))))
+      (hy-delete-file-and-buffer wiki-page)
+      (hy-delete-dir-and-buffer hywiki-directory))))
+
+(ert-deftest hywiki-tests--get-page-list-multiple-words ()
+  "Verify `hywiki-get-page-list' returns multiple WikiWords."
+  (let* ((hywiki-directory (make-temp-file "hywiki" t))
+         (basename "WikiWord")
+         (wiki-page-list nil))
+    (unwind-protect
+        (progn
+          (dolist (char '("A" "B" "C" "D" "E" "F" "G" "H" "I" "J"))
+            (push (hywiki-add-page (format "%s%s" basename char)) 
wiki-page-list))
+          (should (= 10 (length wiki-page-list)))
+          (should (= 10 (length (hywiki-get-page-list))))
+          (should (= 10 (length (seq-uniq (hywiki-get-page-list))))))
+      (hy-delete-files-and-buffers wiki-page-list)
+      (hy-delete-dir-and-buffer hywiki-directory))))
+
+(ert-deftest hywiki-tests--get-page-list-when-new-wiki-directory ()
+  "Verify `hywiki-get-page-list' is empty for new `hywiki-directory'."
+  (let* ((hywiki-directory (make-temp-file "hywiki" t))
+         (wiki-page (hywiki-add-page "WikiWord")))
+    (unwind-protect
+        (progn
+          (should (= 1 (length (hywiki-get-page-list))))
+          (let ((hywiki-directory (make-temp-file "hywiki" t)))
+            (unwind-protect
+                (progn
+                  (should (hash-empty-p (hywiki-get-page-hasht)))
+                    (should (= 0 (length (hywiki-get-page-list)))))
+              (hy-delete-dir-and-buffer hywiki-directory))))
+      (hy-delete-file-and-buffer wiki-page)
+      (hy-delete-dir-and-buffer hywiki-directory))))
+
 ;; Following two test cases for verifying proper face is some what
 ;; experimental. They need to be run in interactive mode and with the
 ;; help of hy-test-helpers:consume-input-events it seems the property
-;; can be verified. In the middle of it the "*ert*" buffer gets
-;; swapped in and the temp buffer needs to be brought back!?
+;; can be verified.
 
 (ert-deftest hywiki-tests--face-property-for-wikiword-with-wikipage ()
   "Verify WikiWord for a wiki page gets face property hywiki-word-face."
   (skip-unless (not noninteractive))
   (let* ((hsys-org-enable-smart-keys t)
          (hywiki-directory (make-temp-file "hywiki" t))
-         (hywiki--pages-hasht nil)
          (wikipage (hywiki-add-page "WikiWord")))
     (unwind-protect
         (with-temp-buffer
           (let ((buffer (current-buffer)))
-            (hywiki-mode)
+            (hywiki-mode 1)
             (insert "WikiWord")
-            (should (hact 'kbd-key "RET"))
+           (newline nil t)
             (hy-test-helpers:consume-input-events)
-            (should (string= "*ert*" (buffer-name)))
-            (set-buffer buffer)
             (goto-char 4)
-            (should (equal buffer (current-buffer)))
             (should (hproperty:but-get (point) 'face hywiki-word-face))))
-      (hywiki-mode -1)
+      (hywiki-mode 0)
       (hy-delete-file-and-buffer wikipage)
       (hy-delete-dir-and-buffer hywiki-directory))))
 
@@ -116,21 +239,16 @@
   "Verify WikiWord for no wiki page does not get face property 
hywiki-word-face."
   (skip-unless (not noninteractive))
   (let* ((hsys-org-enable-smart-keys t)
-         (hywiki-directory (make-temp-file "hywiki" t))
-         (hywiki--pages-hasht nil))
+         (hywiki-directory (make-temp-file "hywiki" t)))
     (unwind-protect
         (with-temp-buffer
           (let ((buffer (current-buffer)))
-            (hywiki-mode)
+            (hywiki-mode 0)
             (insert "WikiWord")
-            (should (hact 'kbd-key "RET"))
+           (newline nil t)
             (hy-test-helpers:consume-input-events)
-            (should (string= "*ert*" (buffer-name)))
-            (set-buffer buffer)
             (goto-char 4)
-            (should (equal buffer (current-buffer)))
             (should-not (hproperty:but-get (point) 'face hywiki-word-face))))
-      (hywiki-mode -1)
       (hy-delete-dir-and-buffer hywiki-directory))))
 
 (provide 'hywiki-tests)

Reply via email to