2 Commits 788b9e1c2f ... b6c2144f50

Author SHA1 Message Date
  Fred Gilham b6c2144f50 Add commentary select; fix xrefs 3 weeks ago
  Fred Gilham eced6fe890 Fix one of the places where the module name is removed from buffer 3 weeks ago
1 changed files with 222 additions and 121 deletions
  1. 222 121
      bible.el

+ 222 - 121
bible.el

@@ -3,10 +3,10 @@
 ;; Copyright (c) 2025-2026 Fred Gilham
 ;; Copyright (c) 2025-2026 Fred Gilham
 
 
 ;; Author: Fred Gilham <fmgilham@gmail.com>
 ;; Author: Fred Gilham <fmgilham@gmail.com>
-;; Version: 1.1.1
+;; Version: 1.2.0
 ;; Keywords: files, text, hypermedia
 ;; Keywords: files, text, hypermedia
 ;; Package-Requires: ((emacs "29.1") cl-lib dom shr)
 ;; Package-Requires: ((emacs "29.1") cl-lib dom shr)
-;; URL: https://gitbot.homedns.org/fred/bible-mode
+;; URL: https://gitbot.homedns.org/fred/bible
 
 
 ;; This file is not part of GNU Emacs.
 ;; This file is not part of GNU Emacs.
 
 
