Prechádzať zdrojové kódy

Miscellaneous cleanups and improvements to tooltips.

Fred Gilham 1 mesiac pred
rodič
commit
93eb90d8b4
1 zmenil súbory, kde vykonal 227 pridanie a 193 odobranie
  1. 227 193
      bible.el

+ 227 - 193
bible.el

@@ -20,18 +20,52 @@
 ;; Biblical texts provided by the Sword project.
 ;; Word study is also supported.
 
-;;; Usage:
+;;; Installation:
 
 ;; First install `diatheke'.  On Debian/Ubuntu it's in the `diatheke'
 ;; package. In other distributions it might be in the sword package.
 
+;; Next get the Bible texts (modules) you want to use. This can be
+;; done with the installmgr utility, or if you use a program like
+;; BibleTime or Xiphos you can use the GUI interface that they
+;; provide.
+;;
+;; The code is written to work well with the following modules:
+;;
+;; KJV --- has Strongs references for OT, Strongs references and
+;; Robinson morphology codes for NT.
+;;
+;; NASB --- has Strongs references.
+;;
+;; AbbottSmithStrongs --- A fairly extensive Greek lexicon
+;;
+;; BDBGlosses_Strongs --- A Hebrew lexicon, more extensive than
+;; StrongsRealHebrew.
+;;
+;; StrongsRealGreek / StrongsRealHebrew --- Shorter Greek and Hebrew
+;; lexicons.
+;;
+;; Robinson --- Morphological codes 
+;;
+;; Packard --- Morphological codes (used by LXX which is a
+;; Morphologically tagged version of the Septuagint)
+;;
+;; OSHM --- Hebrew morphological codes used by OSHB.
+;;
+;; OSHB --- Hebrew Bible with Strongs references and morphological
+;; codes.
+
 ;; For Windows I found that you can simply install the Xiphos package.
 ;; It includes the Sword library and its utilities including diatheke,
 ;; installmgr and mkfastmod. Add the "Program Files\Xiphos\bin" path
 ;; to your execution path.
 
+;;; Usage:
+
 ;; Use M-x `bible-open' to open a Bible buffer.
 ;; Use C-h f `bible' to see available keybindings.
+;; The program also installs a Bible menu with keybindings and other
+;; commands.
 
 ;; You may customize `bible-module' to set a default browsing
 ;; module, as well as `bible-word-study-enabled' to enable word
@@ -51,7 +85,7 @@
 ;; references. This is for red letters, purple highlighting of the
 ;; verse numbers, bold face of the divine name in the OT and so on.
 
-;; If strongs tags and/or morphological tags are present, they are
+;; If Strongs tags and/or morphological tags are present, they are
 ;; looked up in appropriate lexical and morphological modules and used
 ;; to add tooltips to the text so that mousing over words will bring
 ;; up a tooltip with information about the word. Clicking on a word
@@ -60,12 +94,11 @@
 
 ;;; Code:
 
