Compare commits

...

10 commits

7 changed files with 92 additions and 61 deletions

2
README
View file

@ -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. To build, first install the LDC compiler and libcurl.
Configure the build environment, compile and optionally install: Configure the build environment, compile and optionally install:

View file

@ -2,7 +2,7 @@ module config;
public: public:
enum esvVersion = "0.2.0-dev"; enum esvVersion = "0.3.0";
enum apiKey = "abfb7456fa52ec4292c79e435890cfa3df14dc2b"; enum apiKey = "abfb7456fa52ec4292c79e435890cfa3df14dc2b";
enum configPath = "~/.config/esv.conf"; enum configPath = "~/.config/esv.conf";

51
esv.1
View file

@ -1,4 +1,4 @@
.Dd $Mdocdate: June 26 2024 $ .Dd $Mdocdate: May 01 2025 $
.Dt ESV 1 .Dt ESV 1
.Os .Os
.Sh NAME .Sh NAME
@ -15,8 +15,7 @@
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
displays Bible passages on your terminal. displays Bible passages on your terminal.
It can also play recorded audio tracks of certain passages, It can also play audio passages.
through integration with an MP3 player utility.
.Pp .Pp
See the section See the section
.Sx EXAMPLES .Sx EXAMPLES
@ -27,29 +26,28 @@ Verses can be provided in the format of
.Em chapter:verse , .Em chapter:verse ,
and and
.Em chapter:verse-verse . .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" , .Dq "1 Corinthians" ,
you can put a hyphen or underscore in the place of the space, you can provide the book name with hyphens or underscores in place of
or you can just pass the full book name with the space in it the spaces, or you can pass the original book name.
by surrounding the argument with quotes in your shell.
Thus, both Thus, both
.Dq 1-Corinthians .Dq 1-Corinthians
and and
.Dq "1 Corinthians" .Dq 1_Corinthians
are valid book names. are also valid book names.
.Pp .Pp
By default, By default,
.Xr mpg123 1 .Xr mpg123 1
is used as the MP3 player. is used as the player for audio passages.
However, this can be overridden; This can be overridden however;
see the see the
.Sx ENVIRONMENT .Sx ENVIRONMENT
section for more information on this. section for more information.
.Pp .Pp
The options are as follows: The options are as follows:
.Bl -tag -width 123456 .Bl -tag -width 123456
.It Fl a .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 .It Fl c Ar config
Read the configuration from the path Read the configuration from the path
.Ar config . .Ar config .
@ -114,7 +112,8 @@ Where to read the configuration file,
rather than using the default location (see section rather than using the default location (see section
.Sx FILES ) . .Sx FILES ) .
.It Ev ESV_PLAYER .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, If this is not set,
.Nm .Nm
will look for will look for
@ -133,22 +132,20 @@ Read John 1:29-31:
.Pp .Pp
Listen to a recorded audio track of Psalm 128: Listen to a recorded audio track of Psalm 128:
.Pp .Pp
.Dl esv -a Psalm 128 .Dl esv -a Psalm 139
.Pp
Search the Bible for the phrase
.Dq "in love" :
.Pp
.Dl esv -s 'in love'
.Pp .Pp
.Sh SEE ALSO .Sh SEE ALSO
.Xr esvsearch 1
.Xr esv.conf 5 .Xr esv.conf 5
.Sh AUTHORS .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 .Sh BUGS
Currently there are no known bugs in Currently there are no known bugs in
.Nm ; .Nm .
but if you think you've found a potential bug, If you think you've found a potential bug,
please report it to me using my email address above. please report it to my email address above.
.Pp
Existing bugs and planned features can be found on the bug tracker:
.Lk https://todo.sr.ht/~jeremy/esv

View file

@ -1,4 +1,4 @@
.Dd $Mdocdate: March 23 2023 $ .Dd $Mdocdate: May 01 2025 $
.Dt ESV.CONF 5 .Dt ESV.CONF 5
.Os .Os
.Sh NAME .Sh NAME
@ -15,9 +15,12 @@ An example is listed below:
.Dl [section] .Dl [section]
.Dl key = value .Dl key = value
.Pp .Pp
Comments can be used by putting a hashtag A line beginning with a hashtag
.Dq # .Dq #
symbol at the beginning of a line. will be considered a
.Dq comment
and will be ignored by
.Xr esv 1 .
.Pp .Pp
The available configuration options are as follows: The available configuration options are as follows:
.Bl -tag -width keyword .Bl -tag -width keyword

View file