@@ -206,7 +206,8 @@ See `bible--display-lemma-hebrew'."
 
 
 (defconst bible--verse-regexp "\\(I \\|1 \\|II \\|2 \\|III \\|3 \\)??[a-zA-Z]+?[ \t\n][0-9]+[:][0-9]+")
 (defconst bible--verse-regexp "\\(I \\|1 \\|II \\|2 \\|III \\|3 \\)??[a-zA-Z]+?[ \t\n][0-9]+[:][0-9]+")
 
 
-(defvar bible--modules (lazy-completion-table bible--modules bible--list-biblical-modules))
+(defvar bible--texts (lazy-completion-table bible--texts bible--list-biblical-texts))
+(defvar bible--commentaries (lazy-completion-table bible--commentaries bible--list-biblical-commentaries))
 
 
 ;; REVIEW: I believe these chapter counts aren't the same for all modules, e.g. JPS. (FMG 5-Mar-2026)
 ;; REVIEW: I believe these chapter counts aren't the same for all modules, e.g. JPS. (FMG 5-Mar-2026)
 (defvar bible--books
 (defvar bible--books
@@ -242,25 +243,53 @@ See `bible--display-lemma-hebrew'."
 ;; TODO: Add abbreviations found in other documents/commentaries? (FMG 5-Mar-2026)
 ;; TODO: Add abbreviations found in other documents/commentaries? (FMG 5-Mar-2026)
 (defvar bible--book-name-abbreviations
 (defvar bible--book-name-abbreviations
   '(;; Old Testament
   '(;; Old Testament
-    ("Ge"     . "Genesis")         ("Ex"    . "Exodus")           ("Le"   . "Leviticus")     ("Nu"    . "Numbers")
-    ("De"     . "Deuteronomy")     ("Js"    . "Joshua")           ("Jg"   . "Judges")        ("Judg"   . "Judges")
-    ("Ru"    . "Ruth")             ("1 Samuel"     . "I Samuel")  ("I Sa"  . "I Samuel")     ("1 Sa" . "I Samuel")
-    ("2 Samuel"     . "II Samuel") ("II Sa" . "II Samuel")        ("2 Sa" . "II Samuel")     ("1 Kings"  . "I Kings")
-    ("I Ki"  . "I Kings")          ("1 Ki" . "I Kings")           ("2 Kings"      . "II Kings") ("II Ki" . "II Kings")
-    ("2 Ki" . "II Kings")          ("1 Chronicles" . "I Chronicles")  ("I Ch"  . "I Chronicles")  ("1 Ch" . "I Chronicles")
+    ("Ge" . "Genesis") ("Gen" . "Genesis")
+    ("Ex" . "Exodus")
+    ("Le" . "Leviticus")
+    ("Nu" . "Numbers")
+    ("De" . "Deuteronomy") ("Deu" . "Deuteronomy")
+    ("Js" . "Joshua")
+    ("Jg" . "Judges")  ("Judg" . "Judges")
+    ("Ru" . "Ruth")
+    ("1 Samuel" . "I Samuel") ("I Sa" . "I Samuel") ("1 Sa" . "I Samuel")
+    ("2 Samuel" . "II Samuel") ("II Sa" . "II Samuel") ("2 Sa" . "II Samuel")
+    ("1 Kings" . "I Kings") ("I Ki" . "I Kings") ("1 Ki" . "I Kings")
+    ("2 Kings" . "II Kings") ("II Ki" . "II Kings") ("2 Ki" . "II Kings")
+    ("1 Chronicles" . "I Chronicles")  ("I Ch" . "I Chronicles")  ("1 Ch" . "I Chronicles")
     ("2 Chronicles" . "II Chronicles") ("II Ch" . "II Chronicles") ("2 Ch" . "II Chronicles")
     ("2 Chronicles" . "II Chronicles") ("II Ch" . "II Chronicles") ("2 Ch" . "II Chronicles")
-    ("Ezr"  . "Ezra")          ("Ne"    . "Nehemiah")
-    ("Es"     . "Esther")          ("Jb"    . "Job")              ("Ps"   . "Psalms")        ("Pr"    . "Proverbs")
-    ("Ec"     . "Ecclesiastes")    ("So"    . "Song of Solomon")  ("Is"   . "Isaiah")        ("Je"    . "Jeremiah")
-    ("La"     . "Lamentations")    ("Ez"    . "Ezekiel")          ("Da"   . "Daniel")        ("Ho"    . "Hosea")
-    ("Joe"    . "Joel")            ("Am"    . "Amos")             ("Ob"   . "Obadiah")       ("Jon"   . "Jonah")
-    ("Mi"     . "Micah")           ("Na"    . "Nahum")            ("Ha"   . "Habakkuk")      ("Zep"   . "Zephaniah")
-    ("Hag"    . "Haggai")          ("Ze"    . "Zechariah")        ("Mal"  . "Malachi")
+    ("Ezr" . "Ezra")
+    ("Ne" . "Nehemiah")
+    ("Es" . "Esther")
+    ("Jb" . "Job")
+    ("Ps" . "Psalms")
+    ("Pr" . "Proverbs")
+    ("Ec" . "Ecclesiastes")
+    ("So" . "Song of Solomon")
+    ("Is" . "Isaiah")
+    ("Je" . "Jeremiah")
+    ("La" . "Lamentations")
+    ("Ez" . "Ezekiel")
+    ("Da" . "Daniel")
+    ("Ho" . "Hosea")
+    ("Joe" . "Joel")
+    ("Am" . "Amos")
+    ("Ob" . "Obadiah")
+    ("Jon" . "Jonah")
+    ("Mi" . "Micah")
+    ("Na" . "Nahum")
+    ("Ha" . "Habakkuk")
+    ("Zep" . "Zephaniah")
+    ("Hag" . "Haggai")
+    ("Ze"    . "Zechariah")
+    ("Mal"  . "Malachi")
 
 
     ;; New Testament
     ;; New Testament
     ;; Added AbbottSmith lexicon abbreviations to allow proper following of cross references in lexicon buffers.
     ;; Added AbbottSmith lexicon abbreviations to allow proper following of cross references in lexicon buffers.
     ("Mt" . "Matthew") ("Matt" . "Matthew")
     ("Mt" . "Matthew") ("Matt" . "Matthew")
-    ("Mk" . "Mark") ("Lk" . "Luke") ("Jo" . "John") ("Ac" . "Acts")
+    ("Mk" . "Mark")
+    ("Lk" . "Luke")
+    ("Jo" . "John")
+    ("Ac" . "Acts")
     ("Ro" . "Romans") ("Rom" . "Romans")
     ("Ro" . "Romans") ("Rom" . "Romans")
     ("1 Corintihans" . "I Corinthians") ("I Co" . "I Corinthians") ("1 Co" . "I Corinthians") ("ICor" . "I Corinthians")
     ("1 Corintihans" . "I Corinthians") ("I Co" . "I Corinthians") ("1 Co" . "I Corinthians") ("ICor" . "I Corinthians")
     ("2 Corinthians" . "II Corinthians") ("II Co" . "II Corinthians") ("2 Co" . "II Corinthians") ("IICor" . "II Corinthians")
     ("2 Corinthians" . "II Corinthians") ("II Co" . "II Corinthians") ("2 Co" . "II Corinthians") ("IICor" . "II Corinthians")
@@ -274,15 +303,15 @@ See `bible--display-lemma-hebrew'."
     ("2 Timothy" . "II Timothy")  ("II Ti" . "II Timothy") ("2 Ti" . "II Timothy") ("IITim" . "II Timothy")
     ("2 Timothy" . "II Timothy")  ("II Ti" . "II Timothy") ("2 Ti" . "II Timothy") ("IITim" . "II Timothy")
     ("Tit" . "Titus")
     ("Tit" . "Titus")
     ("Phm" . "Philemon") ("Phlm" . "Philemon")
     ("Phm" . "Philemon") ("Phlm" . "Philemon")
-    ("He"   . "Hebrews") ("Heb"   . "Hebrews")
-    ("Ja"    . "James") ("Jas"    . "James")
-    ("1 Peter" . "I Peter")   ("I Pe"   . "I Peter")  ("1 Pe" . "I Peter")
-    ("2 Peter" . "II Peter")  ("II Pe"  . "II Peter") ("2 Pe" . "II Peter") ("IIPet" . "II Peter")
-    ("1 John"  . "I John")    ("I Jo"   . "I John")   ("1 Jo" . "I John") ("IJohn" . "I John")
-    ("2 John"  . "II John")   ("II Jo"  . "II John")  ("2 Jo" . "II John")   ("IIJohn" . "II John")
-    ("3 John"  . "III John")  ("III Jo" . "III John") ("3 Jo" . "III John") ("IIIJohn" . "III John")
-    ("Ju"    . "Jude")
-    ("Re"   . "Revelation of John") ("Rev"   . "Revelation of John"))
+    ("He" . "Hebrews") ("Heb" . "Hebrews")
+    ("Ja" . "James") ("Jas" . "James")
+    ("1 Peter" . "I Peter") ("I Pe" . "I Peter") ("1 Pe" . "I Peter")
+    ("2 Peter" . "II Peter")  ("II Pe" . "II Peter") ("2 Pe" . "II Peter") ("IIPet" . "II Peter")
+    ("1 John" . "I John") ("I Jo" . "I John") ("1 Jo" . "I John") ("IJohn" . "I John")
+    ("2 John" . "II John") ("II Jo"  . "II John") ("2 Jo" . "II John") ("IIJohn" . "II John")
+    ("3 John" . "III John") ("III Jo" . "III John") ("3 Jo" . "III John") ("IIIJohn" . "III John")
+    ("Ju" . "Jude")
+    ("Re" . "Revelation of John") ("Rev" . "Revelation of John"))
   "A-list of abbreviations for Bible books.")
   "A-list of abbreviations for Bible books.")
 
 
 ;;;;; Book / chapter
 ;;;;; Book / chapter
@@ -345,7 +374,8 @@ See `bible--display-lemma-hebrew'."
 
 
 ;;;;; Misc key bindings
 ;;;;; Misc key bindings
 
 
-(define-key bible-map "m" 'bible-select-module)
+(define-key bible-map "T" 'bible-select-text)
+(define-key bible-map "C" 'bible-select-commentary)
 (define-key bible-map "w" 'bible-toggle-word-study)
 (define-key bible-map "w" 'bible-toggle-word-study)
 (define-key bible-map "l" 'bible-toggle-red-letter)
 (define-key bible-map "l" 'bible-toggle-red-letter)
 
 
@@ -359,35 +389,6 @@ See `bible--display-lemma-hebrew'."
             [menu-bar bible split-display]
             [menu-bar bible split-display]
             '("Split Display" . bible-split-display))
             '("Split Display" . bible-split-display))
 
 
-;;;;; Search
-
-(define-key bible-map "/" 'bible-search)
-(define-key bible-map "s" 'bible-search)
-(define-key bible-map
-            [menu-bar bible search]
-            '("Search" . bible-search))
-
-(define-key bible-map "r" 'bible-set-search-range)
-(define-key bible-map
-            [menu-bar bible range]
-            '("Set Search Range" . bible-set-search-range))
-
-(defconst bible-search-mode-map (make-keymap))
-(define-key bible-search-mode-map "s" 'bible-search)
-(define-key bible-search-mode-map "w" 'bible-toggle-word-study)
-(define-key bible-search-mode-map "n" 'bible-next-search-item)
-(define-key bible-search-mode-map "p" 'bible-previous-search-item)
-(define-key bible-search-mode-map (kbd "RET") 'bible-search-mode-follow-verse)
-
-;;;;; Term display
-
-(defconst bible-term-hebrew-mode-map (make-sparse-keymap))
-(define-key bible-term-hebrew-mode-map "z" 'text-scale-adjust)
-
-(defconst bible-term-greek-mode-map (make-sparse-keymap))
-(define-key bible-term-greek-mode-map "z" 'text-scale-adjust)
-(define-key bible-term-greek-mode-map [mouse-1] 'bible-search-mode-follow-xref)
-
 ;;;;; Navigation
 ;;;;; Navigation
 
 
 (define-key bible-map "p" 'bible-previous-chapter)
 (define-key bible-map "p" 'bible-previous-chapter)
@@ -423,6 +424,33 @@ See `bible--display-lemma-hebrew'."
 (define-key bible-map "\C-n" 'next-logical-line)
 (define-key bible-map "\C-n" 'next-logical-line)
 (define-key bible-map "\C-p" 'previous-logical-line)
 (define-key bible-map "\C-p" 'previous-logical-line)
 
 
+;;;;; Search
+
+(define-key bible-map "/" 'bible-search)
+(define-key bible-map "s" 'bible-search)
+(define-key bible-map
+            [menu-bar bible search]
+            '("Search" . bible-search))
+
+(define-key bible-map "r" 'bible-set-search-range)
+(define-key bible-map
+            [menu-bar bible range]
+            '("Set Search Range" . bible-set-search-range))
+
+(defconst bible-search-mode-map (make-keymap))
+(define-key bible-search-mode-map "s" 'bible-search)
+(define-key bible-search-mode-map "w" 'bible-toggle-word-study)
+(define-key bible-search-mode-map "n" 'bible-next-search-item)
+(define-key bible-search-mode-map "p" 'bible-previous-search-item)
+(define-key bible-search-mode-map (kbd "RET") 'bible-search-mode-follow-verse)
+
+;;;;; Term display
+
+(defconst bible-term-mode-map (make-sparse-keymap))
+(define-key bible-term-mode-map "z" 'text-scale-adjust)
+(define-key bible-term-mode-map [mouse-1] 'bible-search-mode-follow-xref)
+
+
 (defun bible-toggle-display-diatheke ()
 (defun bible-toggle-display-diatheke ()
   "Toggle diatheke args display."
   "Toggle diatheke args display."
   (interactive)
   (interactive)
@@ -491,9 +519,13 @@ See `bible--display-lemma-hebrew'."
             [menu-bar bible sepp]
             [menu-bar bible sepp]
             '(menu-item '"--"))
             '(menu-item '"--"))
 
 
+(define-key bible-map
+            [menu-bar bible select-biblical-commentary]
+            '("Select Commentary" . bible-display-available-commentaries))
+
 (define-key bible-map
 (define-key bible-map
             [menu-bar bible select-biblical-text]
             [menu-bar bible select-biblical-text]
-            '("Select Module" . bible-display-available-modules))
+            '("Select Text" . bible-display-available-texts))
 
 
 ;;;; Terms
 ;;;; Terms
 
 
@@ -556,25 +588,26 @@ This command is run by clicking on text, not directly by the user."
   (setq buffer-read-only t)
   (setq buffer-read-only t)
   (visual-line-mode t))
   (visual-line-mode t))
 
 
-(define-derived-mode bible-term-hebrew-mode special-mode "Bible Term (Hebrew)"
-  "Mode for researching Hebrew terms in the Bible.
-\\{bible-term-hebrew-mode-map}"
+
+(define-derived-mode bible-term-mode special-mode "Bible Term"
+  "Mode for researching terms in the Bible.
+\\{bible-term-mode-map}"
   (buffer-disable-undo)
   (buffer-disable-undo)
   (font-lock-mode t)
   (font-lock-mode t)
-  (use-local-map bible-term-hebrew-mode-map)
+  (use-local-map bible-term-mode-map)
   (setq buffer-read-only t)
   (setq buffer-read-only t)
   (visual-line-mode t))
   (visual-line-mode t))
 
 
-(define-derived-mode bible-term-greek-mode special-mode "Bible Term (Greek)"
+(define-derived-mode bible-term-hebrew-mode bible-term-mode "Bible Term (Hebrew)"
+  "Mode for researching Hebrew terms in the Bible.
+\\{bible-term-hebrew-mode-map}")
+
+(define-derived-mode bible-term-greek-mode bible-term-mode "Bible Term (Greek)"
   "Mode for researching Greek terms in the Bible.
   "Mode for researching Greek terms in the Bible.
-\\{bible-term-greek-mode-map}"
-  (buffer-disable-undo)
-  (font-lock-mode t)
-  (use-local-map bible-term-greek-mode-map)
-  (setq buffer-read-only t)
-  (visual-line-mode t))
+\\{bible-term-greek-mode-map}")
 
 
-(define-derived-mode bible-module-select-mode special-mode "Select Text Module"
+
+(define-derived-mode bible-module-select-mode special-mode "Select Module"
   (buffer-disable-undo)
   (buffer-disable-undo)
   (font-lock-mode t)
   (font-lock-mode t)
   (setq buffer-read-only t))
   (setq buffer-read-only t))
@@ -667,10 +700,18 @@ specifies the module to use."
         (setq bible-search-range nil)
         (setq bible-search-range nil)
       (setq bible-search-range range))))
       (setq bible-search-range range))))
 
 
-(defun bible-select-module ()
+(defun bible-select-text ()
   "Ask user for a new text module for the current `bible' buffer."
   "Ask user for a new text module for the current `bible' buffer."
   (interactive)
   (interactive)
-  (let ((module (completing-read "Module: " bible--modules)))
+  (let ((module (completing-read "Text: " bible--texts)))
+    (unless (string= module "")
+      (setq-default bible-module module)
+      (bible--display module))))
+
+(defun bible-select-commentary ()
+  "Ask user for a new text module for the current `bible' buffer."
+  (interactive)
+  (let ((module (completing-read "Commentary: " bible--commentaries)))
     (unless (string= module "")
     (unless (string= module "")
       (setq-default bible-module module)
       (setq-default bible-module module)
       (bible--display module))))
       (bible--display module))))
@@ -739,6 +780,7 @@ Handle abbreviations from lexicon module (AbbottSmith)."
          book
          book
          chapter
          chapter
          verse)
          verse)
+    (message "Trying to follow %s" xref)
     (cond ((= (length verse-ref) 2) ; Mat 5 or the like
     (cond ((= (length verse-ref) 2) ; Mat 5 or the like
            (setq book-abbrev (car verse-ref)
            (setq book-abbrev (car verse-ref)
                  chapter-verse (split-string (cadr verse-ref) ":")))
                  chapter-verse (split-string (cadr verse-ref) ":")))
@@ -823,21 +865,13 @@ MODULE is the text module to use and defaults to the current module."
       (apply #'call-process args))
       (apply #'call-process args))
     (buffer-string)))
     (buffer-string)))
 
 
-;; TODO: Bible chapter titles mostly appear in Psalms. This code works
-;;       OK except for Psalm 119 which changes the chapter title to
-;;       indicate the Hebrew letter that each verse of a stanza begins
-;;       with.
-;;
-;;       Chapter titles seem to be part of each verse in the modules I saw.
-;;
-;;       Fixing this issue would require keeping track of the current
-;;       chapter title and emitting the title whenever it changed.
-;;       Since there is (AFAIK) only one chapter in the Bible that has
-;;       this issue, it doesn't seem like a high priority now.
 (defvar-local bible-chapter-title nil
 (defvar-local bible-chapter-title nil
   "Text preceding start of chapter.
   "Text preceding start of chapter.
 Mostly in Psalms, like `Of David' or the like.")
 Mostly in Psalms, like `Of David' or the like.")
 
 
+(defvar-local bible-level "0"
+  "Used by some modules for indentation and line breaks.")
+
 ;;;; Greek and Hebrew lexeme and morpheme tooltip rendering.
 ;;;; Greek and Hebrew lexeme and morpheme tooltip rendering.
 
 
 ;;;;; Hash tables for Lexical definitions.
 ;;;;; Hash tables for Lexical definitions.
@@ -1187,7 +1221,6 @@ in buffer)."
               (add-face-text-property refstart (point) '(:foreground "blue"))
               (add-face-text-property refstart (point) '(:foreground "blue"))
               (put-text-property refstart (point) 'keymap bible-lemma-keymap))))))))
               (put-text-property refstart (point) 'keymap bible-lemma-keymap))))))))
 
 
-
 (defun bible-new-line ()
 (defun bible-new-line ()
   "Ensure beginning of line.  Try to avoid redundant blank lines."
   "Ensure beginning of line.  Try to avoid redundant blank lines."
   (unless (= (current-column) 0)
   (unless (= (current-column) 0)
@@ -1199,8 +1232,6 @@ Since each verse will have a `title' tag, keep track and only emit a
 title when the new title in `title-node' is different from the one
 title when the new title in `title-node' is different from the one
 stored in `bible-chapter-title'."
 stored in `bible-chapter-title'."
   (unless (equal bible-chapter-title title-node)
   (unless (equal bible-chapter-title title-node)
-;;    (unless bible-chapter-title
-;;      (goto-char (point-min)))
     (setq-local bible-chapter-title title-node)
     (setq-local bible-chapter-title title-node)
     (let ((title-text (bible-dom-texts bible-chapter-title)))
     (let ((title-text (bible-dom-texts bible-chapter-title)))
       (let ((refstart (point))
       (let ((refstart (point))
@@ -1212,6 +1243,23 @@ stored in `bible-chapter-title'."
 	(setq refend (point))
 	(setq refend (point))
 	(put-text-property refstart refend 'face 'bold)))))
 	(put-text-property refstart refend 'face 'bold)))))
 
 
+;; These tags appear in ESV modules (and maybe others?)
+;; REVIEW: Is this right? (FMG 5-Mar-2026)
+(defun bible--level-tag (node)
+  "Indent or break line as dictated by NODE."
+  (let ((type (dom-attr node 'type))
+	(level (dom-attr node 'level)))
+    (cond ((and type (string-equal-ignore-case type "x-br"))
+	   (newline))
+          ((and type (string-equal-ignore-case type "x-indent"))
+           (insert "\t"))
+	  ;; REVIEW: Some modules use `level' tag but
+	  ;; not in a consistent way. (FMG 7-Mar-2026)
+	  ((equal level "1")
+	   (insert " "))
+          ((equal level "2")
+	   (newline)))))
+
 (defun bible--insert-domnode-recursive (node &optional iproperties)
 (defun bible--insert-domnode-recursive (node &optional iproperties)
   "Recursively parse domnode NODE obtained from `libxml-parse-html-region'.
   "Recursively parse domnode NODE obtained from `libxml-parse-html-region'.
 Inserts resulting text into active buffer with properties specified in
 Inserts resulting text into active buffer with properties specified in
@@ -1243,7 +1291,9 @@ In processing subnodes, each case will prepend a space if it needs it."
 		;; talking about YOU, Psalm 119.
 		;; talking about YOU, Psalm 119.
 		(if bible-chapter-title 
 		(if bible-chapter-title 
 		    (bible--insert-title subnode) ; Middle of chapter.
 		    (bible--insert-title subnode) ; Middle of chapter.
-		  (save-excursion (goto-char (point-min)) (bible--insert-title subnode)))) ; Beginning of chapter.
+		  (save-excursion
+		    (goto-char (point-min))
+		    (bible--insert-title subnode)))) ; Beginning of chapter.
 	       ;; Font tag should be ignored, treat as if 'w
 	       ;; Font tag should be ignored, treat as if 'w
                ('font (insert " ") (bible--process-word subnode iproperties))
                ('font (insert " ") (bible--process-word subnode iproperties))
                ('hi (when (equal (dom-attr subnode 'type) "bold")
                ('hi (when (equal (dom-attr subnode 'type) "bold")
@@ -1258,20 +1308,7 @@ In processing subnodes, each case will prepend a space if it needs it."
                ;; 'q is used for red letter.
                ;; 'q is used for red letter.
                ;; NASB Module uses 'seg to indicate OT quotations (and others?).
                ;; NASB Module uses 'seg to indicate OT quotations (and others?).
 	       ((or 'body 'seg 'p 'q) (bible--insert-domnode-recursive subnode iproperties))
 	       ((or 'body 'seg 'p 'q) (bible--insert-domnode-recursive subnode iproperties))
-               ;; These tags appear in ESV modules (and maybe others?)
-               ;; REVIEW: Is this right? (FMG 5-Mar-2026)
-               ('l
-                (let ((attributes (dom-attributes subnode)))
-                  (cond ((equal (dom-attr subnode 'type) "x-br")
-                         (bible-new-line))
-                        ((equal (dom-attr subnode 'type) "x-indent")
-                         (insert "\t"))
-                        ((dom-attr subnode 'level)
-                         (let ((indent (string-to-number (alist-get 'level attributes))))
-			   ;; REVIEW: Some modules use `level' tag but
-			   ;; not in a consistent way. (FMG 7-Mar-2026)
-                           (cond ((= indent 1) (insert " "))
-                                 ((= indent 2) (bible-new-line) (insert "\t\t"))))))))
+               ('l (bible--level-tag subnode))
 	       ;; REVIEW: divine name handling doesn't seem to work the same
 	       ;; REVIEW: divine name handling doesn't seem to work the same
 	       ;;         with all modules.
 	       ;;         with all modules.
 	       ('divinename (bible-handle-divine-name subnode))
 	       ('divinename (bible-handle-divine-name subnode))
@@ -1288,9 +1325,10 @@ In processing subnodes, each case will prepend a space if it needs it."
                   (let ((start (point)))
                   (let ((start (point)))
                     (insert " " word)
                     (insert " " word)
                     (let ((end (point)))
                     (let ((end (point)))
+		      (message "crossreferencing %s" (buffer-substring start end))
                       (put-text-property start end 'xref word)
                       (put-text-property start end 'xref word)
-                      (put-text-property start end 'keymap bible-search-mode-map)
-                      (put-text-property start end 'help-echo (concat "Go to " word " (doesn't work yet)"))
+                      (put-text-property start end 'keymap bible-term-mode-map)
+                      (put-text-property start end 'help-echo (concat "Go to " word " (incomplete feature)"))
                       (add-face-text-property start end '(:foreground "blue"))))))
                       (add-face-text-property start end '(:foreground "blue"))))))
                ;; Various text properties---ignore for now
                ;; Various text properties---ignore for now
                ((or 'b 'u) (bible--insert-domnode-recursive subnode iproperties))
                ((or 'b 'u) (bible--insert-domnode-recursive subnode iproperties))
@@ -1303,7 +1341,8 @@ In processing subnodes, each case will prepend a space if it needs it."
                     (add-face-text-property (- (point) (length word)) (point) '(:foreground "gray50")))))))))))
                     (add-face-text-property (- (point) (length word)) (point) '(:foreground "gray50")))))))))))
 
 
 (defun bible--display (&optional module verse)
 (defun bible--display (&optional module verse)
-  "Render a page of Bible text.
+  "Render a page (chapter) of a Bible module.
+Defaults to using `bible-module'.
 If optional argument MODULE is supplied, use that module for display.
 If optional argument MODULE is supplied, use that module for display.
 If optional argument VERSE is supplied, set cursor at verse."
 If optional argument VERSE is supplied, set cursor at verse."
   (when module (setq-local bible-module module))
   (when module (setq-local bible-module module))
@@ -1375,36 +1414,97 @@ If optional argument VERSE is supplied, set cursor at verse."
     (when verse
     (when verse
       (re-search-forward (concat " ?" (number-to-string verse)) nil t)))
       (re-search-forward (concat " ?" (number-to-string verse)) nil t)))
 
 
-;;;; Modules (Bible texts)
+;;;; Modules (Bible texts, commentaries)
+
+(defun compare-module-names (n1 n2)
+  "Compare N1 and N2, ignoring case, using collation order."
+  (string-collate-lessp n1 n2 nil t))
+
+
+(defun bible--get-biblical-modules ()
+  "Populate `bible--texts' and `bible--commentaries' lists."
+  (let ((lines 
+	 (split-string
+	  (bible--exec-diatheke "modulelist" nil "plain" "system")
+	  "[\n\r]+"))
+	(texts nil)
+	(commentaries nil)
+	(doing-texts nil)
+	(doing-commentaries nil))
+    (setq bible--texts nil)
+    (setq bible--commentaries nil)
+    (catch 'done
+      (dolist (line lines)
+	(when doing-texts
+	  (push (split-string line " : ") texts))
+	(when doing-commentaries
+	  (push (split-string line " : ") commentaries))
+	(when (string-equal line "Biblical Texts:")
+	  (setq doing-texts t))
+	(when (string-equal line "Commentaries:")
+	  (setq doing-texts nil)
+	  (pop texts) ; Remove `Commentaries:' line from `bible--texts'.
+	  (setq doing-commentaries t))
+	(when (string-equal line "Lexicons / Dictionaries:")
+	  (pop commentaries) ; Remove `Lexicons / Dictionaries:' line
+			     ; from bible--commentaries.
+	  (throw 'done nil))))
+    (setq bible--texts (sort texts :key #'car :lessp #'compare-module-names))
+    (setq bible--commentaries (sort commentaries :key #'car :lessp #'compare-module-names)))
+  nil)
+
+
+
+(defun bible--list-biblical-texts ()
+  "Return a list of accessible Biblical Text modules."
+  (bible--get-biblical-modules) ; Make sure the lists are fresh.
+  bible--texts)
 
 
-(defun bible--list-biblical-modules ()
+(defun bible--list-biblical-commentaries ()
   "Return a list of accessible Biblical Text modules."
   "Return a list of accessible Biblical Text modules."
-  (let ((text (bible--exec-diatheke "modulelist" nil nil "system"))
-        modules)
-    (catch 'done
-      (dolist (line (split-string text "[\n\r]+"))
-        (when (equal line "Commentaries:")
-          (throw 'done nil))
-        (unless (equal "Biblical Texts:" line)
-          (push (split-string line " : ") modules))))
-    (reverse modules)))
+  (bible--get-biblical-modules) ; Make sure the lists are fresh.
+  bible--commentaries)
 
 
 (defconst bible-module-map (make-keymap))
 (defconst bible-module-map (make-keymap))
 (define-key bible-module-map [mouse-1] 'bible-pick-module)
 (define-key bible-module-map [mouse-1] 'bible-pick-module)
 (define-key bible-module-map (kbd "RET") 'bible-pick-module)
 (define-key bible-module-map (kbd "RET") 'bible-pick-module)
 
 
 
 
-(defun bible-display-available-modules ()
+(defun bible-display-available-texts ()
+  "Display available modules, allow user to select."
+  (interactive)
+  (bible--get-biblical-modules) ; Make sure lists are fresh.
+  (with-current-buffer (get-buffer-create "Texts")
+    (bible-module-select-mode)
+    (let ((buffer-read-only nil))
+      (erase-buffer)
+      (setq-local tab-stop-list '(25))
+      (dolist (text bible--texts)
+        (let ((name (string-trim (car text)))
+              (description (string-trim-left (cadr text))))
+          (insert
+           (propertize (string-trim name)
+                       'face 'bold
+                       'module name
+                       'help-echo (concat "Select " name)
+                       'keymap bible-module-map))
+          (move-to-tab-stop)
+          (insert (format "%s\n" description)))))
+    (goto-char (point-min))
+    (pop-to-buffer (current-buffer) nil t)))
+
+(defun bible-display-available-commentaries ()
   "Display available modules, allow user to select."
   "Display available modules, allow user to select."
   (interactive)
   (interactive)
-  (with-current-buffer (get-buffer-create "Modules")
+  (bible--get-biblical-modules) ; Make sure lists are fresh.
+  (with-current-buffer (get-buffer-create "Commentaries")
     (bible-module-select-mode)
     (bible-module-select-mode)
     (let ((buffer-read-only nil))
     (let ((buffer-read-only nil))
       (erase-buffer)
       (erase-buffer)
       (setq-local tab-stop-list '(25))
       (setq-local tab-stop-list '(25))
-      (dolist (mod (bible--list-biblical-modules))
-        (let ((name (string-trim (car mod)))
-              (description (string-trim-left (cadr mod))))
+      (dolist (commentary bible--commentaries)
+        (let ((name (string-trim (car commentary)))
+              (description (string-trim-left (cadr commentary))))
           (insert
           (insert
            (propertize (string-trim name)
            (propertize (string-trim name)
                        'face 'bold
                        'face 'bold
@@ -1460,7 +1560,7 @@ If optional argument VERSE is supplied, set cursor at verse."
              "III " "3"
              "III " "3"
              matchstr))))
              matchstr))))
          verses)))
          verses)))
-    (sort verses #'string-version-lessp)
+    (sort verses :in-place t :lessp #'string-version-lessp)
     (dolist (verse verses)
     (dolist (verse verses)
       (if query-verses
       (if query-verses
           (setq query-verses (concat query-verses ";" verse))
           (setq query-verses (concat query-verses ";" verse))
@@ -1471,8 +1571,9 @@ If optional argument VERSE is supplied, set cursor at verse."
       (erase-buffer)
       (erase-buffer)
       (bible--insert-domnode-recursive (dom-by-tag html-dom-tree 'body) nil))
       (bible--insert-domnode-recursive (dom-by-tag html-dom-tree 'body) nil))
     (goto-char (point-min))
     (goto-char (point-min))
+    ;; Remove module name from buffer.
     (save-excursion
     (save-excursion
-      (while (re-search-forward (concat "^.*" module) nil t)
+      (while (re-search-forward (concat "^.*" module ".*$") nil t)
         (replace-match ""))))
         (replace-match ""))))
   (setq mode-name (concat "Bible Search (" module))
   (setq mode-name (concat "Bible Search (" module))
   (when bible-search-range
   (when bible-search-range