Compare commits

...

2 Commits

Author SHA1 Message Date
Paul Mosier bdd140b94a Search & config file bugfixes. Doc updates. 2022-12-01 17:56:00 -05:00
Paul Mosier 7df22c80a3 Allow for multiple pages of panes. 2022-05-26 20:58:32 -04:00
10 changed files with 414 additions and 131 deletions

View File

@ -1,5 +1,5 @@
PREFIX = /usr/local
CC = clang
CC = g++
CCFLAGS = -Wall $(shell pkg-config --cflags sword)
TARGET = scriptura
INCLUDES = -I/usr/include/sword -I/usr/include/ncursesw

View File

@ -5,8 +5,8 @@ This program was written to scratch a personal itch. I do a lot of daily comput
## Dependencies
* clang
* libsword and its development libraries (often available in most distributions' standard repos)
* a C++ compiler and standard libraries installed - the Makefile is currently set for g++ but you could switch it to clang++ if preferred
* libsword and its development libraries (also available in most distributions' standard repos)
* ncurses and its development libraries (any modern Linux version should work)
* doxygen (optional, if you're a documentation nerd)
@ -21,7 +21,7 @@ To install scriptura (into /usr/local by default):
>
> sudo make install
On first run, scriptura assumes that a King James module is intalled and available. Many modules from CrossWire are [available here](https://www.crosswire.org/ftpmirror/pub/sword/packages/rawzip/) and other frontends have their own repos. To install them from the command line:
On first run, scriptura assumes that the King James with Apocrypha module is intalled and available. Many modules from CrossWire are [available here](https://www.crosswire.org/ftpmirror/pub/sword/packages/rawzip/) and other frontends have their own repos. To install them from the command line:
> mkdir -p $HOME/.sword/
>
> cd $HOME/.sword/
@ -30,7 +30,7 @@ On first run, scriptura assumes that a King James module is intalled and availab
>
> unzip KJVA.zip
A configuration file will be created at $HOME/.config/scriptura.ini. You can see the sample config file in the codebase for available options.
A configuration file will be created at $HOME/.config/scriptura.ini. You can see the sample config file in the codebase for available options. Just about everything you can modify from inside the program, with the sole exception of the 'panels' entry under [layout]. This determines if you want the two panes to stack horizontal ("h") or vertical ("v") and must be changed manually.
When the software is running, the '?' key will give you the list of commands available. Open any module you have installed and you can go to or search any text.
@ -48,7 +48,6 @@ Other means of contact [can be found here](https://keyoxide.org/hkp/paladin1%40s
This project is basically a one-man operation. If you'd like to show your support financially, you can contribute via:
- _Paypal - paladin1_ at _sdf.org_
- _BTC - bc1q9dfau346z38jth35gkaxacd3fljvfgw6cqcyyv_
## Disclaimer

View File

@ -35,7 +35,7 @@ char CLITEXT[] =
char HELPTEXT[] =
"Scriptura\n\n"
"Key bindings:\n"
"Main key bindings:\n"
" ? this help message\n"
" q quit\n\n"
" ESC close floating window\n"
@ -46,7 +46,11 @@ char HELPTEXT[] =
" arrow up/dn scroll up/down one line\n"
" page up/dn scroll up/down one page\n"
"\n"
"Formatting changes\n"
"Pages:\n"
" 0-4 go to the numbered page\n"
" p create new page\n"
" d delete page\n"
"Formatting changes:\n"
" (takes effect at next search/go to, and depends on loaded module)\n"
" f toggle footnotes\n"
" n toggle non-textual words\n"
@ -56,6 +60,9 @@ char HELPTEXT[] =
"\n(Press any key to return to the main screen)\n"
"\0";
int DEFSEARCH = 1;
int DEFKEY = 0;
void wrapup(int exitval, const char* str) {
endwin();
if (str != NULL) perror(str);
@ -97,10 +104,7 @@ int parseConf(sword::SWBuf buf) {
starray stappend(starray arr, const char* newstr) {
arr.length++;
if (arr.length == 1) {
free(arr.strings); // needed due to stinit()'s malloc(0)
arr.strings = (const char**) malloc(sizeof(char*));
} else {
if (arr.length > 1) {
arr.strings = (const char**)
realloc(arr.strings, arr.length * sizeof(char*));
}
@ -113,7 +117,7 @@ starray stappend(starray arr, const char* newstr) {
starray stinit(starray arr) {
arr.length = 0;
arr.strings = (const char**) malloc(0);
arr.strings = (const char**) malloc(sizeof(char*));
return arr;
}

15
free.h
View File

@ -23,6 +23,12 @@
#include <swconfig.h>
#include <swbuf.h>
// preprocessor directives - for some compiler-constant expressions
#define PAGELIMIT 5 // the maximum number of pages allowed
#define NUMPANES 2 // the max number of panes allowed -- this value
// as is in other places of the code
//! Structure to make managing arrays easier. Who doesn't like arrays?
typedef struct {
int length; //!< number of elements
@ -34,7 +40,8 @@ typedef struct {
* One is stored by each pane. */
typedef struct {
const char* modname; //!< name of module
const char* searchkey; //!< our search key for the module
const char* searchkey; /*!< search key for module - if NULL or empty, the
* struct is considered empty */
int keytype; //!< 0 - versekey, 1 - treekey, 2 - direct
int searchtype; //!< type of search to be performed, if any
const char* scope; //!< scope of search, if any
@ -46,6 +53,12 @@ extern char HELPTEXT[];
//! String giving the informative text on the command line, for '-h'
extern char CLITEXT[];
//! Value of default searchtype for lookups keyed to verse
extern int DEFSEARCH;
//! Value of default keytype for lookups
extern int DEFKEY;
//! Global copy of the program's configuration file settings.
extern sword::SWConfig config;

View File

@ -27,25 +27,23 @@
#include "pane.h"
// constructor
pane::pane(int starty, int startx, int lines, int cols, const char* title) {
pane::pane(int starty, int startx, int lines, int cols, const char* title,
modkey defmod) {
buflocx = buflocy = 0;
hasFocus = false;
rawtext = NULL;
// set some default search parameters
mod.modname = config["defaults"]["module"];
mod.searchkey = config["defaults"]["searchkey"];
mod.keytype = 0;
mod.searchtype = 0;
mod.scope = config["defaults"]["scope"];
setTitle(title);
// set up the window -- resize will give us some initializing
setTitle(title);
pad = NULL;
resize(starty, startx, lines, cols);
redraw(true);
// forms/menus send in a null searchkey
if (defmod.searchkey != NULL) {
setModkey(defmod, title);
}
}
// handle pane resizing
@ -113,7 +111,7 @@ void pane::renderText() {
* char so I think it has to be done this way */
for (int i = 0; i < length; i++) {
int converted = mbstowcs(text, rawtext, 1);
if (converted == -1) strncpy(&(rawtext[i-1]), "'", 1);
if (converted == -1) strncpy(&(rawtext[i-1]), "'", 2);
}
mbstowcs(text, rawtext, length - 1);
@ -437,8 +435,8 @@ int pane::loadMenu(starray opts) {
int pane::printInstructions(int y, const char* inst) {
// NOTE -- starting indentation is hardcoded at two characters in
int strctr = 0;
int line = width - 3;
long unsigned int strctr = 0;
long unsigned int line = width - 3;
while (strlen(&inst[strctr]) > line) {
// set write length to be up to the last space, for word wrapping
while ((inst[line] != ' ') && (line > 0)) line--;
@ -574,7 +572,7 @@ void pane::formClean(FORM* form, FIELD** fields, int numfields) {
}
void pane::setModule(const char* newtitle, const char* newmod,
int keytype) {
int keytype) {
mod.modname = newmod;
mod.keytype = keytype;
setTitle(newtitle);
@ -584,7 +582,7 @@ void pane::setModule(const char* newtitle, const char* newmod,
void pane::setKey(const char* newkey) {
mod.searchkey = newkey;
setSearch(0, "Gen 1:1 - Rev 22:21");
setSearch(DEFSEARCH, "Gen 1:1 - Rev 22:21");
}
void pane::setSearch(int type, const char* scope) {
@ -592,6 +590,8 @@ void pane::setSearch(int type, const char* scope) {
mod.scope = scope;
}
modkey pane::getModkey() {
return mod;
void pane::setModkey(modkey newmod, const char* newtitle) {
setModule(newtitle, newmod.modname, newmod.keytype);
setKey(newmod.searchkey);
setSearch(newmod.searchtype, newmod.scope);
}

11
pane.h
View File

@ -74,7 +74,8 @@ class pane {
int startx, //!< the pane's upper left Y coord
int lines, //!< the pane's number of lines
int cols, //!< the pane's number of columns
const char* title //!< starting titlebar text
const char* title, //!< starting titlebar text
modkey defmod //!< starting modkey, or NULL if not applicable
);
//! Resize the window & pad, in the case of terminal resizing.
@ -160,9 +161,11 @@ class pane {
const char* scope //!< scope to search within, in key format
);
/*! Gets the modkey associated with this pane.
* \returns modkey associated with this pane */
modkey getModkey();
/*! Loads an entirely new modkey into the pane. Will call associated
* redrawing functions. */
void setModkey(modkey newmod, //!< new modkey to load in
const char* newtitle //!< new pane title to use
);
};

View File

@ -182,6 +182,11 @@ const char* scabbard::getModDescription(int modt, int mod) {
return (modules[modt].modlist)[mod]->getDescription();
}
const char* scabbard::getModDescription(const char* modname) {
sword::SWModule *text = swrd.getModule(modname);
return text->getDescription();
}
int scabbard::getKeyType(int modt) {
return modules[modt].keytype;
}
@ -214,13 +219,13 @@ const char* scabbard::search(modkey mod) {
sword::SWKey *clone =
(key->parseVerseList(mod.scope, mod.scope, true)).clone();
sword::ListKey lk =
text->search(mod.searchkey, mod.searchtype, 0, clone);
text->search(mod.searchkey, mod.searchtype, 0, clone);
const char* retval = parseVerses(text, lk);
delete(key);
delete(clone);
return retval;
} else return directSearch(text, mod);
}
return directSearch(text, mod);
}
/* really old code in case we need to pull output from diatheke

View File

@ -41,7 +41,8 @@
#include "free.h"
//! Structure for associating a Sword module type to a list of modules.
/*! Structure for associating a Sword module type (Bibles,
* commentaries, etc) to a list of modules. */
typedef struct {
char label[25]; //!< the module type
int keytype; //!< 0 - versekey, 1 - treekey, 2 - direct/alpha
@ -106,12 +107,17 @@ class scabbard {
int mod //!< from getModDescriptions()
);
/*! Get the full text name for a module.
/*! Get the full text name for a module identified by menu indices.
* \returns the module description */
const char* getModDescription(int modt, //!< from getModClassifications()
int mod //!< from getModDescriptions()
);
/*! Get the full text name for a module identified by key name.
* \returns the module description */
const char* getModDescription(const char* modname //!< module internal name
);
/*! Determine how a module is keyed/indexed.
* \returns the proper keytype; see the keytype field for modkey */
int getKeyType(int modt //!< return value from getModClassifications()

View File

@ -31,10 +31,12 @@
#include "pane.h"
#include "scabbard.h"
/* --[ ASSISTS / TOP NAMESPACE ]-- */
/* --[ ASSISTS / GLOBALS ]-- */
// quick array for page names
char* pages[PAGELIMIT][NUMPANES];
int NUMPANES;
int currentpage, totalpages;
int halfcols, halflines;
int floatx, floaty, floatheight, floatwidth;
int startx1, starty1, startx2, starty2;
@ -42,8 +44,30 @@ int panelength, panewidth;
sword::SWConfig config;
//! Write background text in stdscr
void foundation() {
// wipe out old page info line
for (int i = 0; i < COLS - 20; i++) mvaddch(LINES - 1, i, ' ');
// place page info & background text
int placement = 0;
for (int i = 0; i < totalpages; i++) {
// NOTE -- we are assuming the length of a searchkey & size of NUMPANES
if (i == currentpage) attron(A_STANDOUT);
mvprintw(LINES - 1, placement, "[%d]:%s/%s", i,
config[pages[i][0]]["searchkey"].c_str(),
config[pages[i][1]]["searchkey"].c_str());
attroff(A_STANDOUT);
placement += 26;
}
mvprintw(LINES - 1 , COLS - 20, "%s", "? - help q - quit");
refresh();
}
//! Refresh every portion of a list of panes we are given.
void wipeit(pane* panes) {
clear();
foundation();
for (int i = 0; i < NUMPANES; i++) panes[i].redraw(true);
}
@ -51,28 +75,50 @@ void wipeit(pane* panes) {
starray showForm(const char* title, starray inputs, const char* secondinst,
int floaty, int floatx, int floatheight, int floatwidth) {
// pull up the floating form
pane form = {floaty, floatx, floatheight, floatwidth, title};
modkey defmod;
defmod.searchkey = NULL;
pane form = {floaty, floatx, floatheight, floatwidth, title, defmod};
starray ret = form.loadForm(inputs, secondinst);
// sanitize input? -- if (ret.length != 0)
return ret;
}
//! Construct a modkey from the currently selected page & pane
modkey getModkey(int infocus) {
modkey mod;
mod.modname = config[pages[currentpage][infocus]]["module"];
mod.searchkey = config[pages[currentpage][infocus]]["searchkey"];
mod.searchtype = parseConf(config[pages[currentpage][infocus]]["searchtype"]);
mod.keytype = parseConf(config[pages[currentpage][infocus]]["keytype"]);
mod.scope = config[pages[currentpage][infocus]]["scope"];
return mod;
}
//! Refresh to the current page.
void loadPage(pane* panes, scabbard* scab) {
for (int i = 0; i < NUMPANES; i++) {
modkey mod = getModkey(i);
panes[i].setModkey(mod, scab->getModDescription(mod.modname));
// searchtype will tell us whether this is a search or a straight lookup
if (mod.searchtype == 1) {
panes[i].loadText(scab->getSpan(mod));
} else {
panes[i].loadText(scab->search(mod));
}
}
wipeit(panes);
}
//! Save the config array -- we abstract this out in case this changes.
void saveit(char* configfile) {
/* This is clumsy but we have to use this particular constructor for
* config() so we can save to disk. The global config object uses a
* different constructor. */
sword::SWConfig newconfig(configfile);
newconfig.augment(config);
newconfig.save();
void saveit() {
config.save();
}
//! Set various standard screen landmarks.
void landmarks() {
// place background text
mvprintw(LINES - 1 , COLS - 20, "%s", "? - help q - quit");
refresh();
foundation();
// split up the screen
halfcols = COLS / 2;
@ -108,7 +154,7 @@ void doresize(pane* p) {
// reset standard screen landmarks
landmarks();
// reset and refresh main panes
// reset and refresh main panes -- assumes NUMPANES
p[0].resize(starty1, startx1, panelength, panewidth);
p[1].resize(starty2, startx2, panelength, panewidth);
wipeit(p);
@ -153,28 +199,33 @@ int main(int argc, char** argv) {
printf("Please ensure this directory exists and is writable.\n");
return -1;
}
// set default module and other fields to avoid crashing
fprintf(cnf, "[defaults]\n");
fprintf(cnf, "scope=Gen 1:1 - Rev 22:21\n");
fprintf(cnf, "searchkey=2 Tim 1:7\n");
fprintf(cnf, "module=KJV\n");
fclose(cnf);
printf("done.\n");
}
}
sword::SWConfig tempconfig(configfile);
config.augment(tempconfig);
config.filename = configfile;
config.load();
// ensure some needed config settings are in place
if (! strcmp(config["layout"]["panels"], ""))
config["layout"]["panels"] = "v";
if (! strcmp(config["defaults"]["scope"], ""))
config["defaults"]["scope"] = "Gen 1:1 - Rev 22:21";
if (! strcmp(config["defaults"]["searchkey"], ""))
config["defaults"]["searchkey"] = "2 Tim 1:;7";
config["defaults"]["searchkey"] = "2 Tim 1:7";
if (! strcmp(config["defaults"]["module"], ""))
config["defaults"]["module"] = "KJV";
saveit(configfile);
if (! strcmp(config["defaults"]["searchtype"], "")) {
char* temp;
asprintf(&temp, "%d", DEFSEARCH);
config["defaults"]["searchtype"] = temp;
free(temp);
}
if (! strcmp(config["page0-0"]["searchkey"], ""))
config["page0-0"]["searchkey"] = "2 Tim 1:7";
if (! strcmp(config["page0-1"]["searchkey"], ""))
config["page0-1"]["searchkey"] = "2 Tim 1:7";
saveit();
// NOTE -- anything after this point must use our defined exit wrapup()
@ -203,33 +254,71 @@ int main(int argc, char** argv) {
init_pair(1, COLOR_RED, COLOR_BLACK);
}
// two main panes
NUMPANES = 2;
landmarks();
pane* p = (pane*) malloc(sizeof(pane) * NUMPANES);
const char* title = "Window";
if (! p) wrapup(1, "Error allocating memory for panes.\n");
p[0] = { starty1, startx1, panelength, panewidth, title };
p[1] = { starty2, startx2, panelength, panewidth, title };
// cycle through config file for any saved pages & sanitize
totalpages = 0;
int linking = 1;
for (int i = 0; i < PAGELIMIT; i++) {
for (int j = 0; j < NUMPANES; j++) {
/* sanitize input here --
* It's our own config but the user can edit it. If a searchkey doesn't
* exist then we need to stop to ensure the list is linked properly.
* If it does, accept whatever the searchkey is, even if the user
* modified it. For other settings, verify they are in the file, or take
* the defaults & update the config. When we get to the first blank
* searchkey for the start of a page, no longer take any further input. */
asprintf(&(pages[i][j]), "page%d%s%d", i, "-", j);
pane* focustab;
focustab = &(p[0]);
focustab->toggleFocus();
/* with no searchkey, if this is the first pane then stop linking here;
* otherwise we can get by with setting the searchkey to the default */
if (! strcmp(config[pages[i][j]]["searchkey"], "")) {
(j == 0 ? linking = 0 :
config[pages[i][j]]["searchkey"] = config["defaults"]["searchkey"]);
}
if (linking && (! strcmp(config[pages[i][j]]["module"], "")))
config[pages[i][j]]["module"] = config["defaults"]["module"];
if (linking && (! strcmp(config[pages[i][j]]["keytype"], "")))
config[pages[i][j]]["keytype"] = config["defaults"]["keytype"];
if (linking && (! strcmp(config[pages[i][j]]["searchtype"], "")))
config[pages[i][j]]["searchtype"] = config["defaults"]["searchtype"];
if (linking && (! strcmp(config[pages[i][j]]["scope"], "")))
config[pages[i][j]]["scope"] = config["defaults"]["scope"];
// we have a page
if (linking && (j == 0)) totalpages++;
}
}
// set index for page list
currentpage = 0;
/* load up a scabbard & set blank starting data - scabbard args are
* sanitized in the constructor */
scabbard scab = {};
char blank[] = "Open a text to use this window.\0";
// configure panes
landmarks();
pane* p = (pane*) malloc(sizeof(pane) * NUMPANES);
if (! p) wrapup(1, "Error allocating memory for panes.\n");
for (int i = 0; i < NUMPANES; i++) {
if (config["defaults"]["module"] && config["defaults"]["searchkey"]) {
// this isn't technically the title, but it's what we have now
p[i].setTitle(config["defaults"]["module"]);
p[i].loadText(scab.getSpan(p[i].getModkey()));
} else {
p[i].loadText(blank);
}
modkey mod = getModkey(i);
// NOTE -- assumes NUMPANES, for future work
int starty, startx;
starty = (i == 0 ? starty1 : starty2);
startx = (i == 0 ? startx1 : startx2);
p[i] = { starty, startx, panelength, panewidth,
scab.getModDescription(mod.modname), mod };
}
wipeit(p);
pane* focustab;
int infocus = 0;
focustab = &(p[infocus]);
focustab->toggleFocus();
loadPage(p, &scab);
// loop for input
int ch;
@ -239,7 +328,8 @@ int main(int argc, char** argv) {
case '\t': {
// switch pane focus
focustab->toggleFocus();
focustab = (focustab == &(p[0]) ? &(p[1]) : &(p[0]));
infocus = (infocus + 1) % NUMPANES;
focustab = &(p[infocus]);
focustab->toggleFocus();
break; }
@ -263,12 +353,64 @@ int main(int argc, char** argv) {
doresize(p);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
// go to page
if (totalpages <= (int) ch - 48) break;
currentpage = (int) ch - 48;
loadPage(p, &scab);
break;
case '<': {
// previous page
currentpage = (currentpage == 0 ? totalpages - 1 : currentpage - 1);
loadPage(p, &scab);
break; }
case '>': {
// next page
currentpage = (currentpage + 1) % totalpages;
loadPage(p, &scab);
break; }
case 'd': {
// delete page
if (totalpages == 1) break;
for (int i = currentpage; i < totalpages; i++) {
for (int j = 0; j < NUMPANES; j++) {
if (i == totalpages - 1) {
// delete the last in list
config[pages[i][j]]["searchkey"] = NULL;
} else {
// shift all later pages down to fill the gap
config[pages[i][j]]["module"] = config[pages[i+1][j]]["module"];
config[pages[i][j]]["searchkey"] =
config[pages[i+1][j]]["searchkey"];
config[pages[i][j]]["searchtype"] =
config[pages[i+1][j]]["searchtype"];
config[pages[i][j]]["keytype"] = config[pages[i+1][j]]["keytype"];
config[pages[i][j]]["scope"] = config[pages[i+1][j]]["scope"];
}
}
}
totalpages--;
// reset page index if needed to stay in bounds
if (currentpage == totalpages) currentpage--;
loadPage(p, &scab);
saveit();
break; }
case 'f': {
// toggle footnotes
int footnotes = ! parseConf(config["markup"]["footnotes"]);
config["markup"]["footnotes"] = footnotes + '0';
wipeit(p);
saveit(configfile);
saveit();
break; }
case 'g': {
@ -290,8 +432,10 @@ int main(int argc, char** argv) {
if ((ret.length != 0) && (strlen((ret.strings)[0]) > 0)) {
// user entered something that's not a blank string
config[pages[currentpage][infocus]]["searchkey"] = (ret.strings)[0];
focustab->setKey((ret.strings)[0]);
focustab->loadText(scab.getSpan(focustab->getModkey()));
focustab->loadText(scab.getSpan(getModkey(infocus)));
saveit();
}
wipeit(p);
break; }
@ -300,15 +444,16 @@ int main(int argc, char** argv) {
// toggle non-textual words
int textual = ! parseConf(config["markup"]["nontextual"]);
config["markup"]["nontextual"] = textual + '0';
wipeit(p);
saveit(configfile);
saveit();
break; }
case 'o': {
// load a module into the current pane
const char* typetitle = "Choose a module type";
modkey defmod;
defmod.searchkey = NULL;
pane menupane = {floaty, floatx, floatheight, floatwidth,
typetitle };
typetitle, defmod };
starray mc = scab.getModClassifications();
int modclass = menupane.loadMenu(mc);
if (modclass == -1) {
@ -320,7 +465,7 @@ int main(int argc, char** argv) {
}
const char* modtitle = "Choose a module";
menupane = {floaty, floatx, floatheight, floatwidth, modtitle};
menupane = {floaty, floatx, floatheight, floatwidth, modtitle, defmod};
starray mds = scab.getModDescriptions(modclass);
int mod = menupane.loadMenu(mds);
if (mod == -1) {
@ -331,19 +476,50 @@ int main(int argc, char** argv) {
break;
}
config[pages[currentpage][infocus]]["module"] =
scab.getModName(modclass, mod);
char* temp;
asprintf(&temp, "%d", scab.getKeyType(modclass));
config[pages[currentpage][infocus]]["keytype"] = temp;
free(temp);
focustab->setModule(scab.getModDescription(modclass, mod),
scab.getModName(modclass, mod),
scab.getKeyType(modclass));
focustab->loadText(scab.getSpan(focustab->getModkey()));
focustab->loadText(scab.getSpan(getModkey(infocus)));
saveit();
wipeit(p);
break; }
case 'p': {
// new page
if (totalpages == PAGELIMIT) break;
for (int j = 0; j < NUMPANES; j++) {
config[pages[totalpages][j]]["module"] = config["defaults"]["module"].c_str();
config[pages[totalpages][j]]["searchkey"] = config["defaults"]["searchkey"].c_str();
config[pages[totalpages][j]]["scope"] = config["defaults"]["scope"].c_str();
char* temp;
asprintf(&temp, "%d", DEFKEY);
config[pages[totalpages][j]]["keytype"] = temp;
free(temp);
asprintf(&temp, "%d", DEFSEARCH);
config[pages[totalpages][j]]["searchtype"] = temp;
free(temp);
}
currentpage = totalpages;
totalpages++;
saveit();
loadPage(p, &scab);
break; }
case 'r': {
// toggle redletter
int redletter = ! parseConf(config["markup"]["redletters"]);
config["markup"]["redletters"] = redletter + '0';
wipeit(p);
saveit(configfile);
saveit();
break; }
case 's': {
@ -376,21 +552,37 @@ int main(int argc, char** argv) {
/* user entered something - get first field with data and
* the search scope (the last item), if any */
int i = 0;
for (i = 0; i < ret.length-1; i++) {
// user entered a scope but no search
//if (i == ret.length - 1) break;
for (i = 0; i < ret.length - 1; i++) {
if (strcmp((ret.strings)[i], "") != 0) {
// ensure we have a search scope
const char* newscope;
if (strcmp((ret.strings)[ret.length-1], "") != 0) {
newscope = (ret.strings)[ret.length-1];
} else {
newscope = config["defaults"]["scope"];
}
// update both pane modkey & config file to keep consistency
config[pages[currentpage][infocus]]["searchkey"] = (ret.strings)[i];
config[pages[currentpage][infocus]]["scope"] = newscope;
char* temp;
asprintf(&temp, "%d", i * -1);
config[pages[currentpage][infocus]]["searchtype"] = temp;
free(temp);
focustab->setKey((ret.strings)[i]);
focustab->setSearch(i * -1,
(ret.strings)[ret.length-1]);
focustab->setSearch(i * -1, newscope);
break;
}
}
if (i != ret.length - 1)
focustab->loadText(scab.search(focustab->getModkey()));
if (i != ret.length - 1) {
focustab->loadText(scab.search(getModkey(infocus)));
saveit();
}
}
wipeit(p);
break; }
@ -399,22 +591,30 @@ int main(int argc, char** argv) {
// toggle Strong's numbers
int strongs = ! parseConf(config["markup"]["strongs"]);
config["markup"]["strongs"] = strongs + '0';
wipeit(p);
saveit(configfile);
saveit();
break; }
case 'w': {
// toggle raw text
int raw = ! parseConf(config["markup"]["rawtext"]);
config["markup"]["rawtext"] = raw + '0';
wipeit(p);
saveit(configfile);
saveit();
break; }
case '?': {
// display help text
clear();
addstr(HELPTEXT);
int x, y;
int i = 0;
while (HELPTEXT[i] != '\0') {
addch(HELPTEXT[i++]);
getyx(stdscr, y, x);
if (y == LINES - 1) {
// pay attention to terminal size
getch();
clear();
}
}
getch();
wipeit(p);
break; }

View File

@ -1,35 +1,88 @@
# Default configuration file
# Part of the Scriptura project
# default section must be present and is reverified on every run
[defaults]
# which module to load by default - this should be the abbreviation used by the Sword module
module=KJV
# When searching the Bible, what default portions are you searching - should be in standard Biblical notation format
module=WEB
scope=Gen 1:1 - Rev 22:21
# What verse are you loading on startup - also standard Biblical notation
searchkey=Mat 5:5
searchkey=2 Tim 1:7
searchtype=1
# general ncurses layout
[layout]
# should panels be arranged vertically 'v' or horizontally 'h'
panels=v
# text markup options - most of these can be set during runtime, and are dependent on what data is present in the module
[markup]
# show footnotes (0 or 1)
footnotes=1
# if showing the words of Jesus in a different color, what color is used - this should be a standard ncurses color
footnotes=0
lettercolor=cyan
# if a translation has identified words as not part of the original text, do we italicize it (0 or 1)
nontextual=0
# ignore all other markup options and give us the raw text stored in the module (0 or 1)
rawtext=0
# do we show the words of Jesus in a separate color (0 or 1)
redletters=1
# if the module contains Strong's numbers, do we display them (0 or 1)
strongs=0
[page0-0]
keytype=0
module=WEB
scope=Gen 1:1 - Rev 22:21
searchkey=2 Tim 1:7
searchtype=1
[page0-1]
keytype=0
module=WEB
scope=Gen 1:1 - Rev 22:21
searchkey=2 Tim 1:7
searchtype=1
[page1-0]
keytype=0
module=WEB
scope=Gen 1:1 - Rev 22:21
searchkey=2 Tim 1:7
searchtype=1
[page1-1]
keytype=0
module=WEB
scope=Gen 1:1 - Rev 22:21
searchkey=2 Tim 1:7
searchtype=1
[page2-0]
keytype=0
module=WEB
scope=Gen 1:1 - Rev 22:21
searchkey=2 Tim 1:7
searchtype=1
[page2-1]
keytype=0
module=WEB
scope=Gen 1:1 - Rev 22:21
searchkey=2 Tim 1:7
searchtype=1
[page3-0]
keytype=
module=
scope=
searchkey=
searchtype=
[page3-1]
keytype=
module=
scope=
searchkey=
searchtype=
[page4-0]
keytype=
module=
scope=
searchkey=
searchtype=
[page4-1]
keytype=
module=
scope=
searchkey=
searchtype=