zygo

ncurses gopher client
Log | Files | Refs

commit a7dfc248ff4d88d5f7f63df0e61c63b29623216f
parent bc4a6634b54d62d5a460f22a4e81564358f74794
Author: hhvn <dev@hhvn.uk>
Date:   Sun, 16 Jan 2022 19:10:43 +0000

zygo.c zygo.h config.h: navigation

Diffstat:
Mconfig.h | 1+
Mzygo.c | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mzygo.h | 8+++++++-
3 files changed, 106 insertions(+), 9 deletions(-)

diff --git a/config.h b/config.h @@ -5,6 +5,7 @@ static short uri_pair[2] = {0, 7}; static short cmd_pair[2] = {7, 0}; static short arg_pair[2] = {-1, 0}; static short err_pair[2] = {160, 0}; +static short eid_pair[2] = {4, -1}; static int stimeout = 5; diff --git a/zygo.c b/zygo.c @@ -26,6 +26,7 @@ #include <locale.h> #include <signal.h> #include <unistd.h> +#include <ctype.h> #include <stdio.h> #include "zygo.h" #include "config.h" @@ -41,7 +42,9 @@ int config[] = { struct { int scroll; - int wantinput; + int wantinput; /* 0 - no + * 1 - yes (with cmd) + * 2 - yes (id) */ wint_t input[BUFLEN]; char cmd; char *arg; @@ -318,24 +321,31 @@ list_free(List **l) { void list_append(List **l, Elem *e) { + Elem *elem; + zygo_assert(l); if (!(*l)) { (*l) = emalloc(sizeof(List)); (*l)->len = 0; + (*l)->lastid = 0; (*l)->elems = NULL; } + elem = elem_dup(e); + if (elem->type != 'i') + elem->id = ++(*l)->lastid; + if (!(*l)->elems) { (*l)->len = 1; (*l)->elems = emalloc(sizeof(Elem *) * (*l)->len); - *(*l)->elems = elem_dup(e); + *(*l)->elems = elem; return; } (*l)->len++; (*l)->elems = erealloc((*l)->elems, sizeof(Elem *) * (*l)->len); - *((*l)->elems + (*l)->len - 1) = elem_dup(e); + *((*l)->elems + (*l)->len - 1) = elem; } Elem * @@ -345,6 +355,18 @@ list_get(List **l, size_t elem) { return *((*l)->elems + elem); } +Elem * +list_idget(List **l, size_t id) { + int i; + + if (!l || !(*l) || (*l)->len == 0 || id >= (*l)->len) + return NULL; + for (i = 0; i < (*l)->len; i++) + if ((*((*l)->elems + i))->id == id) + return *((*l)->elems + i); + return NULL; +} + size_t list_len(List **l) { if (!l || !(*l)) @@ -352,6 +374,9 @@ list_len(List **l) { return (*l)->len; } +/* + * Misc functions + */ int readline(char *buf, size_t count) { size_t i = 0; @@ -417,6 +442,18 @@ go(Elem *e) { return 0; } +int +digits(int i) { + int ret = 0; + + do { + ret++; + i /= 10; + } while (i != 0); + + return ret; +} + /* * UI functions */ @@ -436,7 +473,7 @@ error(char *format, ...) { addstr(" "); refresh(); candraw = 0; - alarm(5); + alarm(stimeout); } Scheme * @@ -452,6 +489,12 @@ int draw_line(Elem *e, int maxlines) { int lc, cc; + attron(COLOR_PAIR(PAIR_EID)); + if (e->type != 'i') + printw("% 3d ", e->id); + else + printw(" "); + attroff(A_COLOR); printw("%s | ", getscheme(e->type)->name); attron(COLOR_PAIR(getscheme(e->type)->pair)); printw("%s\n", e->desc); @@ -493,8 +536,10 @@ draw_bar(void) { printw(" "); if (ui.wantinput) { curs_set(1); - attron(COLOR_PAIR(PAIR_CMD)); - printw("%c", ui.cmd); + if (ui.wantinput == 1) { + attron(COLOR_PAIR(PAIR_CMD)); + printw("%c", ui.cmd); + } attron(COLOR_PAIR(PAIR_ARG)); printw("%s", ui.arg); } else curs_set(0); @@ -539,7 +584,7 @@ run(void) { if (c == KEY_RESIZE) { draw_page(); draw_bar(); - } else if (ui.wantinput) { + } else if (ui.wantinput == 1) { if (c == 27 /* escape */) { ui.wantinput = 0; } else if (c == '\n') { @@ -565,6 +610,29 @@ run(void) { syncinput(); } draw_bar(); + } else if (ui.wantinput == 2) { + if (c == 27 /* escape */) { + ui.wantinput = 0; + } else if (c == '\n' || il + 1 >= digits(page->lastid)) { + if (c != '\n') { + ui.input[il++] = c; + ui.input[il] = '\0'; + syncinput(); + } + goto gonum; + } else if (c == KEY_BACKSPACE || c == 127) { + if (il == 0) { + ui.wantinput = 0; + } else { + ui.input[--il] = '\0'; + syncinput(); + } + } else if (isdigit((int)c)) { + ui.input[il++] = c; + ui.input[il] = '\0'; + syncinput(); + } + draw_bar(); } else { switch (c) { case KEY_DOWN: @@ -598,10 +666,20 @@ run(void) { case 'q': endwin(); exit(EXIT_SUCCESS); + /* link numbers */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - /* TODO: numbered link handling */ + ui.wantinput = 2; + ui.input[0] = c; + ui.input[1] = '\0'; + syncinput(); + il = 1; + if (digits(page->lastid) == 1) + goto gonum; + draw_bar(); break; + /* commands without arg */ + /* commands with arg */ case ':': ui.cmd = (char)c; ui.wantinput = 1; @@ -619,6 +697,17 @@ run(void) { break; } } + + continue; + +gonum: + if (atoi(ui.arg) >= page->lastid || atoi(ui.arg) < 1) + error("no such link: %d", atoi(ui.arg)); + else + go(list_idget(&page, atoi(ui.arg))); + ui.wantinput = 0; + draw_page(); + draw_bar(); } } @@ -667,6 +756,7 @@ main(int argc, char *argv[]) { init_pair(PAIR_CMD, cmd_pair[0], cmd_pair[1]); init_pair(PAIR_ARG, arg_pair[0], arg_pair[1]); init_pair(PAIR_ERR, err_pair[0], err_pair[1]); + init_pair(PAIR_EID, eid_pair[0], eid_pair[1]); for (i = 0; scheme[i].type; i++) { scheme[i].pair = i + PAIR_SCHEME; init_pair(scheme[i].pair, scheme[i].fg, -1); diff --git a/zygo.h b/zygo.h @@ -28,12 +28,16 @@ struct Elem { char *selector; char *server; char *port; + size_t id; /* only set when: + * - type != 'i' + * - in a list */ }; typedef struct List List; struct List { struct Elem **elems; size_t len; + size_t lastid; }; typedef struct Scheme Scheme; @@ -54,7 +58,8 @@ enum { PAIR_CMD = 3, PAIR_ARG = 4, PAIR_ERR = 5, - PAIR_SCHEME = 6, + PAIR_EID = 6, + PAIR_SCHEME = 7, }; extern List *history; @@ -80,6 +85,7 @@ char *elemtouri(Elem *e); void list_free(List **l); void list_append(List **l, Elem *e); Elem *list_get(List **l, size_t elem); +Elem *list_idget(List **l, size_t id); size_t list_len(List **l);