-
 ;;;; Requirements
 (require 'dom)
 (require 'shr)
 
-;; Turn off tool bar mode because we want the pixels....
+;; Turn off tool bar mode because we are greedy for pixels....
 (tool-bar-mode -1)
 
 ;;;; Variables
@@ -94,7 +127,10 @@
 
 
 (defcustom bible-greek-lexicon
-  "AbbottSmith"
+  ;; AbbottSmithStrongs now has both links to lemmas and definitions
+  ;; keyed by lemma. So we only need the AbbottSmithStrongs lexicon
+  ;; and not the AbbottSmith lexicon.
+  "AbbottSmithStrongs" 
   "Lexicon used for displaying definitions of Greek words using Strong's codes."
   :type '(string :tag "Lexicon module (e.g. \"StrongsRealGreek\").")
   :local nil
@@ -103,10 +139,9 @@
 
 (defcustom bible-use-index-for-lexicon t
   "Some lexicons are accessed by lemmas rather than Strong's numbers.
-Use an index to look up lemmas from Strong's numbers so these lexicons can
-be used.  Examples of this type of lexicon are AbbottSmith and
-LiddellScott.  XXX LiddellScott currently doesn't work.  XXX AbbottSmithStrongs
-now has the complete entries instead of just links."
+Use an index to look up lemmas from Strong's numbers so these lexicons
+can be used. XXX AbbottSmithStrongs now has both links and complete
+entries instead of just links."
   :type 'boolean
   :local nil
   :group 'bible)
@@ -129,15 +164,19 @@ which are of the form
   :local nil
   :group 'bible)
 
+
+;;; XXX The Hebrew lexicons differ on whether they accept keys of the
+;;; form `Hnnnn' or `nnnn'. The code does not yet handle this
+;;; correctly, so stick with the following.
 (defcustom bible-hebrew-lexicon
-  "StrongsRealHebrew"
+  "BDBGlosses_Strongs" ; This seems to work
   "Lexicon used for displaying definitions of Hebrew words using Strong's codes."
   :type '(string :tag "Lexicon module (e.g. \"StrongsRealHebrew\")")
   :local nil
   :group 'bible)
 
 (defcustom bible-hebrew-lexicon-short
-  "BDBGlosses_Strongs" ; This seems to work
+  "StrongsRealHebrew"
   "Lexicon used for displaying definitions of Hebrew words in tooltips."
   :type '(string :tag "Lexicon module (e.g. \"StrongsRealHebrew\")")
   :local nil
@@ -274,9 +313,6 @@ which are of the form
 (defvar-local bible-has-morphology nil
   "Set if the module being displayed has morphology availabile.")
 
-
-;; (defvar bible--current-module nil)
-
 ;;;; Keymaps
 
 ;;;; N.B. Bible menu items appear in reverse order of their
@@ -416,6 +452,9 @@ which are of the form
   "Query used in toggles (word study and red letter).")
 
 (defvar bible-use-tooltips t)
+(setq tooltip-delay 1)
+(setq tooltip-short-delay .5)
+(setq use-system-tooltips nil)
 
 (defun bible-toggle-tooltips ()
   "Toggle use of tooltips to display lexical/morphological items."
@@ -425,7 +464,6 @@ which are of the form
   (setq tooltip-resize-echo-area bible-use-tooltips))
 
 
-
 (define-key bible-map
 	    [menu-bar bible sepp]
 	    '(menu-item '"--"))
@@ -446,6 +484,7 @@ which are of the form
 	    [menu-bar bible select-biblical-text]
 	    '("Select Module" . bible-display-available-modules))
 
+
 (defun bible--display-greek ()
   "Display Greek text.
 This command is run by clicking on text, not directly by the user."
@@ -475,6 +514,7 @@ This command is run by clicking on text, not directly by the user."
 	    (lambda ()
 	      (interactive)))
 
+;; Not used. Not really sure what to do here or if it's useful to do anything.
 (defconst bible-morph-keymap (make-sparse-keymap))
 (define-key bible-morph-keymap (kbd "RET")
 	    (lambda ()
@@ -585,9 +625,9 @@ Genesis 1:1 is used."
 	 (book-data-string (car book-data))
          (chapter (string-to-number (completing-read "Chapter [1]: " (bible--list-number-range 1 (cdr book-data)) nil t nil nil "1"))))
     (pcase (aref book-data-string 0)
-      (?1 (setq book-data (cons (concat "I" (seq-subseq book-data-string 1)) (cdr book-data))))
-      (?2 (setq book-data (cons (concat "II" (seq-subseq book-data-string 1)) (cdr book-data))))
-      (?3 (setq book-data (cons (concat "III" (seq-subseq book-data-string 1)) (cdr book-data)))))
+      (?1 (setq book-data (cons (concat "I" (substring book-data-string 1)) (cdr book-data))))
+      (?2 (setq book-data (cons (concat "II" (substring book-data-string 1)) (cdr book-data))))
+      (?3 (setq book-data (cons (concat "III" (substring book-data-string 1)) (cdr book-data)))))
     (setq-local bible--current-book book-data)
     (setq-local bible--current-book-name (car book-data))
     (setq-local bible--current-chapter chapter)
@@ -614,9 +654,6 @@ Genesis 1:1 is used."
 (defun bible-select-module ()
   "Ask user for a new text module for the current `bible' buffer."
   (interactive)
-;;  (let* ((bible-module (completing-read "Module: " bible--modules)))
-;;    (bible--display))
-
   (setq-default bible-module (completing-read "Module: " bible--modules))
   (bible--display))
 
@@ -624,19 +661,13 @@ Genesis 1:1 is used."
   "Toggle the inclusion of word study for the active `bible' buffer."
   (interactive)
   (setq bible-word-study-enabled (not bible-word-study-enabled))
-;;  (if (equal major-mode 'bible-search-mode)
-;;      (bible--display-search bible-search-query bible-search-mode)
   (bible--display))
-;;)
 
 (defun bible-toggle-red-letter ()
   "Toggle red letter mode for the active `bible' buffer."
   (interactive)
   (setq bible-red-letter-enabled (not bible-red-letter-enabled))
-;;  (if (equal major-mode 'bible-search-mode)
-;;      (bible--display-search bible-search-query bible-search-mode)
     (bible--display))
-;;)
 
 (defun bible-split-display ()
   "Copy the active `bible' buffer into a new buffer in another window."
@@ -683,7 +714,7 @@ OT/NT etc. If that module doesn't have that verse...???
 Handle abbreviations from lexicon module (AbbottSmith)."
   (interactive)
   (let* ((xref (get-text-property (point) 'xref))
-	 (verse-ref (string-split xref))
+	 (verse-ref (split-string xref))
 	 book-abbrev
 	 book
 	 chapter-verse
@@ -703,6 +734,10 @@ Handle abbreviations from lexicon module (AbbottSmith)."
 	  verse   (cadr chapter-verse))
     (bible-open (string-trim book) (string-to-number chapter) (string-to-number verse))))
 
+
+;;; These can be called interactively if you know the Strong's number
+;;; you want to look up.
+
 (defun bible-term-hebrew (term)
   "Query user for a Strong's Hebrew Lexicon TERM."
   (interactive "sTerm: ")
@@ -713,22 +748,20 @@ Handle abbreviations from lexicon module (AbbottSmith)."
   (interactive "sTerm: ")
   (bible--open-term-greek term))
 
+;;; Interactively insert a verse into an arbitrary current buffer.
 (defun bible-insert ()
   "Query user to select a verse for insertion into the current buffer."
   (interactive)
   (let* ((completion-ignore-case t)
 	 (book-data (assoc (completing-read "Book: " bible--books nil t) bible--books))
          (chapter (when book-data (completing-read "Chapter: " (bible--list-number-range 1 (cdr book-data)) nil t "1" nil "1")))
-         (verse (when chapter (read-from-minibuffer "Verse: "))))
-    (when verse
-      (insert (string-trim
-	       (replace-regexp-in-string
-		(regexp-opt `(,(concat "(" bible-module ")")))
-		""
-		(bible--exec-diatheke (concat (car book-data) " " chapter ":" verse) nil "plain")))))))
+         (verse (when chapter (read-from-minibuffer "Verse: ")))
+	 (query (concat (car book-data) " " chapter ":" verse))
+	 (args (list "diatheke" nil (current-buffer) t "-b" bible-module "-f" "plain" "-k" query)))
+    (apply 'call-process args)))
 
-;;;;; Support
 
+;;;;; Support
 
 (defconst bible-diatheke-filter-options " avlnmw")
 
@@ -773,7 +806,16 @@ module."
     (buffer-string)))
 
 
-
+;;; XXX Bible chapter titles mostly appear in Psalms. This code works
+;;; OK except for Psalm 119 which uses the chapter title as a heading
+;;; for each verse of the psalm.
+;;;
+;;; 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
   "Text preceding start of chapter.
 Mostly in Psalms, like `Of David' or the like.")
@@ -784,11 +826,8 @@ Mostly in Psalms, like `Of David' or the like.")
 ;;;
 
 ;;; Hash tables for Lexical definitions.
-(defvar bible-greek-hash (make-hash-table :test 'equal :size 10000))
-(defvar bible-hebrew-hash (make-hash-table :test 'equal :size 10000))
-
-;; Do lookups using index to lexicon with lookups by lemma.
-(defvar bible-lemma-index-hash (make-hash-table :test 'equal :size 10000))
+(defvar bible-hash-greek (make-hash-table :test 'equal :size 10000))
+(defvar bible-hash-hebrew (make-hash-table :test 'equal :size 10000))
 
 ;;; Hash tables for tooltips.
 (defvar lex-hash (make-hash-table :test 'equal :size 10000))
@@ -815,19 +854,15 @@ Render HTML, return string.  Do some tweaking specific to morphology."
 (defun bible--lex-query (query module)
   "Execute `diatheke' for QUERY, using MODULE. 
 Plain format, returns string."
-  ;; Get rid of query ID at front of string: ?????:
   (bible--exec-diatheke query nil "plain" module))
 
 
 (defun bible--lookup-lemma-index (key)
   "Return the Greek lemma from lemma index with a strong's number as KEY."
-  (or (gethash key bible-lemma-index-hash)
-      (puthash key
-	       (string-trim
-		(replace-regexp-in-string
-		 (concat "(" bible-lexicon-index ")") ""
-		 (bible--lex-query key bible-lexicon-index)))
-	       bible-lemma-index-hash)))
+  (string-trim
+   (string-replace
+    (concat "(" bible-lexicon-index ")") ""
+    (bible--lex-query key bible-lexicon-index))))
 
 ;;;
 ;;; The Greek lexical definitions are done using the HTMLHREF output
@@ -872,83 +907,88 @@ them to the <bookname> <chapter>:<verse> format."
 	  (set-text-properties 0 verse-ref-length nil verse-ref-string) ; Clear unwanted properties (if any)
 	  (insert verse-ref-string))))))
 
-(defun bible--lookup-greek-def (key)
+(defun bible--lookup-def-greek (key)
   "Execute `diatheke' to do query on KEY.
-Massage output so verse cross references are usable.  Returns string.
-We use HTMLHREF format output because it may have verse references
-as HTML links, depending on the lexicon module."
-
+Massage output so verse cross references are usable.  Returns string."
   (with-temp-buffer
-    (let ((args (list "diatheke" nil (current-buffer) t "-b" bible-greek-lexicon "-o" "m" "-f" "HTMLHREF" "-k" key)))
+    (let ((args (list "diatheke" nil (current-buffer) t "-b" bible-greek-lexicon "-o" "m" "-f" "plain" "-k" key)))      
       (when bible-show-diatheke-exec
 	(message "%s" args))
       (apply 'call-process args)
-      (bible--process-href)    ; Clean up XML so xrefs can work after rendering.
-      (shr-render-region (point-min) (point-max))
-      (buffer-string))))
+      (bible--cleanup-lex-text (string-replace (concat "(" bible-greek-lexicon ")") "" (buffer-string))))))
 
-(defun bible--lookup-lex-greek-indexed (key)
+(defun bible--lookup-lemma-greek-indexed (key)
   "Lookup Greek lemma using Strong's number KEY.
 Then look up the definition of that lemma.  Used when two-stage
 lexical definition is set for a particular lexicon."
   (let ((lemma-entry (bible--lookup-lemma-index key))) ; Get lemma from Strong's number
     (when lemma-entry
       (let ((lemma (caddr (split-string lemma-entry " "))))
-	(bible--lookup-greek-def lemma)))))
+	(bible--lookup-def-greek lemma)))))
 
 
-(defun bible--lookup-lex-greek (key)
+(defun bible--lookup-lemma-greek (key)
   "Lookup lexical definition using Strong's number KEY.
 1. Check hash table first.  If entry found, return.
 2. Otherwise, if a lexicon is accessed by lemmas, do lookup using index method.
 3. Otherwise just use the Strong's number method."
-  (or (gethash key bible-greek-hash)
+  (or (gethash key bible-hash-greek)
       (puthash key
 	       (if bible-use-index-for-lexicon
-		   (bible--lookup-lex-greek-indexed key)
-		 (bible--lookup-greek-def key))
-	       bible-greek-hash)))
-
-(defun bible--lookup-strongs-greek (_window object pos)
-  "Look up Greek lexical entry of OBJECT clicked on in WINDOW at POS.
-If not found in hash table, get it from sword database.  Stash in hash
-table, and return string."
-  (let ((query (get-text-property pos 'strong object)))  ; Get Strong's number from text property
-    (when (string-match "[0-9]+" query)
-      (bible--lookup-lex-greek (match-string 0 query)))))
-
-(defun bible--lookup-strongs-hebrew (_window object pos)
-  "Look up Hebrew lexical string for OBJECT at point POS.
-If not found in hash table, get it from sword database,
-stash in hash table, and return string."
-  (let ((query (get-text-property pos 'strong object)))
-    (when (string-match "[0-9]+" query)
-      (let ((lookup-key (concat "H" (match-string 0 query))))
-	(or (gethash lookup-key bible-hebrew-hash)
-	    (let ((raw-text (bible--lex-query lookup-key bible-hebrew-lexicon)))
-	      (puthash lookup-key raw-text bible-hebrew-hash)))))))
+		   (bible--lookup-lemma-greek-indexed key)
+		 (bible--lookup-def-greek key))
+	       bible-hash-greek)))
+
+
+(defun bible--lookup-def-hebrew (key)
+  "Execute `diatheke' to do query on KEY.
+Massage output so various cross references are usable. Returns string."
+  (with-temp-buffer
+    (let ((args (list "diatheke" nil (current-buffer) t "-b" bible-hebrew-lexicon "-f" "plain" "-k" key)))
+      (when bible-show-diatheke-exec
+	(message "%s" args))
+      (apply 'call-process args)
+      (bible--process-href)
+      (string-replace (concat "(" bible-hebrew-lexicon ")") "" (substring (buffer-string) 7)))))
+
+
+(defun bible--lookup-lemma-hebrew (key)
+  "Lookup lexical definition using Strong's number KEY.
+1. Check hash table first.  If entry found, return.
+2. Otherwise, if a lexicon is accessed by lemmas, do lookup using index method.
+3. Otherwise just use the Strong's number method."
+  (or (gethash key bible-hash-hebrew)
+      (puthash key
+	       (bible--lookup-def-hebrew key)
+	       bible-hash-hebrew)))
 
 ;;;
 ;;; We use the shorter lexicons for text in tooltips. We also cache
 ;;; the lex and morph strings, hoping to speed up tooltip rendering.
 ;;;
-(defun bible--lookup-strongs-greek-short (lex)
+(defun bible--lookup-lemma-greek-short (lemma)
   "Look up Greek lexical entry for LEX from short Greek lexicon."
-  (when (string-match "[0-9]+" lex)
-    (bible--lex-query (match-string 0 lex) bible-greek-lexicon-short)))
+  (when (string-match "[0-9]+" lemma)
+    (bible--lex-query (match-string 0 lemma) bible-greek-lexicon-short)))
 
-(defun bible--lookup-strongs-hebrew-short (lex)
-  "Look up Hebrew lexical entry for LEX from short Hebrew lexicon."
-  (when (string-match "[0-9]+" lex)
-    (bible--lex-query lex bible-hebrew-lexicon-short)))
+(defun bible--lookup-lemma-hebrew-short (lemma)
+  "Look up Hebrew lexical entry for LEX from short Hebrew 
+lexicon (StrongsRealGreek)."
+  (when (string-match "[0-9]+" lemma)
+    ;; Remove redundant stuff at the beginnning.
+    (string-fill (substring (bible--lex-query (match-string 0 lemma) bible-hebrew-lexicon-short) 7) 75)))
 
 (defun bible--lookup-lex (lex)
   "Look up lexical item LEX. This is used for tooltips.
 Return hash table entry if present in lex-hash cache, else look up in
 database and stash in cache."
   (when lex
-    (let* ((key (seq-subseq lex 7)) ; strip off "strong:" prefix.
+    (let* ((key (substring lex 7)) ; strip off "strong:" prefix.
 	   (lex-text (gethash key lex-hash)))
+      ;; XXX Kludge alert! Emacs tooltips look really nice for Greek
+      ;; terms, but Hebrew needs system tooltips because of direction
+      ;; issues.
+      (setq use-system-tooltips (if (string-prefix-p "G" key) nil t))
       (if lex-text
 	  lex-text
       	(setq lex-text
@@ -956,17 +996,17 @@ database and stash in cache."
 		     (string-replace 
 		      (concat "(" bible-greek-lexicon-short ")") 
 		      ""
-		      ;; The Greek text doesn't have line breaks, so limit lines to 75 chars.
-		      (string-fill (bible--lookup-strongs-greek-short key) 75)))
+		      ;; The Greek lexicon entries don't have line breaks, so limit lines to 75 chars.
+		      (string-fill (bible--lookup-lemma-greek-short key) 75)))
 		    ((string-prefix-p "H" key)
 		     (string-replace
 		      (concat "(" bible-hebrew-lexicon-short ")")
 		      ""
-		      (bible--lookup-strongs-hebrew-short key)))))
-	(puthash key (bible--cleanup-tooltip-text lex-text) lex-hash)))))
+		      (string-fill (bible--lookup-lemma-hebrew-short key) 75)))))
+	(puthash key (bible--cleanup-lex-text lex-text) lex-hash)))))
 
