Commit Diff


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 <op@omarpolo.com>
+ *
+ * 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 <stdlib.h>
+
+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("<prior>",	cmd_scroll_up);
 	global_set_key("<next>",	cmd_scroll_down);
 
+	global_set_key("M-<left>",	cmd_previous_page);
+	global_set_key("M-<right>",	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