From c39d006fec380f70fd538f8f75b2c734e9a7c106 Mon Sep 17 00:00:00 2001 From: Judah Date: Mon, 4 Mar 2024 17:32:08 -0500 Subject: [PATCH] feat[Make] Copied scripts from kjv Copied the awk scripts, Makefile from lukesmith's kjv repo --- .gitignore | 1 + Makefile | 30 ++++++ add-booknames.py | 273 ----------------------------------------------- esv.awk | 210 ++++++++++++++++++++++++++++++++++++ esv.sh | 95 +++++++++++++++++ json-to-tsv.py | 17 --- 6 files changed, 336 insertions(+), 290 deletions(-) create mode 100644 .gitignore create mode 100644 Makefile delete mode 100755 add-booknames.py create mode 100644 esv.awk create mode 100644 esv.sh delete mode 100755 json-to-tsv.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8c9204a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +esv diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b5bfde2 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +## +# esv command line bible +# + +PREFIX = /usr/local + +esv: esv.sh esv.awk esv.tsv + cat esv.sh > $@ + echo 'exit 0' >> $@ + echo '#EOF' >> $@ + tar czf - esv.awk esv.tsv >> $@ + chmod +x $@ + +test: esv.sh + shellcheck -s sh esv.sh + +clean: + rm -f esv + +install: esv + mkdir -p $(DESTDIR)$(PREFIX)/bin + cp -f esv $(DESTDIR)$(PREFIX)/bin + chmod 755 $(DESTDIR)$(PREFIX)/bin/esv + +uninstall: + rm -f $(DESTDIR)$(PREFIX)/bin/esv + +.PHONY: test clean install uninstall + +# end diff --git a/add-booknames.py b/add-booknames.py deleted file mode 100755 index 83643b9..0000000 --- a/add-booknames.py +++ /dev/null @@ -1,273 +0,0 @@ -#!/usr/bin/env python3 -import re -f = open('esv.tsv', 'r') -outfile = open('esv-correct.tsv', 'w') -testfile = open('test.tsv', 'w') -for item in f: - - number = re.search('[0-9]+', item).group() - - match number: - case "1": - testfile.write(item) - outfile.write("Genesis Ge\t" + item) - - case "2": - testfile.write(item) - outfile.write("Exodus Exo\t" + item) - - case "3": - testfile.write(item) - outfile.write("Leviticus Lev\t" + item) - - case "4": - testfile.write(item) - outfile.write("Numbers Num\t" + item) - - case "5": - testfile.write(item) - outfile.write("Deuteronomy Deu\t" + item) - - case "6": - testfile.write(item) - outfile.write("Joshua Josh\t" + item) - - case "7": - testfile.write(item) - outfile.write("Judges Jdgs\t" + item) - - case "8": - testfile.write(item) - outfile.write("Ruth Ruth\t" + item) - - case "9": - testfile.write(item) - outfile.write("1 Samuel 1Sm\t" + item) - - case "10": - testfile.write(item) - outfile.write("2 Samuel 2Sm\t" + item) - - case "11": - testfile.write(item) - outfile.write("1 Kings 1Ki\t" + item) - - case "12": - testfile.write(item) - outfile.write("2 Kings 2Ki\t" + item) - - case "13": - testfile.write(item) - outfile.write("1 Chronicles 1Chr\t" + item) - - case "14": - testfile.write(item) - outfile.write("2 Chronicles 2Chr\t" + item) - - case "15": - testfile.write(item) - outfile.write("Ezra Ezra\t" + item) - - case "16": - outfile.write("Nehemiah Neh\t" + item) - testfile.write(item) - - case "17": - testfile.write(item) - outfile.write("Esther Est\t" + item) - - case "18": - testfile.write(item) - outfile.write("Job Job\t" + item) - - case "19": - testfile.write(item) - outfile.write("Psalms Psa\t" + item) - - case "20": - testfile.write(item) - outfile.write("Proverbs Prv\t" + item) - - case "21": - testfile.write(item) - outfile.write("Ecclesiastes Eccl\t" + item) - - case "22": - testfile.write(item) - outfile.write("Song of Solomon SSol\t" + item) - - case "23": - testfile.write(item) - outfile.write("Isaiah Isa\t" + item) - - case "24": - testfile.write(item) - outfile.write("Jeremiah Jer\t" + item) - - case "25": - testfile.write(item) - outfile.write("Lamentations Lam\t" + item) - - case "26": - testfile.write(item) - outfile.write("Ezekiel Eze\t" + item) - - case "27": - testfile.write(item) - outfile.write("Daniel Dan\t" + item) - - case "28": - testfile.write(item) - outfile.write("Hosea Hos\t" + item) - - case "29": - testfile.write(item) - outfile.write("Joel Joel\t" + item) - - case "30": - testfile.write(item) - outfile.write("Amos Amos\t" + item) - - case "31": - testfile.write(item) - outfile.write("Obadiah Obad\t" + item) - - case "32": - testfile.write(item) - outfile.write("Jonah Jonah\t" + item) - - case "33": - testfile.write(item) - outfile.write("Micah Mic\t" + item) - - case "34": - testfile.write(item) - outfile.write("Nahum Nahum\t" + item) - - case "35": - testfile.write(item) - outfile.write("Habakkuk Hab\t" + item) - - case "36": - testfile.write(item) - outfile.write("Zephaniah Zep\t" + item) - - case "37": - testfile.write(item) - outfile.write("Haggai Hag\t" + item) - - case "38": - testfile.write(item) - outfile.write("Zechariah Zec\t" + item) - - case "39": - testfile.write(item) - outfile.write("Malachi Mal\t" + item) - - case "40": - testfile.write(item) - outfile.write("Matthew Mat\t" + item) - - case "41": - testfile.write(item) - outfile.write("Mark Mark\t" + item) - - case "42": - testfile.write(item) - outfile.write("Luke Luke\t" + item) - - case "43": - testfile.write(item) - outfile.write("John John\t" + item) - - case "44": - testfile.write(item) - outfile.write("The Acts Acts\t" + item) - - case "45": - testfile.write(item) - outfile.write("Romans Rom\t" + item) - - case "46": - testfile.write(item) - outfile.write("1 Corinthians 1Cor\t" + item) - - case "47": - testfile.write(item) - outfile.write("2 Corinthians 2Cor\t" + item) - - case "48": - testfile.write(item) - outfile.write("Galatians Gal\t" + item) - - case "49": - testfile.write(item) - outfile.write("Ephesians Eph\t" + item) - - case "50": - testfile.write(item) - outfile.write("Philippians Phi\t" + item) - - case "51": - testfile.write(item) - outfile.write("Colossians Col\t" + item) - - case "52": - testfile.write(item) - outfile.write("1 Thessalonians 1Th\t" + item) - - case "53": - testfile.write(item) - outfile.write("2 Thessalonians 2Th\t" + item) - - case "54": - testfile.write(item) - outfile.write("1 Timothy 1Tim\t" + item) - - case "55": - testfile.write(item) - outfile.write("2 Timothy 2Tim\t" + item) - - case "56": - testfile.write(item) - outfile.write("Titus Titus\t" + item) - - case "57": - testfile.write(item) - outfile.write("Philemon Phmn\t" + item) - - case "58": - testfile.write(item) - outfile.write("Hebrews Heb\t" + item) - - case "59": - testfile.write(item) - outfile.write("James Jas\t" + item) - - case "60": - testfile.write(item) - outfile.write("1 Peter 1Pet\t" + item) - - case "61": - testfile.write(item) - outfile.write("2 Peter 2Pet\t" + item) - - case "62": - testfile.write(item) - outfile.write("1 John 1Jn\t" + item) - - case "63": - testfile.write(item) - outfile.write("2 John 2Jn\t" + item) - - case "64": - testfile.write(item) - outfile.write("3 John 3Jn\t" + item) - - case "65": - testfile.write(item) - outfile.write("Jude Jude\t" + item) - - case "66": - testfile.write(item) - outfile.write("Revelation Rev\t" + item) diff --git a/esv.awk b/esv.awk new file mode 100644 index 0000000..399516f --- /dev/null +++ b/esv.awk @@ -0,0 +1,210 @@ +BEGIN { + # $1 Book name + # $2 Book abbreviation + # $3 Book number + # $4 Chapter number + # $5 Verse number + # $6 Verse + FS = "\t" + + MAX_WIDTH = 80 + if (ENVIRON["ESV_MAX_WIDTH"] ~ /^[0-9]+$/) { + if (int(ENVIRON["ESV_MAX_WIDTH"]) < MAX_WIDTH) { + MAX_WIDTH = int(ENVIRON["ESV_MAX_WIDTH"]) + } + } + + if (cmd == "ref") { + mode = parseref(ref, p) + p["book"] = cleanbook(p["book"]) + } +} + +cmd == "list" { + if (!($2 in seen_books)) { + printf("%s (%s)\n", $1, $2) + seen_books[$2] = 1 + } +} + +function parseref(ref, arr) { + # 1. + # 2. :? + # 3. :?: + # 3a. :?:[,]... + # 4. :?- + # 5. :?:- + # 6. :?:-: + # 7. / + # 8. /search + # 9. :?/search + + if (match(ref, "^[1-9]?[a-zA-Z ]+")) { + # 1, 2, 3, 3a, 4, 5, 6, 8, 9 + arr["book"] = substr(ref, 1, RLENGTH) + ref = substr(ref, RLENGTH + 1) + } else if (match(ref, "^/")) { + # 7 + arr["search"] = substr(ref, 2) + return "search" + } else { + return "unknown" + } + + if (match(ref, "^:?[1-9]+[0-9]*")) { + # 2, 3, 3a, 4, 5, 6, 9 + if (sub("^:", "", ref)) { + arr["chapter"] = int(substr(ref, 1, RLENGTH - 1)) + ref = substr(ref, RLENGTH) + } else { + arr["chapter"] = int(substr(ref, 1, RLENGTH)) + ref = substr(ref, RLENGTH + 1) + } + } else if (match(ref, "^/")) { + # 8 + arr["search"] = substr(ref, 2) + return "search" + } else if (ref == "") { + # 1 + return "exact" + } else { + return "unknown" + } + + if (match(ref, "^:[1-9]+[0-9]*")) { + # 3, 3a, 5, 6 + arr["verse"] = int(substr(ref, 2, RLENGTH - 1)) + ref = substr(ref, RLENGTH + 1) + } else if (match(ref, "^-[1-9]+[0-9]*$")) { + # 4 + arr["chapter_end"] = int(substr(ref, 2)) + return "range" + } else if (match(ref, "^/")) { + # 9 + arr["search"] = substr(ref, 2) + return "search" + } else if (ref == "") { + # 2 + return "exact" + } else { + return "unknown" + } + + if (match(ref, "^-[1-9]+[0-9]*$")) { + # 5 + arr["verse_end"] = int(substr(ref, 2)) + return "range" + } else if (match(ref, "-[1-9]+[0-9]*")) { + # 6 + arr["chapter_end"] = int(substr(ref, 2, RLENGTH - 1)) + ref = substr(ref, RLENGTH + 1) + } else if (ref == "") { + # 3 + return "exact" + } else if (match(ref, "^,[1-9]+[0-9]*")) { + # 3a + arr["verse", arr["verse"]] = 1 + delete arr["verse"] + do { + arr["verse", substr(ref, 2, RLENGTH - 1)] = 1 + ref = substr(ref, RLENGTH + 1) + } while (match(ref, "^,[1-9]+[0-9]*")) + + if (ref != "") { + return "unknown" + } + + return "exact_set" + } else { + return "unknown" + } + + if (match(ref, "^:[1-9]+[0-9]*$")) { + # 6 + arr["verse_end"] = int(substr(ref, 2)) + return "range_ext" + } else { + return "unknown" + } +} + +function cleanbook(book) { + book = tolower(book) + gsub(" +", "", book) + return book +} + +function bookmatches(book, bookabbr, query) { + book = cleanbook(book) + if (book == query) { + return book + } + + bookabbr = cleanbook(bookabbr) + if (bookabbr == query) { + return book + } + + if (substr(book, 1, length(query)) == query) { + return book + } +} + +function printverse(verse, word_count, characters_printed) { + if (ENVIRON["ESV_NOLINEWRAP"] != "" && ENVIRON["ESV_NOLINEWRAP"] != "0") { + printf("%s\n", verse) + return + } + + word_count = split(verse, words, " ") + for (i = 1; i <= word_count; i++) { + if (characters_printed + length(words[i]) + (characters_printed > 0 ? 1 : 0) > MAX_WIDTH - 8) { + printf("\n\t") + characters_printed = 0 + } + if (characters_printed > 0) { + printf(" ") + characters_printed++ + } + printf("%s", words[i]) + characters_printed += length(words[i]) + } + printf("\n") +} + +function processline() { + if (last_book_printed != $2) { + print $1 + last_book_printed = $2 + } + + printf("%d:%d\t", $4, $5) + printverse($6) + outputted_records++ +} + +cmd == "ref" && mode == "exact" && bookmatches($1, $2, p["book"]) && (p["chapter"] == "" || $4 == p["chapter"]) && (p["verse"] == "" || $5 == p["verse"]) { + processline() +} + +cmd == "ref" && mode == "exact_set" && bookmatches($1, $2, p["book"]) && (p["chapter"] == "" || $4 == p["chapter"]) && p["verse", $5] { + processline() +} + +cmd == "ref" && mode == "range" && bookmatches($1, $2, p["book"]) && ((p["chapter_end"] == "" && $4 == p["chapter"]) || ($4 >= p["chapter"] && $4 <= p["chapter_end"])) && (p["verse"] == "" || $5 >= p["verse"]) && (p["verse_end"] == "" || $5 <= p["verse_end"]) { + processline() +} + +cmd == "ref" && mode == "range_ext" && bookmatches($1, $2, p["book"]) && (($4 == p["chapter"] && $5 >= p["verse"] && p["chapter"] != p["chapter_end"]) || ($4 > p["chapter"] && $4 < p["chapter_end"]) || ($4 == p["chapter_end"] && $5 <= p["verse_end"] && p["chapter"] != p["chapter_end"]) || (p["chapter"] == p["chapter_end"] && $4 == p["chapter"] && $5 >= p["verse"] && $5 <= p["verse_end"])) { + processline() +} + +cmd == "ref" && mode == "search" && (p["book"] == "" || bookmatches($1, $2, p["book"])) && (p["chapter"] == "" || $4 == p["chapter"]) && match(tolower($6), tolower(p["search"])) { + processline() +} + +END { + if (cmd == "ref" && outputted_records == 0) { + print "Unknown reference: " ref + } +} diff --git a/esv.sh b/esv.sh new file mode 100644 index 0000000..4f09a37 --- /dev/null +++ b/esv.sh @@ -0,0 +1,95 @@ +#!/bin/sh +# esv: Read the Word of God from your terminal +# License: Public domain + +SELF="$0" + +get_data() { + sed '1,/^#EOF$/d' < "$SELF" | tar xzf - -O "$1" +} + +if [ -z "$PAGER" ]; then + if command -v less >/dev/null; then + PAGER="less" + else + PAGER="cat" + fi +fi + +show_help() { + exec >&2 + echo "usage: $(basename "$0") [flags] [reference...]" + echo + echo " -l list books" + echo " -W no line wrap" + echo " -h show help" + echo + echo " Reference types:" + echo " " + echo " Individual book" + echo " :" + echo " Individual chapter of a book" + echo " ::[,]..." + echo " Individual verse(s) of a specific chapter of a book" + echo " :-" + echo " Range of chapters in a book" + echo " ::-" + echo " Range of verses in a book chapter" + echo " ::-:" + echo " Range of chapters and verses in a book" + echo + echo " /" + echo " All verses that match a pattern" + echo " /" + echo " All verses in a book that match a pattern" + echo " :/" + echo " All verses in a chapter of a book that match a pattern" + exit 2 +} + +while [ $# -gt 0 ]; do + isFlag=0 + firstChar="${1%"${1#?}"}" + if [ "$firstChar" = "-" ]; then + isFlag=1 + fi + + if [ "$1" = "--" ]; then + shift + break + elif [ "$1" = "-l" ]; then + # List all book names with their abbreviations + get_data esv.tsv | awk -v cmd=list "$(get_data esv.awk)" + exit + elif [ "$1" = "-W" ]; then + export ESV_NOLINEWRAP=1 + shift + elif [ "$1" = "-h" ] || [ "$isFlag" -eq 1 ]; then + show_help + else + break + fi +done + +cols=$(tput cols 2>/dev/null) +if [ $? -eq 0 ]; then + export ESV_MAX_WIDTH="$cols" +fi + +if [ $# -eq 0 ]; then + if [ ! -t 0 ]; then + show_help + fi + + # Interactive mode + while true; do + printf "esv> " + if ! read -r ref; then + break + fi + get_data esv.tsv | awk -v cmd=ref -v ref="$ref" "$(get_data esv.awk)" | ${PAGER} + done + exit 0 +fi + +get_data esv.tsv | awk -v cmd=ref -v ref="$*" "$(get_data esv.awk)" | ${PAGER} diff --git a/json-to-tsv.py b/json-to-tsv.py deleted file mode 100755 index 5065115..0000000 --- a/json-to-tsv.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python3 - -import json -import pandas -from flatten_json import flatten - -f = open('ESV.json') - -json_list = json.load(f) -key_list = ['book', 'chapter', 'verse', 'text'] -json_list = [{k:d[k] for k in key_list} for d in json_list] - -# Flatten and convert to a data frame -json_list_flattened = (flatten(d, '.') for d in json_list) -df = pandas.DataFrame(json_list_flattened) - -export_csv = df.to_csv('esv.tsv', sep='\t', encoding='utf-8', index=None, header=True)