-(defun bible--lookup-morph (morph)
-  "Look up morphological item MORPH. 
+(defun bible--lookup-morph-entry (morph)
+  "Look up entry for morphological item MORPH. 
 Return hash table entry if present in morph-hash cache, else look up in
 database and stash in cache."
   (when morph
@@ -975,13 +1015,13 @@ database and stash in cache."
 		 (let (morph-module morph-key)
 		   (cond ((string-prefix-p "robinson:" morph)
 			  (setq morph-module "Robinson")
-			  (setq morph-key (seq-subseq morph (length "robinson:"))))
+			  (setq morph-key (substring morph (length "robinson:"))))
 			 ((string-prefix-p "packard:" morph)
 			  (setq morph-module "Packard")
-			  (setq morph-key (seq-subseq morph (length "packard:"))))
+			  (setq morph-key (substring morph (length "packard:"))))
 			 ((string-prefix-p "oshm:" morph)
 			  (setq morph-module "OSHM")
-			  (setq morph-key (seq-subseq morph (length "oshm:")))))
+			  (setq morph-key (substring morph (length "oshm:")))))
 		   (string-replace (concat "(" morph-module ")")
 				   ""
 				   (bible--morph-query morph-key morph-module)))
@@ -1021,7 +1061,7 @@ database and stash in cache."
     (" III. ."	.	" III.")
     (" IV. ."	.	" IV.")
     (" V. ."	.	" V.")
