emacs-sword

Table of Contents

1. Package Header

this is the package header

==:

;;; emacs-sword.el --- The Sword of the Lord with a decided Lisp
;; Copyright (C) 2022-2026  William Malander

;; Author: William Malander <william@malanderengineering.com>
;; Keywords: lisp
;; Version: 3.0.0

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:

;; The Sword of the Lord with a decided Lisp.
;;
;; This is a package written to replace e-sword for linux and emacs users.
;; Changelog:
;;
;; 3.0.0:
;; BREAKING CHANGE:
;; Properly namespace all variables and functions (except foreign imports)
;;     This is (i think) the first actual breaking change we have had.
;;     I have bumped major version because of that.
;;     Make sure to properly migrate.  Migration guide available upon request.
;;     (Todo: Link migration guide)
;; User facing variables that changed:
;;     Dictionary-Directory -> emacs-sword-dictionary-directory
;;     Bible-Directory      -> emacs-sword-bible-directory
;;     Greek                -> emacs-sword-greek-dictionary
;;     Hebrew               -> emacs-sword-hebrew-dictionary
;;     Bibles               -> emacs-sword-bible-list
;;     emacs-sheath         -> emacs-sword-sheath
;;     player               -> emacs-sword-player
;;     Audio-Directory      -> emacs-sword-audio-directory
;;     Resource-Directory   -> emacs-sword-resource-directory
;;     Resources            -> emacs-sword-resource-list
;;     Resource-Repository  -> emacs-sword-resource-repository
;;     Abbreviations        -> emacs-sword-abbreviations
;; Other Changes:
;; Add explicit mention of 'emacs-sword-abbreviations to the message in (emacs-sword--check-book).
;;     This was done to bring attention to the abbreviations variable, so someone who thinks to check the message buffer but not the variables can find it.
;; emacs-sword-word-search and emacs-sword-goto-def now open in view-mode
;; emacs-sword-visit-bibles and emacs-sword-visit-dictionaries also open in view-mode
;;     There is also a new emacs-sword-lagacy-visit-mode to put the old functions on the default keys
;; Fixed unintentional (and undeclared) dependency on s.el
;; Mark emacs-sword-visit-abbrev as obsolete.  Please use `describe-variable' for emacs-sword-abbreviations instead
;; 2.3.1:
;; The prefix key var should automatically reset prefix when updated with customize.
;; Word search wont accidentally get the header anymore
;; Word search speed is optimised by assuming long words are less used and sorting accordingly
;; Word search modes "words" and "loose" now allow regexp in all words
;; The main functionallity of word search has been extracted into another function (called emacs-sword--word-search-backend)
;; Word search immediatly now runs on the same backend as word search.
;; Book abbreviations now work when capitalised normally
;; All mentions of "capitalise" are now "capitalize"
;; Using > in find verse now works again.
;; 2.3.0:
;; Book abbreviations capitalisation is more robust now
;; Word search now has three modes, strict, words, and loose
;; See emacs-sword-search-mode for details
;; 2.2.0:
;; Bible abbreviations no longer are required to be capitalised
;; Bible names are now "fuzzy matched".  The real name with the lowest levenshtein distance (with transposations) is assumed to be the one you wanted
;; 2.1.1:
;; Fixed a bug where goto-def would not respect dictionary directory
;; 2.1.0:
;; Added prefixkey variable.  Useful on mobile devices that cant use Shift.
;; 2.0.3:
;; forces treemacs to load in time for parsing if it is installed
;; 2.0.2:
;; preventing emacs-sword from cluttering treemacs too much
;; 2.0.1:
;; minor bug fixes concerning treemacs
;; 2.0:
;; Added official support for Treemacs.
;; The following will only happen if you have treemacs installed:
;; Will automatically create a treemacs workspace if there isnt one already.
;; C-S-b t will open the Emacs-sword workspace.
;; 1.9.3:
;; Changed resource downloader to handle .zip files
;; 1.9.2:
;; Fixed an issue when finding a single verse that is in parenthesis printing the verse number instead of the verse
;; eww-download should be back after you quit the resource downloader
;; 1.9.1:
;; fixed missing function call
;; 1.9:
;; Added Bible book abbreviations.  They are usable in place of the whole book name everywhere.
;; C-S-b v a now opens a buffer with all the abbreviations.
;; Abbreviations are fully customisable, you can replace, remove, or add new abbreviations.
;; 1.8.2:
;; Changed keybindings in emacs-sword-resource-downloader to be easier.
;; 1.8.1:
;; Added a comment to start of word search immediatley and standard.
;; 1.8:
;; Added immediate prefix and search
;; 1.7.4:
;; Changed the key bindings to be more intuative.
;; Names prefix keys.
;; 1.7.3:
;; Added functions to visit Bible and dictionary directories.
;; Changed key-bindings to use C-S-b v for visit prefix
;; 1.7.2:
;; Allowed audio function to stack file to end of book with ->
;; 1.7.1:
;; Fixed downloads not ending where they should.
;; 1.7:
;; Added Resource Downloader and other functions related.
;; Added Resource Repository variable.
;; 1.6:
;; Added resources and directory.
;; You can link to any header in a resource.
;; You can convert a two column table into a list with listify.
;; 1.5.4:
;; Changed Find Verse from using src block to using verse block, so links work and it makes sense.
;; 1.5.3:
;; If Word Search does not find any verses it will now tell you so.
;; Goto Defenition now works like every other function.
;; 1.5.2:
;; Changed the Word Search backend to support regexp.

;;; Code:
(require 'org)

2. Variables

Here are all the variables. They are all customizable, so no need to mess about with them here

==:

(defgroup emacs-sword nil
  "Customize Emacs Sword"
  :group 'emacs)

(defcustom emacs-sword-dictionary-directory ""
  "Directory (Relative to Sheath) where the dictionaries are stored."
  :type 'string
  :group 'emacs-sword)

(defcustom emacs-sword-bible-directory ""
  "Directory (Relative to Sheath) where the Bibles are stored."
  :type 'string
  :group 'emacs-sword)

(defcustom emacs-sword-greek-dictionary "strongsgreek.org"
  "Greek dictionary"
  :type 'string
  :group 'emacs-sword
    :set (lambda (symbol value)
         (set-default-toplevel-value symbol value)
         (if (boundp 'emacs-sword-hebrew-dictionary)  (setq emacs-sword-dictionary-list `(,emacs-sword-hebrew-dictionary ,emacs-sword-greek-dictionary)))))

(defcustom emacs-sword-hebrew-dictionary "strongshebrew.org"
  "Hebrew dictionary"
  :type 'string
  :group 'emacs-sword
  :set (lambda (symbol value)
         (set-default-toplevel-value symbol value)
         (if (boundp 'eamcs-sword-greek-dictionary) (setq emacs-sword-dictionary-list `(,emacs-sword-hebrew-dictionary ,emacs-sword-greek-dictionary)))))

(defvar emacs-sword-dictionary-list `(,emacs-sword-hebrew-dictionary ,emacs-sword-greek-dictionary))

(defcustom emacs-sword-bible-list '("KJV_10SLPV.org")
  "List of Bibles"
  :type '(repeat string)
  :group 'emacs-sword)

(defcustom emacs-sword-sheath "~/emacs-sword/"
  "Emacs Sword home directory"
  :type 'string
  :group 'emacs-sword)

(setq org-babel-exp-code-template
      (concat "\n==:\n"
              org-babel-exp-code-template))

(defcustom emacs-sword-player "vlc"
  "The command for playing audio."
  :type 'string
  :group 'emacs-sword)

(defcustom emacs-sword-audio-directory "audio/"
  "Directory where audio files are stored relative to Emacs Sheath"
  :type 'string
  :group 'emacs-sword)

(defcustom emacs-sword-resource-directory ""
  "Directory (Relative to Emacs Sheath) where the resources are stored"
  :type 'string
  :group 'emacs-sword)

(defcustom emacs-sword-resource-list '("")
  "List of resources
NOTE:  NO SPACES ARE SUPPORTED!!!"
  :type '(repeat string)
  :group 'emacs-sword)

(defcustom emacs-sword-resource-repository "malanderengineering.com/packages/repo/"
  "URL where the downloadable resources are stored"
  :type 'string
  :group 'emacs-sword)

(defcustom emacs-sword-abbreviations '( 
               ("Gen" . "Genesis")
               ("Exo" . "Exodus")
               ("Lev" . "Leviticus")
               ("Num" . "Numbers")
               ("Deu" . "Deuteronomy")
               ("Jos" . "Joshua")
               ("Jdg" . "Judges")
               ("Rth" . "Ruth")
               ("1Sa" . "Samuel 1")
               ("2Sa" . "Samuel 2")
               ("1Ki" . "Kings 1")
               ("2Ki" . "Kings 2")
               ("1Ch" . "Chronicles 1")
               ("2Ch" . "Chronicles 2")
               ("Ezr" . "Ezra")
               ("Neh" . "Nehemiah")
               ("Est" . "Ester")
               ("Job" . "Job")
               ("Psa" . "Psalms")
               ("Pro" . "Proverbs")
               ("Ecc" . "Ecclesiastes")
               ("Son" . "Song of Solomon")
               ("Isa" . "Isaiah")
               ("Jer" . "Jeremiah")
               ("Lam" . "Lamentations")
               ("Eze" . "Ezekiel")
               ("Dan" . "Daniel")
               ("Hos" . "Hosea")
               ("Joe" . "Joel")
               ("Amo" . "Amos")
               ("Oba" . "Obadiah")
               ("Jon" . "Jonah")
               ("Mic" . "Micah")
               ("Nah" . "Nahum")
               ("Hab" . "Habakkuk")
               ("Zep" . "Zephaniah")
               ("Hag" . "Haggai")
               ("Zec" . "Zechariah")
               ("Mal" . "Malachi")
               ("Mat" . "Matthew")
               ("Mar" . "Mark")
               ("Luk" . "Luke")
               ("Joh" . "John")
               ("Act" . "Acts")
               ("Rom" . "Romans")
               ("1Co" . "Corinthians 1")
               ("2Co" . "Corinthians 2")
               ("Gal" . "Galatians")
               ("Eph" . "Ephesians")
               ("Php" . "Philippians")
               ("Col" . "Colossians")
               ("1Th" . "Thessalonians 1")
               ("2Th" . "Thessalonians 2")
               ("1Ti" . "Timothy 1")
               ("2Ti" . "Timothy 2")
               ("Tit" . "Titus")
               ("Phm" . "Philemon")
               ("Heb" . "Hebrews")
               ("Jas" . "James")
               ("1Pe" . "Peter 1")
               ("2Pe" . "Peter 2")
               ("1Jn" . "John 1")
               ("2Jn" . "John 2")
               ("3Jn" . "John 3")
               ("Jud" . "Jude")
               ("Rev" . "Revelation")
               )
  "Alist of book abbreviations"
  :type '(alist :key-type (symbol :tag "Key")
        :value-type (string :tag "Value"))
  :group 'emacs-sword)
;; (defcustom emacs-sword-prefix-key-var "C-S-b"
;;   "Prefix key of Emacs Sword.  Set to nothing to not set it automatically."
;;   :type 'string
;;   :group 'emacs-sword
;;   ;:set (lambda (sym defs) (emacs-sword--set-prefix-key defs))
;;   )


(defcustom emacs-sword-search-mode "strict"
  "Search mode of Emacs Sword.

Strict is the default to maintain identical functionality to old versions.

Strict searches for the exact string given by the user. it does allow for custom regex.
Words searches for the words (space seperated) given by the user in any order.  Technically, also a priority search, as the longest word is checked then the others
Loose searches for the substrings (space seperated) given by the user in any order.

The primary difference between 'words' and 'loose' is that 'words' assumes what you gave it are whole words, while 'loose' does not.  For example, with the search 'man', 'words' will not match 'woman', but loose will."
  :group 'emacs-sword
  :type '(choice
          (const :tag "Strict" "strict")
          (const :tag "Words" "words")
          (const :tag "Loose" "loose")))

(defcustom emacs-sword-enable-treemacs nil
  "Whether or not to enable `treemacs' integration.

If `t', try to set up an emacs sword workspace in treemacs (if one does not already exist) and enable treemacs functions"
  :group 'emacs-sword
  :type '(boolean))

3. Functions

3.1. Bible Related Functions

3.1.1. Find Verse

This function finds the verse reference in the previous list (eg. (John 3:16)), and pastes it in a source block. the syntax is (BOOKssCHAPTER:VERSE) where BOOK the the book, s is space, CHAPTER is chapter, and VERSE is verse. The command to run this function is C-S-b f (or Ctrl-Shift-b f) or you could call it with M-x emacs-sword-find-verse (where M is Alt).

==:

(defun emacs-sword-find-verse ()
  "This function finds the verse reference in the previous list (eg. (John  3:16)), and pastes it in a source block.  the syntax is (BOOKssCHAPTER:VERSE) where BOOK the the book, s is space, CHAPTER is chapter, and VERSE is verse.
The command to run this function is C-S-b f (or Ctrl-Shift-b f) or you could call it with M-x emacs-sword-find-verse (where M is Alt)."
  (interactive)

  (let ((output "")
    (verse (save-excursion
         (search-backward ")")
         (let ((line (thing-at-point 'line t)))
           (with-temp-buffer
             (insert line)
             (search-backward ")")(or (thing-at-point 'list t) (concat (thing-at-point 'sexp t) ")"))
             )
           )
         )
           )
    (book "")
    (chapter "")
    (verse-num "")
    (line-bounds nil)
    (multiple nil)
    (Bible (emacs-sword--query-user 'bible)))
    (message "Let #1")
    (with-current-buffer (or (get-file-buffer Bible)
                             (find-file-noselect Bible))
      (message "Change Buffer to %s" Bible)
      (save-excursion
    (message "move point")
    (goto-char (point-min))
    (get-buffer-create "kjv-search")
    (with-current-buffer "kjv-search"
          (message "Change Buffer to kjv-search")
          (goto-char (point-min))
          (insert verse)
          (goto-char (point-min))
      (message "Reference inserted in temp buffer")
          (let ((search-result (search-forward "-" nil t)))
            (if search-result
        (progn
          (save-excursion
            (message "go to end?")
            (let ((rest (search-forward ">" nil t)))
              (if rest
              (setq multiple ">")
            (progn
              (message "%s" (number-at-point))
              (setq multiple (number-at-point))
              (message "%d" multiple)
              (message "%d" multiple))))))))
          (goto-char (point-min))
          (setq book (progn (re-search-forward "[1-3]?[A-z]+\\s-?[0-9]?") (match-string 0))
        chapter (progn (goto-char (point-min)) (re-search-forward "[0-9]+:" nil t) (substring (match-string 0) 0 -1))
        verse-num (progn (goto-char (point-min)) (re-search-forward ":[0-9]*" nil t) (substring (match-string 0) 1)))
      (setq book (emacs-sword--check-book (string-trim-right book)))
      (message "set all search params")
      (message "multiple == %s" multiple)
          (kill-current-buffer))
    (search-forward (string-trim-right (concat "** " book)) nil t)
    (message "book: %s" book)
    (search-forward (concat "Chapter " chapter) nil t)
    (message "chapter: %s" chapter)
    (search-forward (concat "(" verse-num ")") nil t)
    (message "verse: %s" verse-num)
    (message "%s" (point))
    (message "%s" (current-buffer))
    (setq output "\n")
    (if multiple
        (progn
          (if (equal multiple ">")
          (save-excursion
            (message "Checking Chapter Length")
            (or (search-forward "*** Chapter" nil t) (goto-char (point-max)))
            (re-search-backward "[0-9]\)" nil t)
            (goto-char (+ 1 (point)))
            (message "%s" (number-at-point))
            (setq multiple (- (number-at-point) (number-at-point) (number-at-point)))
            (message "multiple == %d" multiple)))
          
          (progn
        (dotimes (count (+ (- (string-to-number (concat "-" verse-num)) multiple) 0))
          (setq output (concat output (thing-at-point 'line t))) (forward-line 1) (message output) (message "%d" count)))
              (setq output (concat output (thing-at-point 'line t))))
      (setq output (concat output (thing-at-point 'line t))))))
    
    
    (save-excursion
      (progn(search-backward ")")
            (beginning-of-line)
            (thing-at-point 'list)
            (search-forward ")")
            (kill-line 0)
            (insert (concat "#+NAME: " (string-trim-right book) " " chapter ":" verse-num (if multiple (format "%s" multiple)) "\n#+begin_verse "))
            (insert output)
        (insert "#+end_verse")
            (unless multiple
              (progn (re-search-backward "([0-9]") (setq line-bounds (point)) (search-forward ")"))
              (delete-region line-bounds (point)))
            (message "pasted %s" verse))))
      )
  
  

3.1.2. Link Verse

This function finds a verse in the previous array (eg. [John 3:16]) and make a link to it in your Bible of choice. the syntax is [BOOKssCHAPTER:VERSE] where BOOK the the book, s is space, CHAPTER is chapter, and VERSE is verse. The command to run this function is C-S-b l b (or Ctrl-Shift-b l b) or you could call it with M-x emacs-sword-link-verse (where M is Alt).

==:

  (defun emacs-sword-link-verse ()
    "This function finds a verse in the previous array (eg. [John  3:16]) and make a link to it in your Bible of choice. the syntax is [BOOKssCHAPTER:VERSE] where BOOK the the book, s is space, CHAPTER is chapter, and VERSE is verse.
The command to run this function is C-S-b l b (or Ctrl-Shift-b l b) or you could call it with M-x emacs-sword-link-verse (where M is Alt)."
    (interactive)
    (let ((output "")
          (verse (save-excursion
                   (search-backward "]")(search-forward "]")(thing-at-point 'sexp t)))
          (book "")
          (chapter "")
          (verse-num "")
          (Bible (emacs-sword--query-user 'bible)))
      (message "Let #1")
      (with-current-buffer (or (get-file-buffer Bible)
                               (find-file-noselect Bible))
        (message "Change Buffer to %s" Bible)
        (save-excursion
          (message "move point")
          (goto-char (point-min))
          (get-buffer-create "kjv-search")
          (with-current-buffer "kjv-search"
            (message "Change Buffer to kjv-search")
            (goto-char (point-min))
            (insert verse)
            (goto-char (point-min))
            (setq book (progn (re-search-forward "[A-z]+\\s-?[0-9]?") (substring (match-string 0) 1))
                  chapter (progn (goto-char (point-min)) (re-search-forward "[0-9]+:") (substring (match-string 0) 0 -1)) 
                  verse-num (progn (goto-char (point-min)) (re-search-forward ":[0-9]*") (substring (match-string 0) 1)))
        (setq book (emacs-sword--check-book (string-trim-right book)))
            (message "set all search params")
            (kill-current-buffer))
          (search-forward (string-trim-right (concat "** " book)))
          (message "book: %s" book)
          (search-forward (concat "Chapter " chapter))
          (message "chapter: %s" chapter)
          (search-forward (concat "(" verse-num ")"))
          (message "verse: %s" verse-num)
          (message "%s" (point))
          (message "%s" (current-buffer))
          (setq output (concat "[[file:" Bible "::" (number-to-string (line-number-at-pos)) "]" verse "]" ))
          ))
      (save-excursion
        (let ((bound1 nil)
              (bound2 nil))
          (search-backward "[")
          (setq bound1 (point))
          (thing-at-point 'sexp)
          (search-forward "]")
          (setq bound2 (point))
          (delete-region bound1 bound2)
          (insert output)))))
  

3.1.3. Word Search

This function searches the Bible of choice for WORD, where word is your word of choice, and prints all verses where WORD is found in a buffer. The command to run this function is C-S-b s (or Ctrl-Shift-b s) or you could call it with M-x emacs-sword-word-search (where M is Alt).

==:

  (defun emacs-sword-word-search (word)
    "This function searches the Bible of choice for WORD, where word is your word of choice, and prints all verses where WORD is found in a buffer.
The command to run this function is C-S-b s (or Ctrl-Shift-b s) or you could call it with M-x emacs-sword-word-search (where M is Alt)."
    (interactive "sWhich word to search? ")
    (let ((verse "")
          (chapter "")
          (book "")
          (pointer 1)
      (word-list (emacs-sword--search-criteria-breakdown word))
          (Bible (emacs-sword--query-user 'bible)))
      (emacs-sword--word-search-backend verse chapter book pointer word-list Bible) ; run the backend
      (view-buffer-other-window (get-buffer "Word Search")) ; bring the word search buffer to the fore
      ;; We dont need to do anything else, as the backed automatically puts everything in a temp buffer
      ))

3.1.4. Word Search Immediately

This function searches the Bible for your word of choice, and prints all verses where the word is found in a drawer. The command to run this function is C-S-b i s (or Ctrl-Shift-b i s) or you could call it with M-x emacs-sword-word-search-immediately (where M is Alt).

==:

(defun emacs-sword-word-search-immediately (word)
  "Similar to emacs-sword-word-search, except it puts the result in a drawer in a list format (as opposed to header)

Almost fully anotated, if you want to see an example of what to do with emacs-sword--word-search-backend programmatically"
  (interactive "sWhich word to search? ")
  (let ((verse "")
        (chapter "")
        (last-chapter "")
        (book "")
        (last-book "")
        (pointer 1)
    (word-list (emacs-sword--search-criteria-breakdown word))
    (buff (buffer-name))
        (Bible (emacs-sword--query-user 'bible)))
    (message Bible)
    (emacs-sword--word-search-backend verse chapter book pointer word-list Bible) ; run the backend
    ;; Now, we need to export from the temp buffer to the current buffer
    (insert (concat "\n:WordSearch:\n# Search String: '" word "'")) ; insert drawer header
    (with-current-buffer  "Word Search" ; go to the search buffer emacs-sword--word-search-backend generates
      (goto-char (point-min)) ; make sure we are at the start (we should be, but just in case)
      (while (re-search-forward "([0-9]+)" nil t) ;; while there are still lines
        (save-excursion
          (message "search")
          (setq verse (thing-at-point 'line t) ; verse is the current line
                pointer (save-excursion (search-forward ".org::") (number-to-string (thing-at-point 'number))) ; pointer is the pointer in the link
                chapter (progn (re-search-backward "***\sChapter") (thing-at-point 'line t)) ; chapter is the last "*** Chapter" instance
                book (progn (org-up-heading-safe) (thing-at-point 'line t)))) ; Book, see org-up-heading-safe for how it works
    (with-current-buffer buff ; Back to the users buffer
      (message "print")
      (insert (concat "\n" (progn (if (equal book last-book) (progn (setq last-chapter "") "") (replace-regexp-in-string "\\** \\([ -z]*\\)" "- \\1 ::" book))))) ; convert the book heading into the list format
      (insert (concat (progn (if (equal chapter last-chapter) "" (replace-regexp-in-string "\\** \\([ -z]*\\)" " - \\1 ::" chapter))) ; convert the chapter to list format
              "    " verse "    [[file:" Bible "::" pointer "][go to verse]]")) ; insert verse and link
      (delete-duplicate-lines (point-at-bol -4) (point)) ; delete the duplicated lines in the past 5 lines
      (setq last-book book  ; set last-book and last-chapter to current book and chapter
        last-chapter chapter))))
    (insert "\n:end:")
    (if (equal verse "")
    (insert "No Verses Found."))))

3.1.5. Word Search Backend

Non interactive function{s} to perform the backend functionality for word search

==:

(defun emacs-sword--word-search-backend (verse chapter book pointer word-list Bible)
  "Backend of word search so both word search and word search immediately can stay up to date"
  
  (if (get-buffer "Word Search")  ; Kill the Word Search buffer if it is open.  Essentially clean up
      (kill-buffer "Word Search"))
  (get-buffer-create "Word Search")
  (with-current-buffer "Word Search"
    (org-mode)
    (insert (concat "# Search String: '" word "'"))
    (message Bible)
    ;;(display-buffer (current-buffer))
    (with-current-buffer  (or (get-file-buffer Bible)
                              (find-file-noselect Bible))

      ;; In the days of yore, this was required to get emacs to search properly
      ;; in word mode.  Not really sure I know why it was, I must have forgotten.
      ;; Either way, it does not seem to be nessicary now, and was causing warnings.
      ;(fundamental-mode)
      (save-excursion
      (message (buffer-file-name))
      (goto-char (point-min))
      (search-forward "* ")
      (while (re-search-forward (car word-list) nil t)
        (save-excursion
          (message "search")
      ;; This line has word-list[0]
      (message (thing-at-point 'line t))
          (setq verse (thing-at-point 'line t)
                pointer (number-to-string (line-number-at-pos))
                chapter (progn (re-search-backward "***\sChapter") (thing-at-point 'line t))
                book (progn (org-up-heading-safe) (thing-at-point 'line t)))
      
      ;; Check if the other words are in the verse
      (setq has-others nil) ; initialise has-others
      (setq others-not-available "no")
      
      (dolist (item word-list) ; for item in word-list
        (if (string-match-p item verse) ; if item (as a regexp) in verse
        (setq has-others t)
          (setq has-others nil
            others-not-available "yes")
          ))
      
      (if (and has-others (equal others-not-available "no")) ; if verse has others and not one of the others is not available
          (progn ;; if yes, then continue as planned
        (message "Verse has all word")
        (with-current-buffer "Word Search"
                  (message "print")
                  (insert (concat "\n" (progn (if (equal book (progn
                                (save-excursion
                                  (org-up-heading-safe)
                                  (thing-at-point 'line t)))) "" book))))
                  (insert (concat (progn (if (equal chapter (progn
                                  (save-excursion
                                (org-back-to-heading)
                                (thing-at-point 'line t)))) "" chapter))
                  verse "[[file:" Bible "::" pointer "][go to verse]]"))
                  (delete-duplicate-lines (point-at-bol -4) (point)))
        )
        (progn ;; else, skip this word
          (message "Verse does not have all words, skipping")
          )
        )
      
          )))

      ;(org-mode)
      )
    (goto-char (point-min))
    (if (equal verse "")
    (insert "No Verses Found.")))
  
  )
  1. Search Criteria Breakdown

    ==:

    (defun emacs-sword--search-criteria-breakdown (search)
      
      (setq returnvalue nil) ; initialise return value
      
      (if (equal emacs-sword-search-mode "strict") ; if search mode is strict, return list where car is search
          (setq returnvalue `(,search)))
      (if (equal emacs-sword-search-mode "words") ; if search mode is words, return list where all words have a space before
          (let ((word-list (split-string search " "))
            (with-spaces '()))
        (dolist (i word-list )
            (setq with-spaces (append with-spaces (list (concat " " i))))
            )
        (setq returnvalue with-spaces)
        ))
      (if (equal-including-properties emacs-sword-search-mode "loose") ; if search mode is loose, return list with all words
          (let ((word-list (split-string search " ")))
        (setq returnvalue word-list)
        ))
      (sort returnvalue                   ; Sort return value by length
        (lambda (a b)
          (> (length a) (length b)))) ; End sort
      returnvalue ; return return value
      )
    

3.1.6. Audio Playing

This is a function for playing audio. To use, press 'C-S-b a' after a list with the format of (BOOKssCHAPTER) where BOOK is the book you want, s is space, and CHAPTER is the chapter you want to start on.

==:

(defun emacs-sword-play-audio ()
  "This is a function for playing audio
 To use, press C-S-b a after a list with the format of (BOOKssCHAPTER) where BOOK is the book you want, s is space, and CHAPTER is the chapter you want to start on."
  (interactive)
  (let ((output "")
        (verse (save-excursion
                 (search-backward ")")(or (thing-at-point 'list) (concat (thing-at-point 'sexp) ")"))))
        (book "")
        (chapter "")
    (multiple ""))
    (message "Let #1")
    (with-temp-buffer
      (message "Change Buffer to search")
      (goto-char (point-min))
      (insert verse)
      (goto-char (point-min))
      (message "Reference inserted in temp buffer")
      (setq book (progn (re-search-forward "[0-9]?\\s-?[A-z]+\\s-?[0-9]?") (match-string 0))
            chapter (progn  (re-search-forward "[0-9]+") (match-string 0))
        multiple (if (equal ?- (following-char)) ">")
        default-directory (substring (shell-command-to-string (concat "/bin/echo " (expand-file-name (concat emacs-sword-sheath emacs-sword-audio-directory "*-\"" (string-trim-right book) "\"/")))) 0 -1))
      (setq book (emacs-sword--check-book (string-trim-right book)))
      (message "set all search params")
      (message multiple)
      (message default-directory)
      (setq output (concat "\"" book (if (equal (length chapter) 1) "0") chapter ".mp3\""))
      (if (equal multiple ">")
      (progn
        (message "multiple")
        (setq chapter (number-to-string (+ 1 (string-to-number chapter))))
        (message chapter)
        (while (file-exists-p (concat "" book (if (equal (length chapter) 1) "0") chapter ".mp3"))
        (setq output (concat output  " "  (concat "\"" book (if (equal (length chapter) 1) "0") chapter ".mp3\""))
          chapter (number-to-string (+ 1 (string-to-number chapter))))
        (message output))))
      (message (concat emacs-sword-player " " output))
      (start-process-shell-command "emacs-sword-audio" nil (concat emacs-sword-player " " output )))))

3.1.7. Book Abbreviation Expasion

checks if book is an abbreviation, if so, expands to full lenght

==:

(defun emacs-sword--check-book (book)
  "checks if book is an abbreviation, if so, expands book to full length."
  (message book)
  (setq book (emacs-sword--captialize-abbrev book))
  (if (eq (length book) 3)
      (progn
    (message "Expanding book abbreviation...")
    (setq book (cdr (assoc book emacs-sword-abbreviations)))
    (message "done")
    (message book))
    (progn
      (message "book not an abbreviation in 'emacs-sword-abbreviations. Checking Levenshtein...")
      (emacs-sword--check-book-levenshtein book)
      )))

3.1.8. Capitalise Abbreviation

==:

(defun emacs-sword--captialize-abbrev (input)
  "Capitalise the input as an abbreviation
This actually captializes the second character if the first is non-capitalizable"
  (let ((old (downcase input))
    (new (downcase input)))
    (setq new (concat (upcase (substring new 0 1)) (substring new 1)))
    (if (eq 0 (string-match-p "[0-9]" (substring new 0 1)))
    (setq new (concat (substring new 0 1) (capitalize (substring new 1)))))
    (message new)
    )
  )

3.1.9. Abbreviation List

==:

(defun emacs-sword-visit-abbrev ()
  "Lists all abbreviations and what they abbreviate in an alist."
  (declare (obsolete "please use the built in function (describe-variable). Will be removed by v3.5 or v4.0, whichever is soonest" "3.0.0"))
  (interactive)
  (describe-variable 'emacs-sword-abbreviations))

3.1.10. Book Levenshtein Distance

==:

(defun emacs-sword--check-book-levenshtein (book)
  "checks if a book is within a certain levenshtein distance (with transpositions) of any book name"
  (message book)
  (let ((cost 100)
    (last-cost)
    (true-book))
    (progn
      (dolist (element emacs-sword-abbreviations true-book)
    (setq last-cost cost)
    (setq cost (min cost (levenshtein-distance (upcase (cdr element)) (upcase book))) )
    (if (not (equal last-cost cost))
        (setq true-book (cdr element))
      )
    )
      )
    )
  )

3.1.11. Query User for Bible or Resources

==:


(defun emacs-sword--query-user (for-what)
  "Query the user for which `for-what' (which is a symbol) to use.
Valid valued are: `bible', `dicationary', and `resource'"
  (let ((directory (symbol-value (intern-soft (concat "emacs-sword-" (symbol-name for-what) "-directory"))))
        (list (symbol-value (intern-soft (concat "emacs-sword-" (symbol-name for-what) "-list")))))
    (concat
     emacs-sword-sheath
     directory
     (elt list
          (-
           (read-number
            (concat (format "Choose a %s: %s" (capitalize (symbol-name for-what)) list) " " (capitalize (symbol-name for-what)) " Number ")
            )
           1)
          )
     )))

3.2. Resource and Dictionary Functions

3.2.1. Got To Definition

This function finds a Strong's Number in the previous list (eg. (g1)) and opens it in another window. The syntax is (DN) where D is h or g (h for hebrew and g for greek), and N is number The command to run this function is C-S-b g (or Ctrl-Shift-b g) or you could call it with M-x emacs-sword-goto-def (where M is Alt).

==:

  (defun emacs-sword-goto-def ()
    "This function finds a Strong's Number in the previous list (eg. (g1)) and opens it in another window.  The syntax is (DN) where D is h or g (h for hebrew and g for greek), and N is number
The command to run this function is C-S-b g (or Ctrl-Shift-b g) or you could call it with M-x emacs-sword-goto-def (where M is Alt)."
    (interactive)
    (let ((dictionary "")
          (id "")
          (command (save-excursion
                       (search-backward ")") (thing-at-point 'list t))))
      (get-buffer-create "kjv-search")
      (with-current-buffer "kjv-search"
        (message "Change Buffer to kjv-search")
        (goto-char (point-min))
        (insert command)
        (goto-char (point-min))
    (message "set dictionary...")
        (setq dictionary (progn (re-search-forward "h\\|g") (cond ((string= (match-string 0) "h") (concat emacs-sword-sheath emacs-sword-dictionary-directory emacs-sword-hebrew-dictionary)) ((string= (match-string 0) "g") (concat emacs-sword-sheath emacs-sword-dictionary-directory emacs-sword-greek-dictionary))))
        id (progn (goto-char (point-min)) (re-search-forward "[0-9]+") (concat "(" (match-string 0) ")")))
      (message "set all search params")
      (kill-current-buffer))
      (message "%s" dictionary)
      (message "%s" id)
      (set-buffer (or (get-file-buffer dictionary)
                      (find-file-noselect dictionary)))
      (goto-char (point-min))
      (search-forward (concat "** " id))
      (view-buffer-other-window (current-buffer))
      (message "done")))

3.2.2. Link Resource

This function is for linking a resource. The syntax is [REFERNECE] where REFERENCE is the header (sans *s) you want to link. You can run this function with C-S-b l r.

==:

(defun emacs-sword-link-resource (desc)
  "This function is for linking a resource. The syntax is [REFERNECE] where REFERENCE is the header (sans *s) you want to link.
You can run this function with C-S-b l r."
  (interactive "sWhat is the link decription?(default: [Reference]) ")
  (let ((output "")
        (resource (save-excursion
                    (search-backward "]")(search-forward "]")(thing-at-point 'sexp t)))
        (chapter "")
        (book (emacs-sword--query-user 'resource)))
    (message "Let #1")
    (with-current-buffer (or (get-file-buffer book)
                             (find-file-noselect book))
      (message "Change Buffer to %s" book)
      (save-excursion
        (message "move point")
        (goto-char (point-min))
        (get-buffer-create "search")
        (with-current-buffer "search"
          (message "Change Buffer to search")
          (goto-char (point-min))
          (insert resource)
          (goto-char (point-min))
          (setq chapter (progn (goto-char (point-min)) (re-search-forward "\\[.+") (substring (match-string 0) 1 -1)))
          (message "set all search params")
      (if desc 
          (setq desc chapter))
      (message desc)
          (kill-current-buffer))
    (re-search-forward (concat "\\*+\s" chapter))
        (message "chapter: %s" chapter)
        (message "%s" (point))
        (message "%s" (current-buffer))
        (setq output (concat "[[file:" book "::" (number-to-string (line-number-at-pos)) "][" desc "]]" ))
        ))
    (save-excursion
      (let ((bound1 nil)
            (bound2 nil))
        (search-backward "[")
        (setq bound1 (point))
        (thing-at-point 'sexp)
        (search-forward "]")
        (setq bound2 (point))
        (delete-region bound1 bound2)
        (insert output)))))

3.2.3. Visit Resources

Open the resource directory in a dired buffer. The key-binding for this is C-S-b r v

==:

(defun emacs-sword-visit-bibles ()
  "Query user for which Bible to visit, then open it in view-mode."
  (interactive)
  (let ((bible (emacs-sword--query-user 'bible)))
    (view-file bible)))
(defun emacs-sword-visit-dictionaries ()
  "Query user for which dictionary to visit, then open it in view-mode."
  (interactive)
  (let ((dict (emacs-sword--query-user 'dictionary)))
    (view-file dict)))

;; Begin Legacy Visit Functions
(defun emacs-sword-visit-resources ()
  "Open `emacs-sword-resource-directory' in `dired'.

While this function uses the legacy visit definition, it works best for resources that may not be in the `emacs-sword-resource-list', as they are (for example) images or something."
  (interactive)
  (dired (concat emacs-sword-sheath emacs-sword-resource-directory)))
(defun emacs-sword-visit-dictionaries-legacy ()
  "Open `emacs-sword-dictionary-directory' in `dired'"
  (interactive)
  (dired (concat emacs-sword-sheath emacs-sword-dictionary-directory)))
(defun emacs-sword-visit-bibles-legacy ()
  "Open `emacs-sword-bible-directory' in `dired'"
  (interactive)
  (dired (concat emacs-sword-sheath emacs-sword-bible-directory)))
;; End Legacy Visit Functions

3.2.4. Download Resources

You can download resources from MalanderEngineering.com or any other url you decide to use

==:

(defun emacs-sword-resource-downloader (url)
  (interactive "sPlease enter the url of the resource you want to download. if blank, you can see the resources at emacs-sword-resource-repository: ")
  (message url)
  (if (> (length url) 1)
      (with-temp-buffer
    (setq-local def-dir default-directory
            default-directory (concat emacs-sword-sheath emacs-sword-resource-directory))
    (shell-command (concat "wget '" url "'") t)
    (shell-command "unzip *.zip" t))
    (progn
      (eww emacs-sword-resource-repository)
      (switch-to-buffer "*eww*")
      (local-set-key (kbd "d") 'emacs-sword--download)
      (local-set-key (kbd "q") 'emacs-sword--kill-eww))))
(defun emacs-sword--kill-eww ()
  (interactive)
  (local-set-key (kbd "d") 'eww-download)
  (kill-buffer "*eww*")
  (with-temp-buffer
    (setq-local def-dir default-directory
        default-directory (concat emacs-sword-sheath emacs-sword-resource-directory))
    (shell-command  "unzip *.zip" t)
    (shell-command "rm *.zip" t)))

3.2.5. download

simple fork of eww-download

==:

(defun emacs-sword--download ()
  "simple fork of `eww-download'.
Use link at point if there is one, else the current page's URL."
  (interactive)
  (access-file (concat emacs-sword-sheath emacs-sword-resource-directory) "Download failed")
  (let ((url (or (get-text-property (point) 'shr-url)
                 (eww-current-url))))
    (if (not url)
        (message "No URL under point")
      (url-retrieve url 'emacs-sword--download-callback (list url)))))
(defun emacs-sword--download-callback (status url)
  (unless (plist-get status :error)
    (let* ((obj (url-generic-parse-url url))
           (path (directory-file-name (car (url-path-and-query obj))))
           (file (eww-make-unique-file-name
                  (eww-decode-url-file-name (file-name-nondirectory path))
                  (concat emacs-sword-sheath emacs-sword-resource-directory))))
      (goto-char (point-min))
      (re-search-forward "\r?\n\r?\n")
      (let ((coding-system-for-write 'no-conversion))
        (write-region (point) (point-max) file))
      (message "Saved %s" file))))

3.3. Preperation and Initilisation

3.3.1. Emacs Sword Initialisation

This function generates some Bibles and Dictionaries once.

==:


(defun emacs-sword-init ()
  (if (file-directory-p emacs-sword-sheath)
      (message "Emacs Sword already initialized.")
    (with-temp-buffer
      (message "Emacs Sword is not initialized.  Downloading default resources...")
      (shell-command "wget https://malanderengineering.com/packages/repo/emacs-sword.zip" t)
      (shell-command (concat "unzip emacs-sword.zip -d " emacs-sword-sheath) t)
      (shell-command "rm emacs-sword.zip" t))))
(emacs-sword-init)

3.3.2. Customise Emacs Sword

This function opens the emacs-sword customization. The command to run this function is C-S-b c (or Ctrl-Shift-b c) or you could call it with M-x emacs-sword-customize (where M is Alt).

==:

  (defun emacs-sword-customize ()
    "This function opens the emacs-sword customization.
The command to run this function is C-S-b c (or Ctrl-Shift-b c) or you could call it with M-x emacs-sword-customize (where M is Alt)."
    (interactive)
    (customize-group-other-window 'emacs-sword))

3.3.3. Prepare KJV+

this function is used for preparing KJV+ it is already complete, so you dont need it.

==:

  (defun emacs-sword-prepare-kjv+ ()
    "Convert kjv+ from Xiphos extract format to proper org-mode format"
    (interactive)
    (let ((id 1)
          (place (point)))
      (save-excursion
        (query-replace-regexp "(1)" "*** Chapter \n(1)")
        )
      (save-excursion
        (while (search-forward "*** Chapter" nil t)
          (insert (concat " " (number-to-string id)))
          (setq id (+ id 1))))
      (save-excursion
        (query-replace-regexp "H\\([0-9]+\\)" "[[file:strongshebrew.org::*(\\1)][\\1]]"))))


(defun emacs-sword-prepare-bible ()
  "Insert org-mode headers for each chapter"
    (interactive)
    (let ((id 1)
          (place (point)))
      (save-excursion
        (query-replace-regexp "(1)" "*** Chapter \n(1)")
        )
      (save-excursion
        (while (search-forward "*** Chapter" nil t)
          (insert (concat " " (number-to-string id)))
          (setq id (+ id 1))))))

3.3.4. Reload KJV+ Numbers

This function corrects the links in KJV+. whenever you change your emacs-sword customization is it a good idea to run this command. The command to run this function is C-S-b r r (or Ctrl-Shift-b r r) or you could call it with M-x emacs-sword-reload-KJV+-numbers (where M is Alt).

==:

    (defun emacs-sword-reload-KJV+-numbers ()
      "This function corrects the links in KJV+.  whenever you change your emacs-sword custom variables is it a good idea to run this command.
The command to run this function is C-S-b r r (or Ctrl-Shift-b r r) or you could call it with M-x emacs-sword-reload-KJV+-numbers (where M is Alt)."
      (interactive)
      (let ((Bible (concat emacs-sword-sheath emacs-sword-bible-directory "KJV+.org")))
        (with-current-buffer (or (get-file-buffer Bible)
                                 (find-file-noselect Bible))
          (replace-regexp "file:.+?strong" (concat "file:" emacs-sword-sheath emacs-sword-dictionary-directory "strong")))))

3.4. Listify

This function makes a table into a list. You must use two column tables The keybinding is C-S-b t

==:

(defun emacs-sword-listify (table pre)
  "This function makes a table into a list. You must use two column tables
The keybinding is C-S-b t"
  (interactive "nHow many rows (excluding key and --- based rows) are in the table? \nnHow many lines are key or --- based? ")
  (if (eq pre 0)
      (message "not killing lines")
    (dotimes (i (+ 1 pre))
      (kill-line)))
  (let ((start (point))
    (end (save-excursion (search-forward "\n" nil nil (+ 1 table)))))
    (replace-regexp "|\s+\\([,-z]+\\)\s+|\s+\\([,-z\s]+\\)\s+|" "-\s=\\1=\n\t\\2" nil start end)))

3.5. UI

3.5.1. Treemacs-sword init

This function checks if treemacs is availible, if so, makes an emacs sword workspace.

Seems to be kinda buggy, consider removing it.

==:

(if emacs-sword-enable-treemacs
    (progn
      (require 'treemacs)
      (treemacs)
      (treemacs)
      (setq emacs-sword-treemacs-work (expand-file-name (substring emacs-sword-sheath 0 -1)))
      (defun emacs-sword--treemacs-sword ()
        (if (string-search emacs-sword-treemacs-work (format "%s" (treemacs-workspaces)))
            (message "workspace exists...")
          (with-temp-buffer
            (split-window-below)
            (treemacs-edit-workspaces)
            (goto-char (point-max))
            (insert (concat "* Emacs Sword\n** Emacs-Sword\n- path :: " emacs-sword-treemacs-work))
            (treemacs-finish-edit))))
      (emacs-sword--treemacs-sword)
      (defun emacs-sword-treemacs ()
        (interactive)
        (treemacs-do-switch-workspace "Emacs Sword")
        (treemacs))))

3.5.2. Emacs sword Treemacs

This function will open a treemacs buffer with the Emacs Sword workspace. Run by pressing C-S-b t.

emacs-sword-treemacs:

(defun emacs-sword-treemacs ()
  (interactive)
  (treemacs-do-switch-workspace "Emacs Sword")
  (treemacs))

3.6. Levenshtein Distance

==:

;; levenshtein.el --- Edit distance between two strings.

; Copyright (C) 2003, 2005  Aaron S. Hawley, Art Taylor

(defun levenshtein-distance (str1 str2)
  "Return the edit distance between strings STR1 and STR2. now with transpositions"
  (if (not (stringp str1))
      (error "Argument was not a string: %s" str1))
  (if (not (stringp str2))
      (error "Argument was not a string: %s" str2))
  (let* ((make-table ;; Multi-dimensional array object.
          (function
           (lambda (columns rows init)
             (make-vector rows (make-vector columns init)))))
         (tref ;; Table access method.
          (function
           (lambda (table x y)
            (aref (aref table y) x))))
         (tset ;; Table write method.
          (function
           (lambda
             (table x y object)
             (let ((row (copy-sequence (aref table y))))
               (aset row x object)
               (aset table y row)
               object))))
         ;; End table code.
         (length-str1 (length str1))
         (length-str2 (length str2))
         ;; d is a table with lenStr2+1 rows and lenStr2+1 columns
         (d (funcall make-table (1+ length-str1) (1+ length-str2)
                                0))) ;; Initialize to zero.
    ;; i and j are used to iterate over str1 and str2
    (let ((i 0)
          (j 0))
      (while (<= i length-str1) ;; for i from 0 to lenStr1
        (funcall tset d i 0 i) ;; d[i, 0] := i
        (setq i (1+ i))) ;; i++
      (while (<= j length-str2) ;; for j from 0 to lenStr2
        (funcall tset d 0 j j) ;; d[0, j] := j
        (setq j (1+ j)))) ;; j++
    (let ((i 1))
      (while (<= i length-str1) ;; for i from 1 to lenStr1
        (let ((j 1))
          (while (<= j length-str2) ;; for j from 1 to lenStr2
            (let* ((cost
                    ;; if str[i] = str[j] then cost:= 0 else cost := 1
                    (if (equal (aref str1 (1- i)) (aref str2 (1- j)))
                        0
                      1))
                   ;; d[i-1, j] + 1     // deletion
                   (deletion (1+ (funcall tref d (1- i) j)))
                   ;; d[i, j-1] + 1     // insertion
                   (insertion (1+ (funcall tref d i (1- j))))
                   ;; d[i-j,j-1] + cost // substitution
                   (substitution
                    (+ (funcall tref d (1- i) (1- j)) cost))
           (transposition
            (if (and (> i 1) (> j 1) (equal (aref str1 (1- i)) (aref str2 (- j 2))) (equal (aref str1 (- i 2)) (aref str2 (1- j))) )
            (1+ (funcall tref d (- i 2) (- j 2)))
              10)
            ))
              (funcall tset d i j ;; d[i,j] := minimum(
                    (min insertion deletion substitution transposition)))
            (setq j (1+ j)))) ;; j++
        (setq i (1+ i)))) ;; i++
    ;; return d[lenStr1, lenStr2]
    (funcall tref d length-str1 length-str2)))


;; levenshtein.el ends here

3.7. Set Prefix Key

==:

(defun emacs-sword--set-prefix-key (prefix)
  "if prefix is not an empty string, set the emacs-sword-map to prefix, otherwise do nothing"

  (if (not (equal prefix ""))
      (global-set-key (kbd prefix) emacs-sword-map))
  
  )

4. Key Binding

These are the key bindings for emacs-sword. Do not alter unless you know what you are doing. If you do alter, please change the documentation accordingly

4.1. Bindings

==:

(define-prefix-command 'emacs-sword-map)

(global-set-key (kbd "C-S-b") emacs-sword-map)

;prefix begin
(define-prefix-command 'emacs-sword-link)
(define-key emacs-sword-map (kbd "l") 'emacs-sword-link)

(define-prefix-command 'emacs-sword-visit)
(define-key emacs-sword-map (kbd "v") 'emacs-sword-visit)

(define-prefix-command 'emacs-sword-resource-manipulation)
(define-key emacs-sword-map (kbd "r") 'emacs-sword-resource-manipulation)

(define-prefix-command 'emacs-sword-immediately)
(define-key emacs-sword-map (kbd "i") 'emacs-sword-immediately)
;prefix end

(define-key emacs-sword-map (kbd "f") 'emacs-sword-find-verse)
(define-key emacs-sword-map (kbd "l v") 'emacs-sword-link-verse)
(define-key emacs-sword-map (kbd "g") 'emacs-sword-goto-def)
(define-key emacs-sword-map (kbd "c") 'emacs-sword-customize)
(define-key emacs-sword-map (kbd "r r") 'emacs-sword-reload-KJV+-numbers)
(define-key emacs-sword-map (kbd "s") 'emacs-sword-word-search)
(define-key emacs-sword-map (kbd "i s") 'emacs-sword-word-search-immediately)
(define-key emacs-sword-map (kbd "a") 'emacs-sword-play-audio)
(define-key emacs-sword-map (kbd "l r") 'emacs-sword-link-resource)
(if emacs-sword-enable-treemacs
    (define-key emacs-sword-map (kbd "t") 'emacs-sword-treemacs))
(define-key emacs-sword-map (kbd ";") 'emacs-sword-listify)
(define-key emacs-sword-map (kbd "v r") 'emacs-sword-visit-resources)
(define-key emacs-sword-map (kbd "v d") 'emacs-sword-visit-dictionaries)
(define-key emacs-sword-map (kbd "v b") 'emacs-sword-visit-bibles)
(define-key emacs-sword-map (kbd "v a") 'emacs-sword-visit-abbrev)
(define-key emacs-sword-map (kbd "r d") 'emacs-sword-resource-downloader)

(define-minor-mode emacs-sword-legacy-visit-mode
  "Minor mode to tell Emacs Sword to use the legacy visit functions"
  :global t
  :init-value nil
  :keymap (let ((map (make-sparse-keymap)))
            (define-key map (kbd "C-S-b v b") 'emacs-sword-visit-bibles-legacy)
            (define-key map (kbd "C-S-b v d") 'emacs-sword-visit-dictionaries-legacy)
            
            map)
  )

5. Package footer

this is a footer for the package

==:

(provide 'emacs-sword)
;;; emacs-sword.el ends here

Author: William Malander

Created: 2026-07-26 Sun 10:23

Validate