commit 2051e6535ed850f2676a2ef1353b58943369eee8 from: Omar Polo date: Sat Mar 13 21:47:25 2021 UTC first draft of history system is here commit - 3148eeac0e951ab7d1818680e65b366276d484bd commit + 2051e6535ed850f2676a2ef1353b58943369eee8 blob - ad9d7c241a992e0548e4aa80c463f112d0aec7c5 blob + 9b6cc8523d58871663b3a93f05e6daf88a10f206 --- Makefile.am +++ Makefile.am @@ -4,6 +4,7 @@ telescope_SOURCES = compat.h \ compat/*.[ch] \ gemini.c \ gemtext.c \ + hist.c \ keymap.c \ mime.c \ pages.c \ blob - /dev/null blob + 1426ef08f888dba8cf9c25dc9c0c17736aa96666 (mode 644) --- /dev/null +++ hist.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 Omar Polo + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "telescope.h" + +#include + +void +hist_clear_forward(struct histhead *head, struct hist *h) +{ + if (h == NULL) + return; + hist_clear_forward(head, TAILQ_NEXT(h, entries)); + TAILQ_REMOVE(&head->head, h, entries); + free(h); +} + +void +hist_push(struct histhead *head, struct hist *h) +{ + head->len++; + if (TAILQ_EMPTY(&head->head)) + TAILQ_INSERT_HEAD(&head->head, h, entries); + else + TAILQ_INSERT_TAIL(&head->head, h, entries); +} blob - 5a7d85f8cd585912bde5e691d7b840b2837fa8d0 blob + 1cfaeef114ef2fdd2b03e11a08ad16dbf39b8bd5 --- telescope.c +++ telescope.c @@ -23,15 +23,18 @@ static struct proto protos[] = { static struct imsgbuf *netibuf; -static void handle_imsg_err(struct imsg*, size_t); -static void handle_imsg_check_cert(struct imsg*, size_t); -static void handle_imsg_got_code(struct imsg*, size_t); -static void handle_imsg_got_meta(struct imsg*, size_t); -static void handle_imsg_buf(struct imsg*, size_t); -static void handle_imsg_eof(struct imsg*, size_t); +static void die(void) __attribute__((__noreturn__)); +static struct tab *tab_by_id(uint32_t); +static void handle_imsg_err(struct imsg*, size_t); +static void handle_imsg_check_cert(struct imsg*, size_t); +static void handle_imsg_got_code(struct imsg*, size_t); +static void handle_imsg_got_meta(struct imsg*, size_t); +static void handle_imsg_buf(struct imsg*, size_t); +static void handle_imsg_eof(struct imsg*, size_t); +static void dispatch_imsg(int, short, void*); +static void load_page_from_str(struct tab*, const char*); +static void do_load_url(struct tab*, const char*); -static void load_page_from_str(struct tab*, const char*); - static imsg_handlerfn *handlers[] = { [IMSG_ERR] = handle_imsg_err, [IMSG_CHECK_CERT] = handle_imsg_check_cert, @@ -72,7 +75,7 @@ handle_imsg_err(struct imsg *imsg, size_t datalen) page[datalen-1] = '\0'; if (asprintf(&page, "# Error loading %s\n\n> %s\n", - tab->urlstr, page) == -1) + tab->hist_cur->h, page) == -1) die(); load_page_from_str(tab, page); free(page); @@ -164,7 +167,7 @@ handle_imsg_got_meta(struct imsg *imsg, size_t datalen load_page_from_str(tab, err_pages[TOO_MUCH_REDIRECTS]); } else - load_url(tab, tab->meta); + do_load_url(tab, tab->meta); } else { /* 4x, 5x & 6x */ load_page_from_str(tab, err_pages[tab->code]); } @@ -240,16 +243,18 @@ load_page_from_str(struct tab *tab, const char *page) void load_about_url(struct tab *tab, const char *url) { - char *m; + char *m; + size_t len; - memset(tab->urlstr, 0, sizeof(tab->urlstr)); + memset(&tab->url, 0, sizeof(tab->url)); m = strchr(url, ':'); strlcpy(tab->url.scheme, "about", sizeof(tab->url.scheme)); strlcpy(tab->url.path, m+1, sizeof(tab->url.path)); - strlcpy(tab->urlstr, url, sizeof(tab->urlstr)); + len = sizeof(tab->hist_cur->h)-1; + strlcpy(tab->hist_cur->h, url, len); if (!strcmp(url, "about:new")) load_page_from_str(tab, about_new); @@ -262,6 +267,7 @@ load_gemini_url(struct tab *tab, const char *url) { const char *err; char *p; + size_t len; if (has_prefix(url, "gemini:")) { if (!url_parse(url, &tab->url, &err)) @@ -271,9 +277,10 @@ load_gemini_url(struct tab *tab, const char *url) goto err; } - url_unparse(&tab->url, tab->urlstr, sizeof(tab->urlstr)); + len = sizeof(tab->hist_cur->h)-1; + url_unparse(&tab->url, tab->hist_cur->h, len); imsg_compose(netibuf, IMSG_GET, tab->id, 0, -1, - tab->urlstr, strlen(tab->urlstr)+1); + tab->hist_cur->h, len+1); imsg_flush(netibuf); return; @@ -281,13 +288,13 @@ err: if (asprintf(&p, "#error loading %s\n>%s\n", url, err) == -1) die(); - strlcpy(tab->urlstr, url, sizeof(tab->urlstr)); + strlcpy(tab->hist_cur->h, url, len); load_page_from_str(tab, p); free(p); } -void -load_url(struct tab *tab, const char *url) +static void +do_load_url(struct tab *tab, const char *url) { struct proto *p; @@ -302,6 +309,44 @@ load_url(struct tab *tab, const char *url) } void +load_url(struct tab *tab, const char *url) +{ + if (tab->hist_cur != NULL) + hist_clear_forward(&tab->hist, TAILQ_NEXT(tab->hist_cur, entries)); + + if ((tab->hist_cur = calloc(1, sizeof(*tab->hist_cur))) == NULL) { + event_loopbreak(); + return; + } + hist_push(&tab->hist, tab->hist_cur); + do_load_url(tab, url); +} + +int +load_previous_page(struct tab *tab) +{ + struct hist *h; + + if ((h = TAILQ_PREV(tab->hist_cur, mhisthead, entries)) == NULL) + return 0; + tab->hist_cur = h; + do_load_url(tab, h->h); + return 1; +} + +int +load_next_page(struct tab *tab) +{ + struct hist *h; + + if ((h = TAILQ_NEXT(tab->hist_cur, entries)) == NULL) + return 0; + tab->hist_cur = h; + do_load_url(tab, h->h); + return 1; +} + +void stop_tab(struct tab *tab) { imsg_compose(netibuf, IMSG_STOP, tab->id, 0, -1, NULL, 0); blob - 891c0885d00a6245148faa47e09ae776f3e55035 blob + 1dc9501e5f5d65f38cb6543a81ff7be791058e24 --- telescope.h +++ telescope.h @@ -102,8 +102,10 @@ struct tab { uint32_t id; uint32_t flags; - char urlstr[GEMINI_URL_LEN]; struct url url; + struct histhead hist; + struct hist *hist_cur; + size_t hist_off; int code; char meta[GEMINI_URL_LEN]; @@ -144,6 +146,10 @@ int client_main(struct imsgbuf *b); /* gemtext.c */ void gemtext_initparser(struct parser*); +/* hist.c */ +void hist_clear_forward(struct histhead*, struct hist*); +void hist_push(struct histhead*, struct hist*); + /* keymap.c */ int kbd(const char*); const char *unkbd(int); @@ -172,6 +178,8 @@ void sandbox_network_process(void); void load_about_url(struct tab*, const char*); void load_gemini_url(struct tab*, const char*); void load_url(struct tab*, const char*); +int load_previous_page(struct tab*); +int load_next_page(struct tab*); void stop_tab(struct tab*); /* textplain.c */ blob - 21f55e4d4b132b1b04f8ac77fabb7abf908cbf47 blob + 6ebc6bca2a03a899c1eec92c38cb34250c8e8cf7 --- ui.c +++ ui.c @@ -93,6 +93,8 @@ static void cmd_end_of_buffer(struct tab*); static void cmd_kill_telescope(struct tab*); static void cmd_push_button(struct tab*); static void cmd_push_button_new_tab(struct tab*); +static void cmd_previous_page(struct tab*); +static void cmd_next_page(struct tab*); static void cmd_clear_minibuf(struct tab*); static void cmd_execute_extended_command(struct tab*); static void cmd_tab_close(struct tab*); @@ -282,6 +284,9 @@ load_default_keys(void) global_set_key("M-<", cmd_beginning_of_buffer); global_set_key("M->", cmd_end_of_buffer); + global_set_key("C-M-b", cmd_previous_page); + global_set_key("C-M-f", cmd_next_page); + /* vi/vi-like */ global_set_key("k", cmd_previous_line); global_set_key("j", cmd_next_line); @@ -296,6 +301,9 @@ load_default_keys(void) global_set_key("g g", cmd_beginning_of_buffer); global_set_key("G", cmd_end_of_buffer); + global_set_key("H", cmd_previous_page); + global_set_key("L", cmd_next_page); + /* tmp */ global_set_key("q", cmd_kill_telescope); @@ -311,6 +319,9 @@ load_default_keys(void) global_set_key("", cmd_scroll_up); global_set_key("", cmd_scroll_down); + global_set_key("M-", cmd_previous_page); + global_set_key("M-", cmd_next_page); + /* "ncurses standard" */ global_set_key("C-l", cmd_redraw); @@ -584,8 +595,21 @@ cmd_push_button_new_tab(struct tab *tab) t = new_tab(); memcpy(&t->url, &tab->url, sizeof(tab->url)); - memcpy(&t->urlstr, &tab->urlstr, sizeof(tab->urlstr)); load_url_in_tab(t, l->alt); +} + +static void +cmd_previous_page(struct tab *tab) +{ + if (!load_previous_page(tab)) + message("No previous page"); +} + +static void +cmd_next_page(struct tab *tab) +{ + if (!load_next_page(tab)) + message("No next page"); } static void @@ -678,8 +702,8 @@ cmd_load_current_url(struct tab *tab) enter_minibuffer(lu_self_insert, lu_select, exit_minibuffer, &lu_history); strlcpy(ministate.prompt, "Load URL: ", sizeof(ministate.prompt)); - strlcpy(ministate.buf, tab->urlstr, sizeof(ministate.buf)); - ministate.off = strlen(tab->urlstr); + strlcpy(ministate.buf, tab->hist_cur->h, sizeof(ministate.buf)); + ministate.off = strlen(tab->hist_cur->h); ministate.len = ministate.off; } @@ -1279,7 +1303,7 @@ redraw_tabline(void) current = tab->flags & TAB_CURRENT; if (*(title = tab->page.title) == '\0') - title = tab->urlstr; + title = tab->hist_cur->h; if (current) wattron(tabline, A_UNDERLINE); @@ -1321,7 +1345,7 @@ redraw_modeline(struct tab *tab) wprintw(modeline, "%d/%d %s ", tab->s->line_off + tab->s->curs_y, tab->s->line_max, - tab->urlstr); + tab->hist_cur->h); getyx(modeline, y, x); getmaxyx(modeline, max_y, max_x); @@ -1556,6 +1580,8 @@ new_tab(void) if ((tab = calloc(1, sizeof(*tab))) == NULL) goto err; + TAILQ_INIT(&tab->hist.head); + if ((tab->s = calloc(1, sizeof(*t->s))) == NULL) goto err; @@ -1637,7 +1663,7 @@ void ui_on_tab_loaded(struct tab *tab) { stop_loading_anim(tab); - message("Loaded %s", tab->urlstr); + message("Loaded %s", tab->hist_cur->h); } void