Compare commits

..

No commits in common. "1136fa01bbcf469f62b5b97ddd59def9aae587a3" and "0fe81de6c217417a5503c8f6b12eb704592f3d27" have entirely different histories.

7 changed files with 61 additions and 92 deletions

2
README
View file

@ -1,4 +1,4 @@
This is esv 0.3.0, a program that displays Bible passages on the terminal. This is esv, 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.3.0"; enum esvVersion = "0.2.0-dev";
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: May 01 2025 $ .Dd $Mdocdate: June 26 2024 $
.Dt ESV 1 .Dt ESV 1
.Os .Os
.Sh NAME .Sh NAME
@ -15,7 +15,8 @@
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
displays Bible passages on your terminal. displays Bible passages on your terminal.
It can also play audio passages. It can also play recorded audio tracks of certain passages,
through integration with an MP3 player utility.
.Pp .Pp
See the section See the section
.Sx EXAMPLES .Sx EXAMPLES
@ -26,28 +27,29 @@ 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 spaces in it, e.g. If the name of your desired book has a space in it, e.g.
.Dq "1 Corinthians" , .Dq "1 Corinthians" ,
you can provide the book name with hyphens or underscores in place of you can put a hyphen or underscore in the place of the space,
the spaces, or you can pass the original book name. or you can just pass the full book name with the space in it
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 also valid book names. are valid book names.
.Pp .Pp
By default, By default,
.Xr mpg123 1 .Xr mpg123 1
is used as the player for audio passages. is used as the MP3 player.
This can be overridden however; However, this can be overridden;
see the see the
.Sx ENVIRONMENT .Sx ENVIRONMENT
section for more information. section for more information on this.
.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 an audio passage instead of printing a text passage. Play a recorded audio track rather than showing a 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 .
@ -112,8 +114,7 @@ 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 audio player to use when playing audio passages. The name of the MP3 player to use for 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
@ -132,20 +133,22 @@ 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 139 .Dl esv -a Psalm 128
.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@reformers.dev .An Jeremy Baxter Aq Mt jeremy@baxters.nz
.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 ;
If you think you've found a potential bug, but if you think you've found a potential bug,
please report it to my email address above. 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

View file

@ -1,4 +1,4 @@
.Dd $Mdocdate: May 01 2025 $ .Dd $Mdocdate: March 23 2023 $
.Dt ESV.CONF 5 .Dt ESV.CONF 5
.Os .Os
.Sh NAME .Sh NAME
@ -15,12 +15,9 @@ An example is listed below:
.Dl [section] .Dl [section]
.Dl key = value .Dl key = value
.Pp .Pp
A line beginning with a hashtag Comments can be used by putting a hashtag
.Dq # .Dq #
will be considered a symbol at the beginning of a line.
.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[] esvapiParameters = [ immutable string[] ESVAPI_PARAMETERS = [
"include-passage-references", "include-passage-references",
"include-verse-numbers", "include-verse-numbers",
"include-first-verse-numbers", "include-first-verse-numbers",
@ -178,12 +178,6 @@ 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
@ -325,12 +319,11 @@ 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(in string query, searchFormat(alias fmt = "\033[1m%s\033[0m\n %s\n")
string function(string, string) fmt = &defaultSearchFmt) (in string query, int lineLength = 0) /* 0 means default */
{ {
char[] layout; char[] layout;
JSONValue resp; JSONValue resp;
@ -341,9 +334,15 @@ 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 ~= fmt(item["reference"].str, item["content"].str); layout ~= format!fmt(
item["reference"].str,
item["content"].str
.wrap(lineLength)
);
} }
}(); }();

View file

@ -1,4 +1,4 @@
.Dd $Mdocdate: May 01 2025 $ .Dd $Mdocdate: June 26 2024 $
.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 emV .Op Fl V
.Op Fl c Ar config .Op Fl c Ar config
.Ar query .Ar query
.Ek .Ek
@ -41,16 +41,7 @@ See the documentation on
in in
.Xr esv 1 .Xr esv 1
for more information. for more information.
.It Fl e .Sx ENVIRONMENT ) .
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
@ -64,14 +55,18 @@ 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@reformers.dev .An Jeremy Baxter Aq Mt jeremy@baxters.nz
.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 .Nm
.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
If you think you've found a potential bug, If you think you've found a potential bug,
please report it to my email address above. 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

View file

@ -24,9 +24,7 @@ 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;
@ -38,28 +36,8 @@ 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)
{ {
@ -81,7 +59,6 @@ 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) {
@ -94,7 +71,7 @@ main(string[] args)
} }
if (args.length < 2) { if (args.length < 2) {
stderr.writefln("usage: %s [-emV] [-c config] query", stderr.writefln("usage: %s [-e] [-l length] query",
baseName(args[0])); baseName(args[0]));
return 1; return 1;
} }
@ -133,9 +110,7 @@ main(string[] args)
} }
try try
writeln(mFlag writeln(esv.searchFormat(query));
? esv.searchFormat(query, &machineReadableFmt)
: esv.searchFormat(query));
catch (ESVException) catch (ESVException)
die("no results"); die("no results");
catch (CurlException e) catch (CurlException e)