-    ("1. ."	.	"\n1.")
+    ("1. ."	.	"\n 1.")
     ("2. ."	.	"2.")
     ("3. ."	.	"3.")
     ("4. ."	.	"4.")
@@ -1030,7 +1070,8 @@ database and stash in cache."
     ("7. ."	.	"7.")
     ("8. ."	.	"8.")
     ("9. ."	.	"9.")
-    ("a. ."	.	"    a.")
+    ("a. ."	.	"\n    a.")
+    ("(a)."	.	"\n    (a).")
     ("b. ."	.	"    b.")
     ("c. ."	.	"    c.")
     ("d. ."	.	"    d.")
@@ -1038,16 +1079,16 @@ database and stash in cache."
     ("f. ."	.	"    f.")
     ("g. ."	.	"    g.")
     ("h. ."	.	"    h.")
-    (" . "	.	". ")))
+    (" . "	.	". ")
+    ("\n\n"	.	"\n")))
 
-(defun bible--cleanup-tooltip-text (lex-text)
+(defun bible--cleanup-lex-text (lex-text)
   "Reformat tooltip text LEX-TEXT so tooltips look nice."
   (dolist (outline-string bible-outline-strings)
     (setq lex-text (string-replace (car outline-string) (cdr outline-string) lex-text)))
     lex-text)
 
 
-
 ;;;
 ;;; Get string for tooltip display
 ;;;
@@ -1055,22 +1096,22 @@ database and stash in cache."
   "Get text for tooltip display for OBJECT at POS in WINDOW.
 Includes both lex and morph definitions if text module has
 both tags, otherwise just get lex definition."
-  (let* ((lex-morph-text "")
-	 (lex (get-text-property pos 'strong object))
+  (let* ((lex (get-text-property pos 'strong object))
 	 (lex-text (bible--lookup-lex lex))
 	 (morph (get-text-property pos 'morph object))
-	 (morph-text (bible--lookup-morph morph)))
+	 (morph-text (bible--lookup-morph-entry morph)))
     (when lex-text
-      ;;      (setq lex-morph-text (string-trim (string-fill lex-text 75))))
-      (setq lex-morph-text (string-trim lex-text)))
-    (when morph-text
-      (setq lex-morph-text
-	    (concat lex-morph-text "\n" (string-trim morph-text))))
-    ;; This prevents bogus command substitutions in the tooltip by
-    ;; removing backslashes. XXX I couldn't figure out a better way
-    ;; to bypass command substitution in the tooltips.
-    (setq lex-morph-text (subst-char-in-string ?\\ ?  lex-morph-text))
-    lex-morph-text))
+      ;; This prevents bogus command substitutions in the tooltip by
+      ;; removing backslashes. XXX I couldn't figure out a better way
+      ;; to bypass command substitution in the tooltips.
+      (subst-char-in-string 
+       ?\\ 
+       ?
+       (if morph-text
+	   (concat (string-trim lex-text) "\n" (string-trim morph-text))
+	 (string-trim lex-text))))))
+
+
 
 
 (defun bible-handle-divine-name (item)
@@ -1088,18 +1129,19 @@ both tags, otherwise just get lex definition."
 
 (defun bible--process-word (item iproperties)
   "Handle <w ...> fubar </w> tag in ITEM. Check IPROPERTIES for qualifiers.
-Add tooltips for definitions and morphology.  Also insert lemmas in buffer
-(must be done after item is inserted in buffer)."
+Add tooltips for definitions and morphology. Also insert lemmas in
+buffer if `word study' is turned on (must be done after item is inserted
+in buffer)."
   (let ((word (string-trim (dom-text item)))
 	(morph (dom-attr item 'morph))
 	(savlm (dom-attr item 'savlm))
 	(lemma (dom-attr item 'lemma))
 	(divinename (dom-by-tag item 'divinename)))
 
-    (insert word)
+    (let ((refstart (point))
+	  (refend (+ (point) (length word))))
 
-    (let ((refstart (- (point) (length word)))
-	  (refend  (point)))
+      (insert word)
 
       ;; Red letter (Yuck, some modules need this below)
       (when (plist-get iproperties 'jesus)
@@ -1111,14 +1153,16 @@ Add tooltips for definitions and morphology.  Also insert lemmas in buffer
 	(bible-handle-divine-name item))
 
       ;; lexical definitions
-      (when (or savlm lemma)
-	(let ((matched nil)
-	      (item (or savlm lemma)))
-	  (cond ((string-match "strong:G.*" item)        ; Greek
-		 (setq matched (match-string 0 item))
+      (when (or lemma savlm)
+	(let* ((matched nil)
+	       (lexemes (split-string (or lemma savlm)))
+	       ;; XXX KJV module conflates articles with lemmas. Deal with this.
+	       (lexeme (if (> (length lexemes) 2) (nth 1 lexemes) (nth 0 lexemes))))
+	  (cond ((string-match "strong:G.*" lexeme) ; Greek
+		 (setq matched (match-string 0 lexeme))
 		 (put-text-property refstart refend 'keymap bible-greek-keymap))
-		((string-match "strong:H.*" item)        ; Hebrew
-		 (setq matched (match-string 0 item))
+		((string-match "strong:H.*" lexeme) ; Hebrew
+		 (setq matched (match-string 0 lexeme))
 		 (put-text-property refstart refend 'keymap bible-hebrew-keymap)))
 	  ;; Add help-echo, strongs reference for tooltips if match.
 	  (when matched
@@ -1129,25 +1173,23 @@ Add tooltips for definitions and morphology.  Also insert lemmas in buffer
       ;; morphology
       (when morph
 	(let ((matched nil))
-	  (cond ((string-match "robinson:.*" morph)    ; Robinson Greek morphology
-		 (setq matched (match-string 0 morph)))
-		((string-match "packard:.*" morph)     ; Packard Greek morphology --- LXX seems to use this
-		 (setq matched (match-string 0 morph)))
-		((string-match "oshm:.*" morph)        ; OSHM Hebrew morphology
-		 (setq matched (match-string 0 morph)))
-		(t nil
-		   ;;(message "Unknown morphology %s" morph)
-		   ))
+	  (if (or
+	       (string-match "robinson:.*" morph)	; Robinson Greek morphology
+	       (string-match "packard:.*" morph)	; Packard Greek morphology --- LXX seems to use this
+	       (string-match "oshm:.*" morph))		; OSHM Hebrew morphology
+	      (setq matched (match-string 0 morph))
+	    ;;(message "Unknown morphology %s" morph)
+	    )
 	  (when matched
 	    (setq bible-has-morphology t)
 	    (put-text-property refstart refend 'morph matched)
 	    (put-text-property refstart refend 'help-echo 'bible--show-lex-morph))))
 
-      ;; Insert lemma into buffer. Lemma tag will be part of savlm item.
-      ;; XXX Should I do lexicon lookups on these lemmas? I don't use
+      ;; Insert lemma into buffer. Lemma tag will be part of lemma/savelm item.
+      ;; XXX Should I enable lexicon lookups on these lemmas? I don't use
       ;; this anyway....
-      (when (and bible-word-study-enabled savlm (string-match "lemma.*:.*" savlm))
-	(dolist (word (split-string (match-string 0 savlm) " "))
+      (when (and bible-word-study-enabled lemma (string-match "lemma.*:.*" lemma))
+	(dolist (word (split-string (match-string 0 lemma) " "))
 	  (setq word (replace-regexp-in-string "[.:a-zA-Z0-9]+" "" word))
 	  (insert " " word)
 	  (let ((refstart (- (point) 1 (length word)))
@@ -1189,9 +1231,15 @@ XXX In processing subnodes, each case will prepend a space if it needs it."
 	  ((consp subnode)
 	   (let ((tag (dom-tag subnode)))
 	     (pcase tag
-		 ;; Maybe process these at some point? Include footnotes etc.
-		 ;; ('node nil)
-		 ;; ('lb nil)
+	       ;; Maybe process these at some point? Include footnotes etc.
+	       ;; ('node nil)
+	       ;; ('lb nil)
+	       ;; 'w --- Usual case.
+	       ('w (insert " ") (bible--process-word subnode iproperties))
+	       ;; 'q is used for red letter.
+	       ;; NASB Module uses 'seg to indicate OT quotations (and others?).
+	       ((or 'body 'seg 'p 'q) (bible--insert-domnode-recursive subnode iproperties notitle))
+	       ('title (when (not notitle) (setq bible-chapter-title subnode) (bible-new-line)))
 	       ;; These tags appear in ESV modules (and maybe others?) XXX still not right
 	       ('l
 		(let ((attributes (dom-attributes subnode)))
@@ -1202,14 +1250,7 @@ XXX In processing subnodes, each case will prepend a space if it needs it."
 			((assoc 'level attributes)
 			 (let ((indent (string-to-number (alist-get 'level attributes))))
 			   (when (= indent 2) (insert "\n\t")))))))
-	       ('title (when (not notitle) (setq bible-chapter-title subnode) (bible-new-line)))
-	       ('body (bible--insert-domnode-recursive subnode iproperties notitle))
-	       ;; NASB Module uses this to indicate OT quotations (and others?).
-	       ('seg (bible--insert-domnode-recursive subnode iproperties notitle))
 	       ('divinename (bible-handle-divine-name subnode))
-	       ;; This tag is used for red letter.
-	       ((or 'p 'q) (bible--insert-domnode-recursive subnode iproperties notitle))
-	       ('w (insert " ") (bible--process-word subnode iproperties))
 	       ;; Some modules use this for line breaks and such.
 	       ('milestone (when (equal (dom-attr subnode 'type) "line") (bible-new-line)))
 	       ('div (when (equal (dom-attr subnode 'type) "paragraph") (bible-new-line)))
@@ -1266,8 +1307,7 @@ XXX In processing subnodes, each case will prepend a space if it needs it."
 	      (refstart (point-min))
 	      refend)
 	  ;; Insert and make bold the title.
-;;;;      (when (string-or-null-p title-text)    ;;; XXXX Maybe wrong
-	  (when (stringp title-text) ;;; XXXX Maybe wrong	
+	  (when (stringp title-text)
 	    (insert title-text "\n")
 	    (setq refend (point))
 	    (put-text-property refstart refend 'face 'bold))))
@@ -1297,7 +1337,7 @@ XXX In processing subnodes, each case will prepend a space if it needs it."
 
   ;; If optional verse specification go to that verse.
   (when verse
-    (re-search-forward (regexp-opt `(,(concat (number-to-string verse) ":"))))))
+    (re-search-forward (regexp-opt `(,(concat (number-to-string verse) ":"))) nil t)))
 
 
 (defun bible--list-biblical-modules ()
@@ -1381,13 +1421,15 @@ XXX In processing subnodes, each case will prepend a space if it needs it."
       (when match
 	(push
 	 ;; Massage match to make it more sortable, get rid of some characters.
-	 (replace-regexp-in-string
+	 (string-replace 
 	  "I " "1"
-	  (replace-regexp-in-string
+	  (string-replace
 	   "II " "2"
-	   (replace-regexp-in-string
+	   (string-replace
 	    "III " "3"
-	    (replace-regexp-in-string ".+; " "" matchstr))))
+	    (string-replace
+	     ".+; " "" 
+	     matchstr))))
 	 verses)))
 
     (setq match 0)
@@ -1412,17 +1454,16 @@ XXX In processing subnodes, each case will prepend a space if it needs it."
       (setq mode-name (concat mode-name ")"))
       (goto-char (point-min)))))
 
-;;;;; Terms
+;;;;; Terms (lemmas, morphology)
 
 
 ;;(defun bible-display-morphology (morph)
 ;; ;; xxx Do something here?
 ;;  )
 
-(defun bible--display-term (termtype)
-  "Display a term of language given by TERMTYPE."
+(defun bible--fixup-lexicon-display (termtype)
+  "Fixup the display of a lexical entry whose language is given by TERMTYPE."
   (let ((buffer-read-only nil))
-
     (goto-char (point-min))
     ;; This enables clicking on Strong's numbers in some lexicon definitions.
     (while (search-forward-regexp "[0-9]+" nil t)
@@ -1454,45 +1495,38 @@ XXX In processing subnodes, each case will prepend a space if it needs it."
   "Open a buffer of the Strong's Hebrew TERM's definition."
   (with-current-buffer (get-buffer-create (concat "*bible-term-hebrew-" term "*"))
     (bible-term-hebrew-mode)
-    (bible--display-term-hebrew term)
-    (pop-to-buffer (current-buffer) nil t)
-    (fit-window-to-buffer)))
-
-(defun bible--open-term-greek (term)
-  "Open a buffer of the Strong's Greek TERM definition."
-  (with-current-buffer (get-buffer-create (concat "*bible-term-greek-" term "*"))
-    (bible-term-greek-mode)
-    (bible--display-term-greek term)
+    (bible--display-lemma-hebrew term)
     (pop-to-buffer (current-buffer) nil t)
     (fit-window-to-buffer)))
 
-;;;
 ;;; Note: Hebrew display of terms is backwards; set bidi direction to
 ;;; 'left-to-right.
-(defun bible--display-term-hebrew (term)
-  "Render the definition of the Strong's Hebrew TERM.
+(defun bible--display-lemma-hebrew (lemma)
+  "Render the definition of the Strong's Hebrew LEMMA.
 Sets the variable `bidi-paragraph-direction' so the English text will
-render left-to-right. XXX Why doesn't this work for the tooltips?"
+render left-to-right. This code is customized for the BDBGlosses_Strongs
+lexicon."
   (let ((buffer-read-only nil))
     (erase-buffer)
-    (insert (replace-regexp-in-string
-	     (regexp-opt `(,bible-hebrew-lexicon))
-	     ""
-	     (bible--exec-diatheke term nil "plain" bible-hebrew-lexicon)
-	     nil nil nil 7))
-    (bible--display-term 'hebrew)
-    (setq bidi-paragraph-direction 'left-to-right)))
+    ;; BDBGlosses_Strongs needs the prefixed `H'.
+    (insert (substring (bible--cleanup-lex-text (bible--lookup-lemma-hebrew (concat "H" lemma))) 7))
+    (bible--fixup-lexicon-display 'hebrew)))
+
 
+(defun bible--open-term-greek (term)
+  "Open a buffer of the Strong's Greek TERM definition."
+  (with-current-buffer (get-buffer-create (concat "*bible-term-greek-" term "*"))
+    (bible-term-greek-mode)
+    (bible--display-lemma-greek term)
+    (pop-to-buffer (current-buffer) nil t)
+    (fit-window-to-buffer)))
 
-(defun bible--display-term-greek (term)
-  "Render the definition of the Strong's Greek TERM."
+(defun bible--display-lemma-greek (lemma)
+  "Render the definition of the Strong's Greek LEMMA."
   (let ((buffer-read-only nil))
     (erase-buffer)
-    (insert (replace-regexp-in-string
-	     (regexp-opt `(,bible-greek-lexicon))
-	     ""
-	     (bible--lookup-lex-greek term)))
-    (bible--display-term 'greek)))
+    (insert (bible--lookup-lemma-greek lemma))
+    (bible--fixup-lexicon-display 'greek)))
 
 
 (defun bible--set-location (book chapter &optional verse)