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:
parent
b90888e718
commit
563922a7e2
221
src/gmnlm.c
221
src/gmnlm.c
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue