diff --git a/README b/README index c92b8b7..1429a8d 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -This is esv, a program that displays Bible passages on the terminal. +This is esv 0.3.0, a program that displays Bible passages on the terminal. To build, first install the LDC compiler and libcurl. Configure the build environment, compile and optionally install: diff --git a/config.di b/config.di index 041e561..5a15fdc 100644 --- a/config.di +++ b/config.di @@ -2,7 +2,7 @@ module config; public: -enum esvVersion = "0.2.0-dev"; +enum esvVersion = "0.3.0"; enum apiKey = "abfb7456fa52ec4292c79e435890cfa3df14dc2b"; enum configPath = "~/.config/esv.conf"; diff --git a/esv.1 b/esv.1 index d8b58c1..30c5a51 100644 --- a/esv.1 +++ b/esv.1 @@ -1,4 +1,4 @@ -.Dd $Mdocdate: June 26 2024 $ +.Dd $Mdocdate: May 01 2025 $ .Dt ESV 1 .Os .Sh NAME @@ -15,8 +15,7 @@ .Sh DESCRIPTION .Nm displays Bible passages on your terminal. -It can also play recorded audio tracks of certain passages, -through integration with an MP3 player utility. +It can also play audio passages. .Pp See the section .Sx EXAMPLES @@ -27,29 +26,28 @@ Verses can be provided in the format of .Em chapter:verse , and .Em chapter:verse-verse . -If the name of your desired book has a space in it, e.g. +If the name of your desired book has spaces in it, e.g. .Dq "1 Corinthians" , -you can put a hyphen or underscore in the place of the space, -or you can just pass the full book name with the space in it -by surrounding the argument with quotes in your shell. +you can provide the book name with hyphens or underscores in place of +the spaces, or you can pass the original book name. Thus, both .Dq 1-Corinthians and -.Dq "1 Corinthians" -are valid book names. +.Dq 1_Corinthians +are also valid book names. .Pp By default, .Xr mpg123 1 -is used as the MP3 player. -However, this can be overridden; +is used as the player for audio passages. +This can be overridden however; see the .Sx ENVIRONMENT -section for more information on this. +section for more information. .Pp The options are as follows: .Bl -tag -width 123456 .It Fl a -Play a recorded audio track rather than showing a passage. +Play an audio passage instead of printing a text passage. .It Fl c Ar config Read the configuration from the path .Ar config . @@ -114,7 +112,8 @@ Where to read the configuration file, rather than using the default location (see section .Sx FILES ) . .It Ev ESV_PLAYER -The name of the MP3 player to use for playing audio passages. +The name of the audio player to use when playing audio passages. +The program specified must support playing MP3 audio. If this is not set, .Nm will look for @@ -133,22 +132,20 @@ Read John 1:29-31: .Pp Listen to a recorded audio track of Psalm 128: .Pp -.Dl esv -a Psalm 128 -.Pp -Search the Bible for the phrase -.Dq "in love" : -.Pp -.Dl esv -s 'in love' +.Dl esv -a Psalm 139 .Pp .Sh SEE ALSO +.Xr esvsearch 1 .Xr esv.conf 5 .Sh AUTHORS -.An Jeremy Baxter Aq Mt jeremy@baxters.nz +.An Jeremy Baxter Aq Mt jeremy@reformers.dev +.Pp +Part of the +.Sy esv +distribution found at +.Lk https://reformers.dev/esv .Sh BUGS Currently there are no known bugs in -.Nm ; -but if you think you've found a potential bug, -please report it to me using my email address above. -.Pp -Existing bugs and planned features can be found on the bug tracker: -.Lk https://todo.sr.ht/~jeremy/esv +.Nm . +If you think you've found a potential bug, +please report it to my email address above. diff --git a/esv.conf.5 b/esv.conf.5 index 34164c3..0612b8d 100644 --- a/esv.conf.5 +++ b/esv.conf.5 @@ -1,4 +1,4 @@ -.Dd $Mdocdate: March 23 2023 $ +.Dd $Mdocdate: May 01 2025 $ .Dt ESV.CONF 5 .Os .Sh NAME @@ -15,9 +15,12 @@ An example is listed below: .Dl [section] .Dl key = value .Pp -Comments can be used by putting a hashtag +A line beginning with a hashtag .Dq # -symbol at the beginning of a line. +will be considered a +.Dq comment +and will be ignored by +.Xr esv 1 . .Pp The available configuration options are as follows: .Bl -tag -width keyword diff --git a/esvapi.d b/esvapi.d index 78fa28c..aa3f05a 100644 --- a/esvapi.d +++ b/esvapi.d @@ -114,7 +114,7 @@ immutable string[] bibleBooks = [ ]; /++ All allowed API parameters (for text passages). +/ -immutable string[] ESVAPI_PARAMETERS = [ +immutable string[] esvapiParameters = [ "include-passage-references", "include-verse-numbers", "include-first-verse-numbers", @@ -178,6 +178,12 @@ verseValid(in char[] verse) assert(verseValid("15:12-17")); } +string +defaultSearchFmt(string reference, string content) pure +{ + return format!"\033[1m%s\033[0m\n %s\n"(reference, content.wrap(80)); +} + /++ + Structure containing the authentication key, API URL, + any parameters to use when making a request as well as the @@ -319,11 +325,12 @@ struct ESVApi } /++ - + Calls search() and formats the results nicely as plain text. + + Calls search() and formats the results nicely as plain text, + + unless a custom function is provided. +/ string - searchFormat(alias fmt = "\033[1m%s\033[0m\n %s\n") - (in string query, int lineLength = 0) /* 0 means default */ + searchFormat(in string query, + string function(string, string) fmt = &defaultSearchFmt) { char[] layout; JSONValue resp; @@ -334,15 +341,9 @@ struct ESVApi enforce!ESVException(resp["total"].integer != 0, "No results for search"); - lineLength = lineLength == 0 ? 80 : lineLength; - () @trusted { foreach (JSONValue item; resp["results"].array) { - layout ~= format!fmt( - item["reference"].str, - item["content"].str - .wrap(lineLength) - ); + layout ~= fmt(item["reference"].str, item["content"].str); } }(); diff --git a/esvsearch.1 b/esvsearch.1 index c8a1046..50bf4b0 100644 --- a/esvsearch.1 +++ b/esvsearch.1 @@ -1,4 +1,4 @@ -.Dd $Mdocdate: June 26 2024 $ +.Dd $Mdocdate: May 01 2025 $ .Dt ESVSEARCH 1 .Os .Sh NAME @@ -7,7 +7,7 @@ .Sh SYNOPSIS .Nm esvsearch .Bk -words -.Op Fl V +.Op Fl emV .Op Fl c Ar config .Ar query .Ek @@ -41,7 +41,16 @@ See the documentation on in .Xr esv 1 for more information. -.Sx ENVIRONMENT ) . +.It Fl e +Instead of showing loose matches for +.Ar query , +only show exact matches. +.It Fl m +Print matches in a machine-readable format, +where each result takes up just one line. +Any spaces in the book name are replaced with underscores +and a slash character separates the passage reference +from the passage content. .It Fl V Print the version number and exit. .El @@ -55,18 +64,14 @@ Search the Bible for verses containing .Xr esv 1 , .Xr esv.conf 5 .Sh AUTHORS -.An Jeremy Baxter Aq Mt jeremy@baxters.nz +.An Jeremy Baxter Aq Mt jeremy@reformers.dev +.Pp +Part of the +.Sy esv +distribution found at +.Lk https://reformers.dev/esv .Sh BUGS -.Nm -outputs search results in a human-readable manner, -which makes it nice for humans to read but difficult -for machines to parse and store. -.Nm -should support outputting results in a shell-readable format -and the JSON format. -.Pp +Currently there are no known bugs in +.Nm . If you think you've found a potential bug, -please report it to me using my email address above. -.Pp -Existing bugs and planned features can be found on the bug tracker: -.Lk https://todo.sr.ht/~jeremy/esv +please report it to my email address above. diff --git a/esvsearch.d b/esvsearch.d index e990d73..c070a9b 100644 --- a/esvsearch.d +++ b/esvsearch.d @@ -24,7 +24,9 @@ import std.file : FileException; import std.getopt : getopt, GetOptException; import std.path : baseName, expandTilde; import std.process : environment; +import std.regex : regex, matchAll, replaceFirst; import std.stdio : writeln, writefln; +import std.string : tr; import esvapi; import initial; @@ -36,8 +38,28 @@ import cf = config; string cFlag; /* config path */ bool eFlag; /* exact matches */ +bool mFlag; /* machine readable */ bool VFlag; /* show version */ +string +machineReadableFmt(string reference, string content) +{ + /* match the start of the reference against bibleBooks + * to identify what book it's from, so we can replace + * spaces in the book name with underscores :-) */ + foreach (string book; bibleBooks) { + auto match = reference.matchAll(regex("^(" ~ book ~ ") \\d")); + if (!match.empty) { + assert(match.captures[1] == book + && bookValid(match.captures[1])); + reference = reference.replaceFirst( + regex('^' ~ book), book.tr(" ", "_")); + } + } + + return reference ~ " / " ~ content ~ "\n"; +} + int main(string[] args) { @@ -59,6 +81,7 @@ main(string[] args) config.caseSensitive, "c", &cFlag, "e", &eFlag, + "m", &mFlag, "V", &VFlag, ); } catch (GetOptException e) { @@ -71,7 +94,7 @@ main(string[] args) } if (args.length < 2) { - stderr.writefln("usage: %s [-e] [-l length] query", + stderr.writefln("usage: %s [-emV] [-c config] query", baseName(args[0])); return 1; } @@ -110,7 +133,9 @@ main(string[] args) } try - writeln(esv.searchFormat(query)); + writeln(mFlag + ? esv.searchFormat(query, &machineReadableFmt) + : esv.searchFormat(query)); catch (ESVException) die("no results"); catch (CurlException e)