@ -114,7 +114,7 @@ immutable string[] bibleBooks = [
]; ];
/++ All allowed API parameters (for text passages). +/ /++ All allowed API parameters (for text passages). +/
immutable string[] ESVAPI_PARAMETERS = [ immutable string[] esvapiParameters = [
"include-passage-references", "include-passage-references",
"include-verse-numbers", "include-verse-numbers",
"include-first-verse-numbers", "include-first-verse-numbers",
@ -178,6 +178,12 @@ verseValid(in char[] verse)
assert(verseValid("15:12-17")); 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, + Structure containing the authentication key, API URL,
+ any parameters to use when making a request as well as the + 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 string
searchFormat(alias fmt = "\033[1m%s\033[0m\n %s\n") searchFormat(in string query,
(in string query, int lineLength = 0) /* 0 means default */ string function(string, string) fmt = &defaultSearchFmt)
{ {
char[] layout; char[] layout;
JSONValue resp; JSONValue resp;
@ -334,15 +341,9 @@ struct ESVApi
enforce!ESVException(resp["total"].integer != 0, enforce!ESVException(resp["total"].integer != 0,
"No results for search"); "No results for search");
lineLength = lineLength == 0 ? 80 : lineLength;
() @trusted { () @trusted {
foreach (JSONValue item; resp["results"].array) { foreach (JSONValue item; resp["results"].array) {
layout ~= format!fmt( layout ~= fmt(item["reference"].str, item["content"].str);
item["reference"].str,
item["content"].str
.wrap(lineLength)
);
} }
}(); }();

View file

@ -1,4 +1,4 @@
.Dd $Mdocdate: June 26 2024 $ .Dd $Mdocdate: May 01 2025 $
.Dt ESVSEARCH 1 .Dt ESVSEARCH 1
.Os .Os
.Sh NAME .Sh NAME
@ -7,7 +7,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm esvsearch .Nm esvsearch
.Bk -words .Bk -words
.Op Fl V .Op Fl emV
.Op Fl c Ar config .Op Fl c Ar config
.Ar query .Ar query
.Ek .Ek
@ -41,7 +41,16 @@ See the documentation on
in in
.Xr esv 1 .Xr esv 1
for more information. 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 .It Fl V
Print the version number and exit. Print the version number and exit.
.El .El
@ -55,18 +64,14 @@ Search the Bible for verses containing
.Xr esv 1 , .Xr esv 1 ,
.Xr esv.conf 5 .Xr esv.conf 5
.Sh AUTHORS .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 .Sh BUGS
.Nm Currently there are no known bugs in
outputs search results in a human-readable manner, .Nm .
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
If you think you've found a potential bug, If you think you've found a potential bug,
please report it to me using my email address above. please report it to my email address above.
.Pp
Existing bugs and planned features can be found on the bug tracker:
.Lk https://todo.sr.ht/~jeremy/esv

View file

@ -24,7 +24,9 @@ import std.file : FileException;
import std.getopt : getopt, GetOptException; import std.getopt : getopt, GetOptException;
import std.path : baseName, expandTilde; import std.path : baseName, expandTilde;
import std.process : environment; import std.process : environment;
import std.regex : regex, matchAll, replaceFirst;
import std.stdio : writeln, writefln; import std.stdio : writeln, writefln;
import std.string : tr;
import esvapi; import esvapi;
import initial; import initial;
@ -36,8 +38,28 @@ import cf = config;
string cFlag; /* config path */ string cFlag; /* config path */
bool eFlag; /* exact matches */ bool eFlag; /* exact matches */
bool mFlag; /* machine readable */
bool VFlag; /* show version */ 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 int
main(string[] args) main(string[] args)
{ {
@ -59,6 +81,7 @@ main(string[] args)
config.caseSensitive, config.caseSensitive,
"c", &cFlag, "c", &cFlag,
"e", &eFlag, "e", &eFlag,
"m", &mFlag,
"V", &VFlag, "V", &VFlag,
); );
} catch (GetOptException e) { } catch (GetOptException e) {
@ -71,7 +94,7 @@ main(string[] args)
} }
if (args.length < 2) { if (args.length < 2) {
stderr.writefln("usage: %s [-e] [-l length] query", stderr.writefln("usage: %s [-emV] [-c config] query",
baseName(args[0])); baseName(args[0]));
return 1; return 1;
} }
@ -110,7 +133,9 @@ main(string[] args)
} }
try try
writeln(esv.searchFormat(query)); writeln(mFlag
? esv.searchFormat(query, &machineReadableFmt)
: esv.searchFormat(query));
catch (ESVException) catch (ESVException)
die("no results"); die("no results");
catch (CurlException e) catch (CurlException e)