1
0
Fork 0
mirror of https://git.sr.ht/~sircmpwn/gmni synced 2024-06-03 11:06:03 +02:00

Merge normal mode & pagination prompts

This commit is contained in:
Drew DeVault 2020-09-20 20:01:31 -04:00
parent b90888e718
commit 563922a7e2

View File

@ -27,9 +27,18 @@ struct browser {
struct gemini_options opts;
FILE *tty;
char *plain_url;
struct Curl_URL *url;
struct link *links;
struct history *history;
bool running;
};
enum prompt_result {
PROMPT_AGAIN,
PROMPT_MORE,
PROMPT_QUIT,
PROMPT_ANSWERED,
};
static void
@ -70,6 +79,63 @@ set_url(struct browser *browser, char *new_url, struct history **history)
return true;
}
static enum prompt_result
do_prompts(const char *prompt, struct browser *browser)
{
fprintf(browser->tty, "%s", prompt);
size_t l = 0;
char *in = NULL;
ssize_t n = getline(&in, &l, browser->tty);
if (n == -1 && feof(browser->tty)) {
return PROMPT_QUIT;
}
if (strcmp(in, "\n") == 0) {
return PROMPT_MORE;
}
if (strcmp(in, "q\n") == 0) {
return PROMPT_QUIT;
}
if (strcmp(in, "b\n") == 0) {
if (!browser->history->prev) {
fprintf(stderr, "At beginning of history\n");
return PROMPT_AGAIN;
}
browser->history = browser->history->prev;
set_url(browser, browser->history->url, NULL);
return PROMPT_ANSWERED;
}
if (strcmp(in, "f\n") == 0) {
if (!browser->history->next) {
fprintf(stderr, "At end of history\n");
return PROMPT_AGAIN;
}
browser->history = browser->history->next;
set_url(browser, browser->history->url, NULL);
return PROMPT_ANSWERED;
}
struct link *link = browser->links;
char *endptr;
int linksel = (int)strtol(in, &endptr, 10);
if (endptr[0] == '\n' && linksel >= 0) {
while (linksel > 0 && link) {
link = link->next;
--linksel;
}
if (!link) {
fprintf(stderr, "Error: no such link.\n");
} else {
set_url(browser, link->url, &browser->history);
return PROMPT_ANSWERED;
}
}
free(in);
return PROMPT_AGAIN;
}
static char *
trim_ws(char *in)
{
@ -80,7 +146,7 @@ trim_ws(char *in)
return in;
}
static void
static bool
display_gemini(struct browser *browser, struct gemini_response *resp)
{
// TODO: Strip ANSI escape sequences
@ -136,29 +202,36 @@ display_gemini(struct browser *browser, struct gemini_response *resp)
++row;
col = 0;
// TODO: It would be nice if we could follow links from this
// prompt
if (browser->pagination && row >= ws.ws_row - 1) {
fprintf(browser->tty, "[Enter for more, or q to stop] ");
size_t n = 0;
char *l = NULL;
if (getline(&l, &n, browser->tty) == -1) {
return;
}
if (strcmp(l, "q\n") == 0) {
return;
if (browser->pagination && row >= ws.ws_row - 4) {
char prompt[4096];
snprintf(prompt, sizeof(prompt), "\n%s at %s\n"
"[Enter]: read more; [n]: follow Nth link; [b]ack; [f]orward; [q]uit\n"
"(more) => ", resp->meta, browser->plain_url);
enum prompt_result result = PROMPT_AGAIN;
while (result == PROMPT_AGAIN) {
result = do_prompts(prompt, browser);
}
switch (result) {
case PROMPT_AGAIN:
case PROMPT_MORE:
break;
case PROMPT_QUIT:
browser->running = false;
return true;
case PROMPT_ANSWERED:
return true;
}
free(l);
row = col = 0;
}
}
gemini_parser_finish(&p);
return false;
}
static void
static bool
display_plaintext(struct browser *browser, struct gemini_response *resp)
{
// TODO: Strip ANSI escape sequences
@ -175,20 +248,20 @@ display_plaintext(struct browser *browser, struct gemini_response *resp)
}
(void)row; (void)col; // TODO: generalize pagination
return false;
}
static void
static bool
display_response(struct browser *browser, struct gemini_response *resp)
{
if (strcmp(resp->meta, "text/gemini") == 0
|| strncmp(resp->meta, "text/gemini;", 12) == 0) {
display_gemini(browser, resp);
return;
return display_gemini(browser, resp);
}
if (strncmp(resp->meta, "text/", 5) == 0) {
display_plaintext(browser, resp);
return;
return display_plaintext(browser, resp);
}
assert(0); // TODO: Deal with other mimetypes
}
static char *
@ -225,19 +298,19 @@ get_input(const struct gemini_response *resp, FILE *source)
return input;
}
static char *
// Returns true to skip prompting
static bool
do_requests(struct browser *browser, struct gemini_response *resp)
{
char *plain_url;
int nredir = 0;
bool requesting = true;
while (requesting) {
CURLUcode uc = curl_url_get(browser->url,
CURLUPART_URL, &plain_url, 0);
CURLUPART_URL, &browser->plain_url, 0);
assert(uc == CURLUE_OK); // Invariant
enum gemini_result res = gemini_request(
plain_url, &browser->opts, resp);
enum gemini_result res = gemini_request(browser->plain_url,
&browser->opts, resp);
if (res != GEMINI_OK) {
fprintf(stderr, "Error: %s\n", gemini_strerr(res, resp));
requesting = false;
@ -253,7 +326,8 @@ do_requests(struct browser *browser, struct gemini_response *resp)
break;
}
char *new_url = gemini_input_url(plain_url, input);
char *new_url = gemini_input_url(
browser->plain_url, input);
assert(new_url);
set_url(browser, new_url, NULL);
break;
@ -278,8 +352,7 @@ do_requests(struct browser *browser, struct gemini_response *resp)
break;
case GEMINI_STATUS_CLASS_SUCCESS:
requesting = false;
display_response(browser, resp);
break;
return display_response(browser, resp);
}
if (requesting) {
@ -287,63 +360,7 @@ do_requests(struct browser *browser, struct gemini_response *resp)
}
}
return plain_url;
}
static bool
do_prompts(const char *prompt, struct browser *browser)
{
bool prompting = true;
while (prompting) {
fprintf(browser->tty, "%s", prompt);
size_t l = 0;
char *in = NULL;
ssize_t n = getline(&in, &l, browser->tty);
if (n == -1 && feof(browser->tty)) {
return false;
}
if (strcmp(in, "q\n") == 0) {
return false;
}
if (strcmp(in, "b\n") == 0) {
if (!browser->history->prev) {
fprintf(stderr, "At beginning of history\n");
continue;
}
browser->history = browser->history->prev;
set_url(browser, browser->history->url, NULL);
break;
}
if (strcmp(in, "f\n") == 0) {
if (!browser->history->next) {
fprintf(stderr, "At end of history\n");
continue;
}
browser->history = browser->history->next;
set_url(browser, browser->history->url, NULL);
break;
}
struct link *link = browser->links;
char *endptr;
int linksel = (int)strtol(in, &endptr, 10);
if (endptr[0] == '\n' && linksel >= 0) {
while (linksel > 0 && link) {
link = link->next;
--linksel;
}
if (!link) {
fprintf(stderr, "Error: no such link.\n");
} else {
set_url(browser, link->url, &browser->history);
break;
}
}
free(in);
}
return true;
return false;
}
int
@ -381,24 +398,38 @@ main(int argc, char *argv[])
ERR_load_crypto_strings();
browser.opts.ssl_ctx = SSL_CTX_new(TLS_method());
bool run = true;
struct gemini_response resp;
while (run) {
browser.running = true;
while (browser.running) {
static char prompt[4096];
char *plain_url = do_requests(&browser, &resp);
if (do_requests(&browser, &resp)) {
// Skip prompts
goto next;
}
snprintf(prompt, sizeof(prompt), "\n%s%s at %s\n"
"[n]: follow Nth link; [o <url>]: open URL; "
"[b]ack; [f]orward; "
"[q]uit\n"
snprintf(prompt, sizeof(prompt), "\n%s at %s\n"
"[n]: follow Nth link; [b]ack; [f]orward; [q]uit\n"
"=> ",
resp.status == GEMINI_STATUS_SUCCESS ? " " : "",
resp.status == GEMINI_STATUS_SUCCESS ? resp.meta : "",
plain_url);
browser.plain_url);
gemini_response_finish(&resp);
run = do_prompts(prompt, &browser);
enum prompt_result result = PROMPT_AGAIN;
while (result == PROMPT_AGAIN || result == PROMPT_MORE) {
result = do_prompts(prompt, &browser);
}
switch (result) {
case PROMPT_AGAIN:
case PROMPT_MORE:
assert(0);
case PROMPT_QUIT:
browser.running = false;
break;
case PROMPT_ANSWERED:
break;
}
next:;
struct link *link = browser.links;
while (link) {
struct link *next = link->next;