Commit Diff


commit - cb75f36c2043dbc8025438662a547f5b162f9e17
commit + c1d27b0e114e6a65f7979971940df212f00bb2ae
blob - f98e328499a42678d5e82a73dfc56a7126464d7c
blob + 3f89716e58df8fb4fc17d02680a8be4cfa49f5ec
--- cmd.c
+++ cmd.c
@@ -253,7 +253,7 @@ cmd_scroll_down(struct buffer *buffer)
 void
 cmd_beginning_of_buffer(struct buffer *buffer)
 {
-	buffer->current_line = TAILQ_FIRST(&buffer->head);
+	buffer->current_line = TAILQ_FIRST(&buffer->vhead);
 	buffer->cpoff = 0;
 	buffer->top_line = buffer->current_line;
 	buffer->line_off = 0;
@@ -262,7 +262,7 @@ cmd_beginning_of_buffer(struct buffer *buffer)
 void
 cmd_end_of_buffer(struct buffer *buffer)
 {
-	buffer->current_line = TAILQ_LAST(&buffer->head, vhead);
+	buffer->current_line = TAILQ_LAST(&buffer->vhead, vhead);
 
 	if (buffer->current_line == NULL)
 		return;
@@ -620,7 +620,7 @@ cmd_link_select(struct buffer *buffer)
 
 	GUARD_RECURSIVE_MINIBUFFER();
 
-	l = TAILQ_FIRST(&buffer->page.head);
+	l = TAILQ_FIRST(&buffer->head);
 	while (l != NULL && l->type != LINE_LINK)
 		l = TAILQ_NEXT(l, lines);
 
@@ -640,7 +640,7 @@ cmd_swiper(struct buffer *buffer)
 	GUARD_RECURSIVE_MINIBUFFER();
 
 	enter_minibuffer(sensible_self_insert, swiper_select, exit_minibuffer,
-	    NULL, compl_swiper, TAILQ_FIRST(&buffer->page.head), 1);
+	    NULL, compl_swiper, TAILQ_FIRST(&buffer->head), 1);
 	strlcpy(ministate.prompt, "Select line: ", sizeof(ministate.prompt));
 }
 
@@ -651,7 +651,7 @@ cmd_toc(struct buffer *buffer)
 
 	GUARD_RECURSIVE_MINIBUFFER();
 
-	l = TAILQ_FIRST(&buffer->page.head);
+	l = TAILQ_FIRST(&buffer->head);
 	while (l != NULL &&
 	    l->type != LINE_TITLE_1 &&
 	    l->type != LINE_TITLE_2 &&
@@ -941,7 +941,7 @@ cmd_mini_goto_beginning(struct buffer *buffer)
 	if ((vl = buffer->current_line) != NULL)
 		vl->parent->type = LINE_COMPL;
 
-	vl = TAILQ_FIRST(&buffer->head);
+	vl = TAILQ_FIRST(&buffer->vhead);
 	while (vl != NULL && vl->parent->flags & L_HIDDEN)
 		vl = TAILQ_NEXT(vl, vlines);
 
@@ -966,7 +966,7 @@ cmd_mini_goto_end(struct buffer *buffer)
 	if ((vl = buffer->current_line) != NULL)
 		vl->parent->type = LINE_COMPL;
 
-	vl = TAILQ_LAST(&buffer->head, vhead);
+	vl = TAILQ_LAST(&buffer->vhead, vhead);
 	while (vl != NULL && vl->parent->flags & L_HIDDEN)
 		vl = TAILQ_PREV(vl, vhead, vlines);
 
blob - e633b929ad6e16c34ee3eda17e47d03f3da9cc3f
blob + 53d379ca74bbfe2e453391a5dd382022d6ab084d
--- compl.c
+++ compl.c
@@ -78,10 +78,10 @@ compl_ts(void **data, void **ret, const char **descr)
 
 	*ret = *tab;
 
-	if (*(*tab)->buffer.page.title == '\0')
+	if (*(*tab)->buffer.title == '\0')
 		return hist_cur((*tab)->hist);
 	*descr = hist_cur((*tab)->hist);
-	return (*tab)->buffer.page.title;
+	return (*tab)->buffer.title;
 }
 
 /*
blob - c69b5a51e53b5caab522d14dd23fec51f52e4d29
blob + d170814554742461eb57783379f97b67f08ea61c
--- downloads.c
+++ downloads.c
@@ -36,7 +36,7 @@ no_downloads(void)
 	l->type = LINE_DOWNLOAD_INFO;
 	l->line = strdup("No downloads");
 
-	TAILQ_INSERT_TAIL(&downloadwin.page.head, l, lines);
+	TAILQ_INSERT_TAIL(&downloadwin.head, l, lines);
 }
 
 void
@@ -46,7 +46,7 @@ recompute_downloads(void)
 	struct line	*l;
 	char		 buf[FMT_SCALED_STRSIZE];
 
-	downloadwin.page.name = "*Downloads*";
+	downloadwin.mode = "*Downloads*";
 	erase_buffer(&downloadwin);
 
 	if (STAILQ_EMPTY(&downloads)) {
@@ -67,7 +67,7 @@ recompute_downloads(void)
 		l->line = strdup(buf);
 		l->alt = strdup(d->path);
 
-		TAILQ_INSERT_TAIL(&downloadwin.page.head, l, lines);
+		TAILQ_INSERT_TAIL(&downloadwin.head, l, lines);
 	}
 
 end:
blob - 49e10ea66c67584f7e03967da8788545e4f98cf4
blob + 4c0614a1bd8fd277ba066453c872da3d66032d9f
--- fs.c
+++ fs.c
@@ -34,6 +34,7 @@
 
 #include "pages.h"
 #include "parser.h"
+#include "telescope.h"
 #include "session.h"
 #include "utils.h"
 
@@ -86,6 +87,7 @@ select_non_dotdot(const struct dirent *d)
 static void
 send_dir(struct tab *tab, const char *path)
 {
+	struct buffer	*buffer = &tab->buffer;
 	struct dirent	**names;
 	int		(*selector)(const struct dirent *) = select_non_dot;
 	int		  i, len;
@@ -112,8 +114,8 @@ send_dir(struct tab *tab, const char *path)
 		return;
 	}
 
-	parser_init(tab, gemtext_initparser);
-	parser_parsef(tab, "# Index of %s\n\n", path);
+	parser_init(buffer, &gemtext_parser);
+	parser_parsef(buffer, "# Index of %s\n\n", path);
 
 	for (i = 0; i < len; ++i) {
 		const char *sufx = "";
@@ -121,7 +123,7 @@ send_dir(struct tab *tab, const char *path)
 		if (names[i]->d_type == DT_DIR)
 			sufx = "/";
 
-		parser_parsef(tab, "=> %s%s\n", names[i]->d_name, sufx);
+		parser_parsef(buffer, "=> %s%s\n", names[i]->d_name, sufx);
 	}
 
 	parser_free(tab);
@@ -139,40 +141,40 @@ is_dir(FILE *fp)
 	return S_ISDIR(sb.st_mode);
 }
 
-static parserinit
+static struct parser *
 file_type(const char *path)
 {
 	const struct mapping {
 		const char	*ext;
-		parserinit	 fn;
+		struct parser	*parser;
 	} ms[] = {
-		{"diff",	textpatch_initparser},
-		{"gemini",	gemtext_initparser},
-		{"gmi",		gemtext_initparser},
-		{"markdown",	textplain_initparser},
-		{"md",		textplain_initparser},
-		{"patch",	gemtext_initparser},
+		{"diff",	&textpatch_parser},
+		{"gemini",	&gemtext_parser},
+		{"gmi",		&gemtext_parser},
+		{"markdown",	&textplain_parser},
+		{"md",		&textplain_parser},
+		{"patch",	&gemtext_parser},
 		{NULL, NULL},
 	}, *m;
 	const char *dot;
 
 	if ((dot = strrchr(path, '.')) == NULL)
-		return textplain_initparser;
+		return &textplain_parser;
 
 	dot++;
 
 	for (m = ms; m->ext != NULL; ++m)
 		if (!strcmp(m->ext, dot))
-			return m->fn;
+			return m->parser;
 
-	return textplain_initparser;
+	return &textplain_parser;
 }
 
 void
 fs_load_url(struct tab *tab, const char *url)
 {
 	const char	*bpath = "bookmarks.gmi", *fallback = "# Not found\n";
-	parserinit	 initfn = gemtext_initparser;
+	struct parser	*parser = &gemtext_parser;
 	char		 path[PATH_MAX];
 	FILE		*fp = NULL;
 	size_t		 i;
@@ -216,7 +218,7 @@ fs_load_url(struct tab *tab, const char *url)
 	} else if (!strncmp(url, "file://", 7)) {
 		url += 7;
 		strlcpy(path, url, sizeof(path));
-		initfn = file_type(url);
+		parser = file_type(url);
 	} else
 		goto done;
 
@@ -228,12 +230,12 @@ fs_load_url(struct tab *tab, const char *url)
 		goto done;
 	}
 
-	parser_init(tab, initfn);
+	parser_init(&tab->buffer, parser);
 	for (;;) {
 		size_t r;
 
 		r = fread(buf, 1, sizeof(buf), fp);
-		if (!parser_parse(tab, buf, r))
+		if (!parser_parse(&tab->buffer, buf, r))
 			break;
 		if (r != sizeof(buf))
 			break;
blob - aeb2fefa2abf58316b2f596b006349b1cbee2348
blob + 2d4a687fef96e329ef2414b0400715e5126f2124
--- help.c
+++ help.c
@@ -48,7 +48,7 @@ emit_help_item(char *prfx, interactivefn *fn)
 	l->line = strdup(prfx);
 	l->alt = (char*)cmd->cmd;
 
-	TAILQ_INSERT_TAIL(&helpwin.page.head, l, lines);
+	TAILQ_INSERT_TAIL(&helpwin.head, l, lines);
 }
 
 static void
@@ -85,7 +85,7 @@ recompute_help(void)
 	if (last_active_map != current_map) {
 		last_active_map = current_map;
 
-		helpwin.page.name = "*Help*";
+		helpwin.mode = "*Help*";
 		erase_buffer(&helpwin);
 		rec_compute_help(current_map, p, sizeof(p));
 		wrap_page(&helpwin, help_cols);
blob - 234fc31e30c9c0ee56f9ef045acdb1fbe2370a72
blob + b5766b6d317771d45938c3ce5e19da15a27d85e8
--- identity.c
+++ identity.c
@@ -80,9 +80,7 @@ size_t		 about_new_len;
 const uint8_t	*bookmarks;
 size_t		 bookmarks_len;
 
-void	gemtext_initparser(struct parser *p) { return; }
-void	textpatch_initparser(struct parser *p) { return; }
-void	textplain_initparser(struct parser *p) { return; }
+struct parser gemtext_parser, textplain_parser, textpatch_parser;
 
 void	 load_page_from_str(struct tab *tab, const char *page) { return; }
 void	 erase_buffer(struct buffer *buffer) { return; }
blob - addfa81f152e57db2d8304edca08ee25bc157475
blob + b2a57a944ecc6774de923e03763976a4318f740a
--- mcache.c
+++ mcache.c
@@ -27,6 +27,7 @@
 #include "hist.h"
 #include "mcache.h"
 #include "parser.h"
+#include "telescope.h"
 #include "utils.h"
 
 static struct timeval tv = { 5 * 60, 0 };
@@ -38,7 +39,7 @@ static size_t		tot;
 
 struct mcache_entry {
 	time_t		 ts;
-	parserfn	 parser;
+	struct parser	*parser;
 	int		 trust;
 	char		*buf;
 	size_t		 buflen;
@@ -108,14 +109,14 @@ mcache_tab(struct tab *tab)
 	if ((e = calloc(1, len)) == NULL)
 		return -1;
 	e->ts = time(NULL);
-	e->parser = tab->buffer.page.init;
+	e->parser = tab->buffer.parser;
 	e->trust = tab->trust;
 	memcpy(e->url, url, l);
 
 	if ((fp = open_memstream(&e->buf, &e->buflen)) == NULL)
 		goto err;
 
-	if (!parser_serialize(tab, fp))
+	if (!parser_serialize(&tab->buffer, fp))
 		goto err;
 
 	fclose(fp);
@@ -153,8 +154,8 @@ mcache_lookup(const char *url, struct tab *tab)
 	if ((e = ohash_find(&h, slot)) == NULL)
 		return 0;
 
-	parser_init(tab, e->parser);
-	if (!parser_parse(tab, e->buf, e->buflen))
+	parser_init(&tab->buffer, e->parser);
+	if (!parser_parse(&tab->buffer, e->buf, e->buflen))
 		goto err;
 	if (!parser_free(tab))
 		goto err;
blob - 98f614c6fa5c2ffd1edf1aff9c30a7e17816b9cc
blob + 39bb0be8f2462d3078a206abc9626949573f966c
--- mime.c
+++ mime.c
@@ -28,13 +28,13 @@ static int	check_for_utf8(char*);
 
 static const struct parser_table {
 	const char	*mediatype;
-	void		(*parserinit)(struct parser*);
+	struct parser	*parser;
 } ptable[] = {
-	{ "text/gemini",	gemtext_initparser },
-	{ "text/x-patch",	textpatch_initparser },
-	{ "text/x-diff",	textpatch_initparser },
-	{ "application/x-patch",textpatch_initparser },
-	{ "text/*",		textplain_initparser },
+	{ "text/gemini",	&gemtext_parser },
+	{ "text/x-patch",	&textpatch_parser },
+	{ "text/x-diff",	&textpatch_parser },
+	{ "application/x-patch",&textpatch_parser },
+	{ "text/*",		&textplain_parser },
 	{ NULL, NULL}
 };
 
@@ -86,7 +86,7 @@ setup_parser_for(struct tab *tab)
 
 	for (t = ptable; t->mediatype != NULL; ++t) {
 		if (!fnmatch(t->mediatype, buf, 0)) {
-			parser_init(tab, t->parserinit);
+			parser_init(&tab->buffer, t->parser);
 			return 1;
 		}
 	}
blob - b4fbe8a2f8d2663be3688240e15f9aa32568198c
blob + f830947eb8c2e60bd29e8fc8f7c293b003fc7d30
--- minibuffer.c
+++ minibuffer.c
@@ -135,7 +135,7 @@ recompute_completions(int add)
 	}
 
 	b = &ministate.compl.buffer;
-	TAILQ_FOREACH(l, &b->page.head, lines) {
+	TAILQ_FOREACH(l, &b->head, lines) {
 		l->type = LINE_COMPL;
 		if (add && l->flags & L_HIDDEN)
 			continue;
@@ -151,7 +151,7 @@ recompute_completions(int add)
 	}
 
 	if (b->current_line == NULL)
-		b->current_line = TAILQ_FIRST(&b->head);
+		b->current_line = TAILQ_FIRST(&b->vhead);
 	b->current_line = adjust_line(b->current_line, b);
 	vl = b->current_line;
 	if (ministate.compl.must_select && vl != NULL)
@@ -403,7 +403,7 @@ jump_to_line(struct line *l)
 
 	buffer = current_buffer();
 
-	TAILQ_FOREACH(vl, &buffer->head, vlines) {
+	TAILQ_FOREACH(vl, &buffer->vhead, vlines) {
 		if (vl->parent == l)
 			break;
 	}
@@ -538,11 +538,9 @@ populate_compl_buffer(complfn *fn, void *data)
 	const char	*s, *descr;
 	struct line	*l;
 	struct buffer	*b;
-	struct parser	*p;
 	void		*linedata;
 
 	b = &ministate.compl.buffer;
-	p = &b->page;
 
 	linedata = NULL;
 	descr = NULL;
@@ -556,13 +554,13 @@ populate_compl_buffer(complfn *fn, void *data)
 		if ((l->line = strdup(s)) == NULL)
 			abort();
 
-		TAILQ_INSERT_TAIL(&p->head, l, lines);
+		TAILQ_INSERT_TAIL(&b->head, l, lines);
 
 		linedata = NULL;
 		descr = NULL;
 	}
 
-	if ((l = TAILQ_FIRST(&p->head)) != NULL &&
+	if ((l = TAILQ_FIRST(&b->head)) != NULL &&
 	    ministate.compl.must_select)
 		l->type = LINE_COMPL_CURRENT;
 }
@@ -700,10 +698,10 @@ minibuffer_init(void)
 		err(1, "hist_new");
 
 	TAILQ_INIT(&ministate.compl.buffer.head);
-	TAILQ_INIT(&ministate.compl.buffer.page.head);
+	TAILQ_INIT(&ministate.compl.buffer.vhead);
 
 	ministate.line.type = LINE_TEXT;
 	ministate.vline.parent = &ministate.line;
-	ministate.buffer.page.name = "*minibuffer*";
+	ministate.buffer.mode = "*minibuffer*";
 	ministate.buffer.current_line = &ministate.vline;
 }
blob - e1168776b481988b2b0c066f6cdbc6ce837932ff
blob + 1bd28ce6270695d16e124b303c635ab3451f683a
--- parser.c
+++ parser.c
@@ -23,28 +23,31 @@
 #include "parser.h"
 #include "telescope.h"
 
-static int parser_foreach_line(struct parser *, const char *, size_t);
+static int parser_foreach_line(struct buffer *, const char *, size_t);
 
 void
-parser_init(struct tab *tab, parserfn fn)
+parser_init(struct buffer *buffer, struct parser *p)
 {
-	erase_buffer(&tab->buffer);
-	fn(&tab->buffer.page);
-	tab->buffer.page.init = fn;
+	erase_buffer(buffer);
+
+	memset(buffer->title, 0, sizeof(buffer->title));
+	buffer->parser = p;
+	buffer->mode = p->name;
+	buffer->parser_flags = p->initflags;
 }
 
 int
-parser_parse(struct tab *tab, const char *chunk, size_t len)
+parser_parse(struct buffer *buffer, const char *chunk, size_t len)
 {
-	struct parser *p = &tab->buffer.page;
+	struct parser *p = buffer->parser;
 
 	if (p->parse)
-		return p->parse(p, chunk, len);
-	return parser_foreach_line(p, chunk, len);
+		return p->parse(buffer, chunk, len);
+	return parser_foreach_line(buffer, chunk, len);
 }
 
 int
-parser_parsef(struct tab *tab, const char *fmt, ...)
+parser_parsef(struct buffer *buffer, const char *fmt, ...)
 {
 	char *s;
 	va_list ap;
@@ -57,7 +60,7 @@ parser_parsef(struct tab *tab, const char *fmt, ...)
 	if (r == -1)
 		return 0;
 
-	r = parser_parse(tab, s, strlen(s));
+	r = parser_parse(buffer, s, strlen(s));
 	free(s);
 	return r;
 }
@@ -65,24 +68,26 @@ parser_parsef(struct tab *tab, const char *fmt, ...)
 int
 parser_free(struct tab *tab)
 {
-	struct parser	*p = &tab->buffer.page;
-	int		 r = 1;
-	char		*tilde, *slash;
+	struct buffer		*buffer = &tab->buffer;
+	struct parser		*p = buffer->parser;
+	int			 r = 1;
+	char			*tilde, *slash;
 
 	if (p->free) {
-		r = p->free(p);
-	} else if (p->len != 0) {
+		r = p->free(buffer);
+	} else if (buffer->len != 0) {
 		if (p->parse)
-			r = p->parse(p, p->buf, p->len);
+			r = p->parse(buffer, buffer->buf, buffer->len);
 		else
-			r = parser_foreach_line(p, p->buf, p->len);
+			r = parser_foreach_line(buffer, buffer->buf,
+			    buffer->len);
 	}
 
-	free(p->buf);
-	p->buf = NULL;
-	p->len = 0;
+	free(buffer->buf);
+	buffer->buf = NULL;
+	buffer->len = 0;
 
-	if (*p->title != '\0')
+	if (*buffer->title != '\0')
 		return r;
 
 	/*
@@ -90,28 +95,30 @@ parser_free(struct tab *tab)
 	 * page title, using the full domain name as fallback.
 	 */
 	if ((tilde = strstr(hist_cur(tab->hist), "/~")) != NULL) {
-		strlcpy(p->title, tilde+1, sizeof(p->title));
+		strlcpy(buffer->title, tilde+1, sizeof(buffer->title));
 
-		if ((slash = strchr(p->title, '/')) != NULL)
+		if ((slash = strchr(buffer->title, '/')) != NULL)
 			*slash = '\0';
 	} else
-		strlcpy(p->title, tab->iri.iri_host, sizeof(p->title));
+		strlcpy(buffer->title, tab->iri.iri_host,
+		    sizeof(buffer->title));
 
 	return r;
 }
 
 int
-parser_serialize(struct tab *tab, FILE *fp)
+parser_serialize(struct buffer *b, FILE *fp)
 {
+	struct parser	*p = b->parser;
 	struct line	*line;
 	const char	*text;
 	int		 r;
 
-	if (tab->buffer.page.serialize != NULL)
-		return tab->buffer.page.serialize(&tab->buffer.page, fp);
+	if (p->serialize != NULL)
+		return p->serialize(b, fp);
 
 	/* a default implementation good enough for plain text */
-	TAILQ_FOREACH(line, &tab->buffer.page.head, lines) {
+	TAILQ_FOREACH(line, &b->head, lines) {
 		if ((text = line->line) == NULL)
 			text = "";
 
@@ -124,31 +131,31 @@ parser_serialize(struct tab *tab, FILE *fp)
 }
 
 int
-parser_append(struct parser *p, const char *buf, size_t len)
+parser_append(struct buffer *b, const char *buf, size_t len)
 {
 	size_t newlen;
 	char *t;
 
-	newlen = len + p->len;
+	newlen = len + b->len;
 	if ((t = calloc(1, newlen)) == NULL)
 		return 0;
-	memcpy(t, p->buf, p->len);
-	memcpy(t + p->len, buf, len);
-	free(p->buf);
-	p->buf = t;
-	p->len = newlen;
+	memcpy(t, b->buf, b->len);
+	memcpy(t + b->len, buf, len);
+	free(b->buf);
+	b->buf = t;
+	b->len = newlen;
 	return 1;
 }
 
 int
-parser_set_buf(struct parser *p, const char *buf, size_t len)
+parser_set_buf(struct buffer *b, const char *buf, size_t len)
 {
 	char *tmp;
 
 	if (len == 0) {
-		p->len = 0;
-		free(p->buf);
-		p->buf = NULL;
+		b->len = 0;
+		free(b->buf);
+		b->buf = NULL;
 		return 1;
 	}
 
@@ -160,36 +167,37 @@ parser_set_buf(struct parser *p, const char *buf, size
 	if ((tmp = calloc(1, len)) == NULL)
 		return 0;
 	memcpy(tmp, buf, len);
-	free(p->buf);
-	p->buf = tmp;
-	p->len = len;
+	free(b->buf);
+	b->buf = tmp;
+	b->len = len;
 	return 1;
 }
 
 static int
-parser_foreach_line(struct parser *p, const char *buf, size_t size)
+parser_foreach_line(struct buffer *b, const char *buf, size_t size)
 {
-	char		*b, *e;
+	struct parser	*p = b->parser;
+	char		*beg, *end;
 	unsigned int	 ch;
 	size_t		 i, l, len;
 
-	if (!parser_append(p, buf, size))
+	if (!parser_append(b, buf, size))
 		return 0;
-	b = p->buf;
-	len = p->len;
+	beg = b->buf;
+	len = b->len;
 
-	if (!(p->flags & PARSER_IN_BODY) && len < 3)
+	if (!(b->parser_flags & PARSER_IN_BODY) && len < 3)
 		return 1;
 
-	if (!(p->flags & PARSER_IN_BODY)) {
-		p->flags |= PARSER_IN_BODY;
+	if (!(b->parser_flags & PARSER_IN_BODY)) {
+		b->parser_flags |= PARSER_IN_BODY;
 
 		/*
 		 * drop the BOM: only UTF-8 is supported, and there
 		 * it's useless; some editors may still add one
 		 * though.
 		 */
-		if (memmem(b, len, "\xEF\xBB\xBF", 3) == b) {
+		if (memmem(beg, len, "\xEF\xBB\xBF", 3) == beg) {
 			b += 3;
 			len -= 3;
 		}
@@ -197,33 +205,33 @@ parser_foreach_line(struct parser *p, const char *buf,
 
 	/* drop every "funny" ASCII character */
 	for (i = 0; i < len; ) {
-		ch = b[i];
+		ch = beg[i];
 		if ((ch >= ' ' || ch == '\n' || ch == '\t')
 		    && ch != 127) { /* del */
 			++i;
 			continue;
 		}
-		memmove(&b[i], &b[i+1], len - i - 1);
+		memmove(&beg[i], &beg[i+1], len - i - 1);
 		len--;
 	}
 
 	while (len > 0) {
-		if ((e = memmem((char*)b, len, "\n", 1)) == NULL)
+		if ((end = memmem((char*)beg, len, "\n", 1)) == NULL)
 			break;
-		l = e - b;
+		l = end - beg;
 
-		if (!p->parseline(p, b, l))
+		if (!p->parseline(b, beg, l))
 			return 0;
 
 		len -= l;
-		b += l;
+		beg += l;
 
 		if (len > 0) {
 			/* skip \n */
 			len--;
-			b++;
+			beg++;
 		}
 	}
 
-	return parser_set_buf(p, b, len);
+	return parser_set_buf(b, beg, len);
 }
blob - 9ee54b926e3370f157ddf1558fcbb2a2466cf902
blob + 0eac68fabed364415954fc82b90e8e820833e5bc
--- parser.h
+++ parser.h
@@ -17,29 +17,31 @@
 #ifndef PARSER_H
 #define PARSER_H
 
-#include "telescope.h"
+struct buffer;
+struct tab;
 
-typedef void (*parserfn)(struct parser *);
+struct parser {
+	const char	 *name;
+	int		  initflags;
 
-void	 parser_init(struct tab *, parserfn);
-int	 parser_parse(struct tab *, const char *, size_t);
-int	 parser_parsef(struct tab *, const char *, ...);
+	int		(*parse)(struct buffer *, const char *, size_t);
+	int		(*parseline)(struct buffer *, const char *, size_t);
+	int		(*free)(struct buffer *);
+	int		(*serialize)(struct buffer *, FILE *);
+};
+
+void	 parser_init(struct buffer *, struct parser *);
+int	 parser_parse(struct buffer *, const char *, size_t);
+int	 parser_parsef(struct buffer *, const char *, ...);
 int	 parser_free(struct tab *);
-int	 parser_serialize(struct tab *, FILE *);
+int	 parser_serialize(struct buffer *, FILE *);
 
-int	 parser_append(struct parser*, const char*, size_t);
-int	 parser_set_buf(struct parser*, const char*, size_t);
+int	 parser_append(struct buffer *, const char *, size_t);
+int	 parser_set_buf(struct buffer *, const char *, size_t);
 
-/* parser_gemtext.c */
-void	 gemtext_initparser(struct parser*);
+extern struct parser	 gemtext_parser;
+extern struct parser	 gophermap_parser;
+extern struct parser	 textpatch_parser;
+extern struct parser	 textplain_parser;
 
-/* parser_gophermap.c */
-void	 gophermap_initparser(struct parser *);
-
-/* parser_textpatch.c */
-void	 textpatch_initparser(struct parser *);
-
-/* parser_textplain.c */
-void	 textplain_initparser(struct parser*);
-
 #endif
blob - fe0e0dc3043977dba823f5063f72446d3e0c3a95
blob + ccab1ade5afda346a97b60e0408826b0cfd29088
--- parser_gemtext.c
+++ parser_gemtext.c
@@ -30,31 +30,26 @@
 
 #include "defaults.h"
 #include "parser.h"
+#include "telescope.h"
 #include "utf8.h"
 
-static int	gemtext_parse_line(struct parser *, const char *, size_t);
-static int	gemtext_free(struct parser *);
-static int	gemtext_serialize(struct parser *, FILE *);
+static int	gemtext_parse_line(struct buffer *, const char *, size_t);
+static int	gemtext_free(struct buffer *);
+static int	gemtext_serialize(struct buffer *, FILE *);
 
-static int	parse_link(struct parser *, const char*, size_t);
-static int	parse_title(struct parser *, const char*, size_t);
-static void	search_title(struct parser *, enum line_type);
+static int	parse_link(struct buffer *, const char*, size_t);
+static int	parse_title(struct buffer *, const char*, size_t);
+static void	search_title(struct buffer *, enum line_type);
 
-void
-gemtext_initparser(struct parser *p)
-{
-	memset(p, 0, sizeof(*p));
+struct parser gemtext_parser = {
+	.name = "text/gemini",
+	.parseline = &gemtext_parse_line,
+	.free = &gemtext_free,
+	.serialize = &gemtext_serialize,
+};
 
-	p->name = "text/gemini";
-	p->parseline = &gemtext_parse_line;
-	p->free  = &gemtext_free;
-	p->serialize = &gemtext_serialize;
-
-	TAILQ_INIT(&p->head);
-}
-
 static inline int
-emit_line(struct parser *p, enum line_type type, char *line, char *alt)
+emit_line(struct buffer *b, enum line_type type, char *line, char *alt)
 {
 	struct line *l;
 
@@ -90,26 +85,26 @@ emit_line(struct parser *p, enum line_type type, char 
 	if (dont_apply_styling)
 		l->flags &= ~L_HIDDEN;
 
-	TAILQ_INSERT_TAIL(&p->head, l, lines);
+	TAILQ_INSERT_TAIL(&b->head, l, lines);
 
 	return 1;
 }
 
 static int
-parse_link(struct parser *p, const char *line, size_t len)
+parse_link(struct buffer *b, const char *line, size_t len)
 {
 	char *label, *url;
 	const char *start;
 
 	if (len <= 2)
-		return emit_line(p, LINE_TEXT, NULL, NULL);
+		return emit_line(b, LINE_TEXT, NULL, NULL);
 
 	line += 2, len -= 2;
 	while (len > 0 && isspace((unsigned char)line[0]))
 		line++, len--;
 
 	if (len == 0)
-		return emit_line(p, LINE_TEXT, NULL, NULL);
+		return emit_line(b, LINE_TEXT, NULL, NULL);
 
 	start = line;
 	while (len > 0 && !isspace((unsigned char)line[0]))
@@ -129,11 +124,11 @@ parse_link(struct parser *p, const char *line, size_t 
 			return 0;
 	}
 
-	return emit_line(p, LINE_LINK, label, url);
+	return emit_line(b, LINE_LINK, label, url);
 }
 
 static int
-parse_title(struct parser *p, const char *line, size_t len)
+parse_title(struct buffer *b, const char *line, size_t len)
 {
 	enum line_type t = LINE_TITLE_1;
 	char *l;
@@ -150,36 +145,36 @@ parse_title(struct parser *p, const char *line, size_t
 		line++, len--;
 
 	if (len == 0)
-		return emit_line(p, t, NULL, NULL);
+		return emit_line(b, t, NULL, NULL);
 
-	if (t == LINE_TITLE_1 && *p->title == '\0')
-		strncpy(p->title, line, MIN(sizeof(p->title)-1, len));
+	if (t == LINE_TITLE_1 && *b->title == '\0')
+		strncpy(b->title, line, MIN(sizeof(b->title)-1, len));
 
 	if ((l = strndup(line, len)) == NULL)
 		return 0;
-	return emit_line(p, t, l, NULL);
+	return emit_line(b, t, l, NULL);
 }
 
 static int
-gemtext_parse_line(struct parser *p, const char *line, size_t len)
+gemtext_parse_line(struct buffer *b, const char *line, size_t len)
 {
 	char *l;
 
-	if (p->flags & PARSER_IN_PRE) {
+	if (b->parser_flags & PARSER_IN_PRE) {
 		if (len >= 3 && !strncmp(line, "```", 3)) {
-			p->flags ^= PARSER_IN_PRE;
-			return emit_line(p, LINE_PRE_END, NULL, NULL);
+			b->parser_flags ^= PARSER_IN_PRE;
+			return emit_line(b, LINE_PRE_END, NULL, NULL);
 		}
 
 		if (len == 0)
-			return emit_line(p, LINE_PRE_CONTENT, NULL, NULL);
+			return emit_line(b, LINE_PRE_CONTENT, NULL, NULL);
 		if ((l = strndup(line, len)) == NULL)
 			return 0;
-		return emit_line(p, LINE_PRE_CONTENT, l, NULL);
+		return emit_line(b, LINE_PRE_CONTENT, l, NULL);
 	}
 
 	if (len == 0)
-		return emit_line(p, LINE_TEXT, NULL, NULL);
+		return emit_line(b, LINE_TEXT, NULL, NULL);
 
 	switch (*line) {
 	case '*':
@@ -190,59 +185,59 @@ gemtext_parse_line(struct parser *p, const char *line,
 		while (len > 0 && isspace((unsigned char)*line))
 			line++, len--;
 		if (len == 0)
-			return emit_line(p, LINE_ITEM, NULL, NULL);
+			return emit_line(b, LINE_ITEM, NULL, NULL);
 		if ((l = strndup(line, len)) == NULL)
 			return 0;
-		return emit_line(p, LINE_ITEM, l, NULL);
+		return emit_line(b, LINE_ITEM, l, NULL);
 
 	case '>':
 		line++, len--;
 		while (len > 0 && isspace((unsigned char)*line))
 			line++, len--;
 		if (len == 0)
-			return emit_line(p, LINE_QUOTE, NULL, NULL);
+			return emit_line(b, LINE_QUOTE, NULL, NULL);
 		if ((l = strndup(line, len)) == NULL)
 			return 0;
-		return emit_line(p, LINE_QUOTE, l, NULL);
+		return emit_line(b, LINE_QUOTE, l, NULL);
 
 	case '=':
 		if (len > 1 && line[1] == '>')
-			return parse_link(p, line, len);
+			return parse_link(b, line, len);
 		break;
 
 	case '#':
-		return parse_title(p, line, len);
+		return parse_title(b, line, len);
 
 	case '`':
 		if (len < 3 || strncmp(line, "```", 3) != 0)
 			break;
 
-		p->flags |= PARSER_IN_PRE;
+		b->parser_flags |= PARSER_IN_PRE;
 		line += 3, len -= 3;
 		while (len > 0 && isspace((unsigned char)*line))
 			line++, len--;
 		if (len == 0)
-			return emit_line(p, LINE_PRE_START,
+			return emit_line(b, LINE_PRE_START,
 			    NULL, NULL);
 		if ((l = strndup(line, len)) == NULL)
 			return 0;
-		return emit_line(p, LINE_PRE_START, l, NULL);
+		return emit_line(b, LINE_PRE_START, l, NULL);
 	}
 
 	if ((l = strndup(line, len)) == NULL)
 		return 0;
-	return emit_line(p, LINE_TEXT, l, NULL);
+	return emit_line(b, LINE_TEXT, l, NULL);
 }
 
 static int
-gemtext_free(struct parser *p)
+gemtext_free(struct buffer *b)
 {
 	/* flush the buffer */
-	if (p->len != 0) {
-		if (!gemtext_parse_line(p, p->buf, p->len))
+	if (b->len != 0) {
+		if (!gemtext_parse_line(b, b->buf, b->len))
 			return 0;
-		if ((p->flags & PARSER_IN_PRE) &&
-		    !emit_line(p, LINE_PRE_END, NULL, NULL))
+		if ((b->parser_flags & PARSER_IN_PRE) &&
+		    !emit_line(b, LINE_PRE_END, NULL, NULL))
 			return 0;
 	}
 
@@ -250,24 +245,24 @@ gemtext_free(struct parser *p)
 	 * use the first level 2 or 3 header as page title if none
 	 * found yet.
 	 */
-	if (*p->title == '\0')
-		search_title(p, LINE_TITLE_2);
-	if (*p->title == '\0')
-		search_title(p, LINE_TITLE_3);
+	if (*b->title == '\0')
+		search_title(b, LINE_TITLE_2);
+	if (*b->title == '\0')
+		search_title(b, LINE_TITLE_3);
 
 	return 1;
 }
 
 static void
-search_title(struct parser *p, enum line_type level)
+search_title(struct buffer *b, enum line_type level)
 {
 	struct line *l;
 
-	TAILQ_FOREACH(l, &p->head, lines) {
+	TAILQ_FOREACH(l, &b->head, lines) {
 		if (l->type == level) {
 			if (l->line == NULL)
 				continue;
-			strlcpy(p->title, l->line, sizeof(p->title));
+			strlcpy(b->title, l->line, sizeof(b->title));
 			break;
 		}
 	}
@@ -286,14 +281,14 @@ static const char *gemtext_prefixes[] = {
 };
 
 static int
-gemtext_serialize(struct parser *p, FILE *fp)
+gemtext_serialize(struct buffer *b, FILE *fp)
 {
 	struct line	*line;
 	const char	*text;
 	const char	*alt;
 	int		 r;
 
-	TAILQ_FOREACH(line, &p->head, lines) {
+	TAILQ_FOREACH(line, &b->head, lines) {
 		if ((text = line->line) == NULL)
 			text = "";
 
blob - 6e951cadd8be59d8108eb6c9052b287e250ad451
blob + 8c9d0ec372c899409d2ce5a72c7d19c84e3deda0
--- parser_gophermap.c
+++ parser_gophermap.c
@@ -20,8 +20,9 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "parser.h"
 #include "iri.h"
+#include "parser.h"
+#include "telescope.h"
 #include "utils.h"
 
 #ifndef LINE_MAX
@@ -38,20 +39,14 @@ struct gm_selector {
 
 static void	gm_parse_selector(char *, struct gm_selector *);
 
-static int	gm_parse_line(struct parser *, const char *, size_t);
-static int	gm_serialize(struct parser *, FILE *);
+static int	gm_parse_line(struct buffer *, const char *, size_t);
+static int	gm_serialize(struct buffer *, FILE *);
 
-void
-gophermap_initparser(struct parser *p)
-{
-	memset(p, 0, sizeof(*p));
-
-	p->name = "gophermap";
-	p->parseline = &gm_parse_line;
-	p->serialize = &gm_serialize;
-
-	TAILQ_INIT(&p->head);
-}
+struct parser gophermap_parser = {
+	.name = "gophermap",
+	.parseline = &gm_parse_line,
+	.serialize = &gm_serialize,
+};
 
 static void
 gm_parse_selector(char *line, struct gm_selector *s)
@@ -94,7 +89,7 @@ selector2uri(struct gm_selector *s, char *buf, size_t 
 }
 
 static inline int
-emit_line(struct parser *p, enum line_type type, struct gm_selector *s)
+emit_line(struct buffer *b, enum line_type type, struct gm_selector *s)
 {
 	struct line *l;
 	char buf[LINE_MAX];
@@ -120,7 +115,7 @@ emit_line(struct parser *p, enum line_type type, struc
 		break;
 	}
 
-	TAILQ_INSERT_TAIL(&p->head, l, lines);
+	TAILQ_INSERT_TAIL(&b->head, l, lines);
 
 	return 1;
 
@@ -134,7 +129,7 @@ err:
 }
 
 static int
-gm_parse_line(struct parser *p, const char *line, size_t linelen)
+gm_parse_line(struct buffer *b, const char *line, size_t linelen)
 {
 	char buf[LINE_MAX] = {0};
 	struct gm_selector s = {0};
@@ -161,17 +156,17 @@ gm_parse_line(struct parser *p, const char *line, size
 	case 'd':	/* non-canonical: doc */
 	case 'h':	/* non-canonical: html file */
 	case 's':	/* non-canonical: sound file */
-		if (!emit_line(p, LINE_LINK, &s))
+		if (!emit_line(b, LINE_LINK, &s))
 			return 0;
 		break;
 
 	case 'i':	/* non-canonical: message */
-		if (!emit_line(p, LINE_TEXT, &s))
+		if (!emit_line(b, LINE_TEXT, &s))
 			return 0;
 		break;
 
 	case '3':	/* error code */
-		if (!emit_line(p, LINE_QUOTE, &s))
+		if (!emit_line(b, LINE_QUOTE, &s))
 			return 0;
 		break;
 	}
@@ -254,13 +249,13 @@ serialize_link(struct line *line, const char *text, FI
 }
 
 static int
-gm_serialize(struct parser *p, FILE *fp)
+gm_serialize(struct buffer *b, FILE *fp)
 {
 	struct line	*line;
 	const char	*text;
 	int		 r;
 
-	TAILQ_FOREACH(line, &p->head, lines) {
+	TAILQ_FOREACH(line, &b->head, lines) {
 		if ((text = line->line) == NULL)
 			text = "";
 
blob - 509eb9750e8073134721617555126699eb403f64
blob + 677a8d446f05d855f392f515d096d910a10a3d9e
--- parser_textpatch.c
+++ parser_textpatch.c
@@ -24,33 +24,27 @@
 #include <string.h>
 
 #include "parser.h"
+#include "telescope.h"
 #include "utils.h"
 
-static int	tpatch_emit_line(struct parser *, const char *, size_t);
-static int	tpatch_parse_line(struct parser *, const char *, size_t);
+static int	tpatch_emit_line(struct buffer *, const char *, size_t);
+static int	tpatch_parse_line(struct buffer *, const char *, size_t);
 
-void
-textpatch_initparser(struct parser *p)
-{
-	memset(p, 0, sizeof(*p));
+struct parser textpatch_parser = {
+	.name = "text/x-patch",
+	.parseline = &tpatch_parse_line,
+	.initflags = PARSER_IN_PATCH_HDR,
+};
 
-	p->name = "text/x-patch";
-	p->parseline = &tpatch_parse_line;
-
-	p->flags = PARSER_IN_PATCH_HDR;
-
-	TAILQ_INIT(&p->head);
-}
-
 static int
-tpatch_emit_line(struct parser *p, const char *line, size_t linelen)
+tpatch_emit_line(struct buffer *b, const char *line, size_t linelen)
 {
 	struct line *l;
 
 	if ((l = calloc(1, sizeof(*l))) == NULL)
 		return 0;
 
-	if (p->flags & PARSER_IN_PATCH_HDR)
+	if (b->parser_flags & PARSER_IN_PATCH_HDR)
 		l->type = LINE_PATCH_HDR;
 	else
 		l->type = LINE_PATCH;
@@ -63,7 +57,7 @@ tpatch_emit_line(struct parser *p, const char *line, s
 
 		memcpy(l->line, line, linelen);
 
-		if (!(p->flags & PARSER_IN_PATCH_HDR))
+		if (!(b->parser_flags & PARSER_IN_PATCH_HDR))
 			switch (*l->line) {
 			case '+':
 				l->type = LINE_PATCH_ADD;
@@ -84,21 +78,21 @@ tpatch_emit_line(struct parser *p, const char *line, s
 				 * than one file.
 				 */
 				l->type = LINE_PATCH_HDR;
-				p->flags |= PARSER_IN_PATCH_HDR;
+				b->parser_flags |= PARSER_IN_PATCH_HDR;
 				break;
 			}
 
 		if (!strncmp(l->line, "+++", 3))
-			p->flags &= ~PARSER_IN_PATCH_HDR;
+			b->parser_flags &= ~PARSER_IN_PATCH_HDR;
 	}
 
-	TAILQ_INSERT_TAIL(&p->head, l, lines);
+	TAILQ_INSERT_TAIL(&b->head, l, lines);
 
 	return 1;
 }
 
 static int
-tpatch_parse_line(struct parser *p, const char *line, size_t linelen)
+tpatch_parse_line(struct buffer *b, const char *line, size_t linelen)
 {
-	return tpatch_emit_line(p, line, linelen);
+	return tpatch_emit_line(b, line, linelen);
 }
blob - 5158068417703854a2dd0fd02b72d9aa20717937
blob + c516f4a24a997ad28535976e391732f755b652e1
--- parser_textplain.c
+++ parser_textplain.c
@@ -24,11 +24,17 @@
 #include <string.h>
 
 #include "parser.h"
+#include "telescope.h"
 
-static int	textplain_parse_line(struct parser*, const char*, size_t);
+static int	textplain_parse_line(struct buffer *, const char *, size_t);
 
+struct parser textplain_parser = {
+	.name = "text/plain",
+	.parseline = &textplain_parse_line,
+};
+
 static inline int
-emit_line(struct parser *p, const char *line, size_t len)
+emit_line(struct buffer *b, const char *line, size_t len)
 {
 	struct line *l;
 
@@ -46,24 +52,13 @@ emit_line(struct parser *p, const char *line, size_t l
 		memcpy(l->line, line, len);
 	}
 
-	TAILQ_INSERT_TAIL(&p->head, l, lines);
+	TAILQ_INSERT_TAIL(&b->head, l, lines);
 
 	return 1;
 }
 
-void
-textplain_initparser(struct parser *p)
-{
-	memset(p, 0, sizeof(*p));
-
-	p->name = "text/plain";
-	p->parseline = &textplain_parse_line;
-
-	TAILQ_INIT(&p->head);
-}
-
 static int
-textplain_parse_line(struct parser *p, const char *line, size_t linelen)
+textplain_parse_line(struct buffer *b, const char *line, size_t linelen)
 {
-	return emit_line(p, line, linelen);
+	return emit_line(b, line, linelen);
 }
blob - 65d38ce297b8bf1f42564a8d08e53b3b33d3bd9c
blob + bed2d3e5578f38695e8bf6c97905898e363d76b5
--- session.c
+++ session.c
@@ -80,7 +80,7 @@ new_tab(const char *url, const char *base, struct tab 
 	}
 
 	TAILQ_INIT(&tab->buffer.head);
-	TAILQ_INIT(&tab->buffer.page.head);
+	TAILQ_INIT(&tab->buffer.vhead);
 
 	tab->id = tab_new_id();
 
@@ -187,7 +187,7 @@ savetab(FILE *fp, struct tab *tab, int killed)
 		fprintf(fp, "killed,");
 
 	fprintf(fp, "top=%zu,cur=%zu %s\n", top_line, current_line,
-	    tab->buffer.page.title);
+	    tab->buffer.title);
 
 	cur = hist_off(tab->hist);
 	size = hist_size(tab->hist);
@@ -598,7 +598,7 @@ parse_tab_line(char *line, struct tab **ct)
 	if ((tab = new_tab(uri, NULL, NULL)) == NULL)
 		err(1, "new_tab");
 	hist_set_offs(tab->hist, tline, cline);
-	strlcpy(tab->buffer.page.title, title, sizeof(tab->buffer.page.title));
+	strlcpy(tab->buffer.title, title, sizeof(tab->buffer.title));
 
 	if (current)
 		*ct = tab;
blob - f09c9ded06f3ae03d9b9b7d6b0c8d2e27a05511f
blob + 317fa406cdd33452a6af50f2b4406942791fffcb
--- telescope.c
+++ telescope.c
@@ -45,6 +45,7 @@
 #include "mcache.h"
 #include "minibuffer.h"
 #include "parser.h"
+#include "parser.h"
 #include "session.h"
 #include "telescope.h"
 #include "tofu.h"
@@ -506,7 +507,7 @@ handle_dispatch_imsg(int fd, int event, void *data)
 				return;
 
 			if (tab) {
-				if (!parser_parse(tab, imsg.data,
+				if (!parser_parse(&tab->buffer, imsg.data,
 				    imsg_get_len(&imsg)))
 					die();
 				ui_on_tab_refresh(tab);
@@ -614,7 +615,7 @@ load_finger_url(struct tab *tab, const char *url)
 	}
 	strlcat(req.req, "\r\n", sizeof(req.req));
 
-	parser_init(tab, textplain_initparser);
+	parser_init(&tab->buffer, &textplain_parser);
 	make_request(tab, &req, PROTO_FINGER, NULL);
 }
 
@@ -673,10 +674,10 @@ load_gopher_url(struct tab *tab, const char *url)
 	path = gopher_skip_selector(tab->iri.iri_path, &type);
 	switch (type) {
 	case '0':
-		parser_init(tab, textplain_initparser);
+		parser_init(&tab->buffer, &textplain_parser);
 		break;
 	case '1':
-		parser_init(tab, gophermap_initparser);
+		parser_init(&tab->buffer, &gophermap_parser);
 		break;
 	case '7':
 		free(tab->last_input_url);
@@ -769,7 +770,7 @@ gopher_send_search_req(struct tab *tab, const char *te
 	strlcat(req.req, "\r\n", sizeof(req.req));
 
 	erase_buffer(&tab->buffer);
-	parser_init(tab, gophermap_initparser);
+	parser_init(&tab->buffer, &gophermap_parser);
 
 	make_request(tab, &req, PROTO_GOPHER, NULL);
 }
@@ -777,8 +778,8 @@ gopher_send_search_req(struct tab *tab, const char *te
 void
 load_page_from_str(struct tab *tab, const char *page)
 {
-	parser_init(tab, gemtext_initparser);
-	if (!parser_parse(tab, page, strlen(page)))
+	parser_init(&tab->buffer, &gemtext_parser);
+	if (!parser_parse(&tab->buffer, page, strlen(page)))
 		abort();
 	if (!parser_free(tab))
 		abort();
@@ -867,8 +868,7 @@ load_url(struct tab *tab, const char *url, const char 
 			return;
 		}
 
-		strlcpy(tab->buffer.page.title, url,
-		    sizeof(tab->buffer.page.title));
+		strlcpy(tab->buffer.title, url, sizeof(tab->buffer.title));
 	}
 
 	if (!lazy)
@@ -921,7 +921,7 @@ write_buffer(const char *path, struct tab *tab)
 
 	if ((fp = fopen(path, "w")) == NULL)
 		return;
-	if (!parser_serialize(tab, fp))
+	if (!parser_serialize(&tab->buffer, fp))
 		message("Failed to save the page.");
 	fclose(fp);
 }
blob - 90515f65cd29ee80b8dfcf1cfc0f0989627a913b
blob + d6f56be2990aa0037fc88e9091cdec9895b751aa
--- telescope.h
+++ telescope.h
@@ -89,35 +89,6 @@ struct vline {
 	TAILQ_ENTRY(vline)	 vlines;
 };
 
-struct parser;
-
-typedef void	(*parserinit)(struct parser *);
-
-typedef int	(*parsechunkfn)(struct parser *, const char *, size_t);
-typedef int	(*parselinefn)(struct parser *, const char *, size_t);
-typedef int	(*parserfreefn)(struct parser *);
-typedef int	(*parserserial)(struct parser *, FILE *);
-
-struct parser {
-	const char	*name;
-	char		 title[128+1];
-	char		*buf;
-	size_t		 len;
-	size_t		 cap;
-
-#define PARSER_IN_BODY	1
-#define PARSER_IN_PRE	2
-#define PARSER_IN_PATCH_HDR 4
-	int		 flags;
-	parserinit	 init;
-	parsechunkfn	 parse;
-	parselinefn	 parseline;
-	parserfreefn	 free;
-	parserserial	 serialize;
-
-	TAILQ_HEAD(, line)	 head;
-};
-
 /*
  * different types of trust for a certificate.  Following
  * gemini://thfr.info/gemini/modified-trust-verify.gmi
@@ -130,9 +101,21 @@ enum trust_state {
 	TS_VERIFIED,
 };
 
+struct parser;
+
 struct buffer {
-	struct parser		 page;
+	char			 title[128 + 1];
+	const char		*mode;
+	char			*buf;
+	size_t			 len;
+	size_t			 cap;
 
+#define PARSER_IN_BODY	1
+#define PARSER_IN_PRE	2
+#define PARSER_IN_PATCH_HDR 4
+	int			 parser_flags;
+	struct parser		*parser;
+
 	size_t			 last_line_off;
 	int			 force_redraw;
 
@@ -143,7 +126,9 @@ struct buffer {
 	struct vline		*top_line;
 	struct vline		*current_line;
 	size_t			 cpoff;
-	TAILQ_HEAD(vhead, vline) head;
+
+	TAILQ_HEAD(, line)	 head;
+	TAILQ_HEAD(vhead, vline) vhead;
 };
 
 #define TAB_CURRENT	0x1	/* only for save_session */
blob - 96ee617abc23624ea778b3e78e9935c9e7375fe8
blob + 98f140024281b30cd2ab0085e907fc006b7be7ae
--- ui.c
+++ ui.c
@@ -35,7 +35,6 @@
 #include <sys/time.h>
 #include <sys/wait.h>
 
-#include <assert.h>
 #include <curses.h>
 #include <errno.h>
 #include <locale.h>
@@ -144,8 +143,8 @@ set_scroll_position(struct tab *tab, size_t top, size_
 	size_t i = 0;
 	int topfound = 0;
 
-	last = TAILQ_FIRST(&tab->buffer.page.head);
-	TAILQ_FOREACH(vl, &tab->buffer.head, vlines) {
+	last = TAILQ_FIRST(&tab->buffer.head);
+	TAILQ_FOREACH(vl, &tab->buffer.vhead, vlines) {
 		if (last != vl->parent) {
 			last = vl->parent;
 			i++;
@@ -163,7 +162,7 @@ set_scroll_position(struct tab *tab, size_t top, size_
 	}
 
 	if (!topfound)
-		tab->buffer.top_line = TAILQ_FIRST(&tab->buffer.head);
+		tab->buffer.top_line = TAILQ_FIRST(&tab->buffer.vhead);
 
 	tab->buffer.current_line = tab->buffer.top_line;
 }
@@ -181,7 +180,7 @@ get_scroll_position(struct tab *tab, size_t *top, size
 	    tab->buffer.current_line == NULL)
 		return;
 
-	TAILQ_FOREACH(l, &tab->buffer.page.head, lines) {
+	TAILQ_FOREACH(l, &tab->buffer.head, lines) {
 		if (tab->buffer.top_line->parent == l)
 			topfound = 1;
 		if (tab->buffer.current_line->parent == l)
@@ -226,7 +225,7 @@ restore_curs_x(struct buffer *buffer)
 		lp = raw_prefixes;
 
 	vl = buffer->current_line;
-	if (vl == NULL || vl->len == 0)
+	if (vl == NULL || vl->len == 0 || vl->parent == NULL)
 		buffer->curs_x = buffer->cpoff = 0;
 	else if (vl->parent->data != NULL) {
 		text = vl->parent->data;
@@ -661,7 +660,7 @@ redraw_tabline(void)
 
 		current = tab == current_tab;
 
-		if (*(title = tab->buffer.page.title) == '\0')
+		if (*(title = tab->buffer.title) == '\0')
 			title = hist_cur(tab->hist);
 
 		if (tab->flags & TAB_URGENT)
@@ -756,7 +755,7 @@ again:
 		goto end;
 
 	if (buffer->top_line == NULL)
-		buffer->top_line = TAILQ_FIRST(&buffer->head);
+		buffer->top_line = TAILQ_FIRST(&buffer->vhead);
 
 	buffer->top_line = adjust_line(buffer->top_line, buffer);
 	if (buffer->top_line == NULL)
@@ -852,7 +851,7 @@ redraw_modeline(struct tab *tab)
 	const char	*spin = "-\\|/";
 
 	buffer = current_buffer();
-	mode = buffer->page.name;
+	mode = buffer->mode;
 
 	werase(modeline);
 	wattr_on(modeline, modeline_face.background, NULL);
@@ -1057,7 +1056,7 @@ redraw_tab(struct tab *tab)
 
 	if (set_title)
 		dprintf(1, "\033]2;%s - Telescope\a",
-		    current_tab->buffer.page.title);
+		    current_tab->buffer.title);
 }
 
 void
@@ -1124,11 +1123,11 @@ ui_init(void)
 
 	/* initialize download window */
 	TAILQ_INIT(&downloadwin.head);
-	TAILQ_INIT(&downloadwin.page.head);
+	TAILQ_INIT(&downloadwin.vhead);
 
 	/* initialize help window */
 	TAILQ_INIT(&helpwin.head);
-	TAILQ_INIT(&helpwin.page.head);
+	TAILQ_INIT(&helpwin.vhead);
 
 	base_map = &global_map;
 	current_map = &global_map;
@@ -1206,7 +1205,7 @@ ui_on_tab_loaded(struct tab *tab)
 
 	hist_cur_offs(tab->hist, &line_off, &curr_off);
 	if (curr_off != 0 &&
-	    tab->buffer.current_line == TAILQ_FIRST(&tab->buffer.head)) {
+	    tab->buffer.current_line == TAILQ_FIRST(&tab->buffer.vhead)) {
 		set_scroll_position(tab, line_off, curr_off);
 		redraw_tab(tab);
 		return;
blob - d86351e71dc259ed782b0251ba92d069e6cc4f82
blob + 2a58e03514ae257ca15008d70eedece728b428c0
--- wrap.c
+++ wrap.c
@@ -39,8 +39,8 @@ empty_linelist(struct buffer *buffer)
 {
 	struct line *l, *lt;
 
-	TAILQ_FOREACH_SAFE(l, &buffer->page.head, lines, lt) {
-		TAILQ_REMOVE(&buffer->page.head, l, lines);
+	TAILQ_FOREACH_SAFE(l, &buffer->head, lines, lt) {
+		TAILQ_REMOVE(&buffer->head, l, lines);
 		free(l->line);
 
 		if (l->type != LINE_COMPL &&
@@ -62,8 +62,8 @@ empty_vlist(struct buffer *buffer)
 	buffer->current_line = NULL;
 	buffer->line_max = 0;
 
-	TAILQ_FOREACH_SAFE(vl, &buffer->head, vlines, t) {
-		TAILQ_REMOVE(&buffer->head, vl, vlines);
+	TAILQ_FOREACH_SAFE(vl, &buffer->vhead, vlines, t) {
+		TAILQ_REMOVE(&buffer->vhead, vl, vlines);
 		free(vl);
 	}
 }
@@ -96,7 +96,7 @@ push_line(struct buffer *buffer, struct line *l, const
 	}
 	vl->flags = flags;
 
-	TAILQ_INSERT_TAIL(&buffer->head, vl, vlines);
+	TAILQ_INSERT_TAIL(&buffer->vhead, vl, vlines);
 	return 1;
 }
 
@@ -174,7 +174,7 @@ wrap_page(struct buffer *buffer, int width)
 
 	empty_vlist(buffer);
 
-	TAILQ_FOREACH(l, &buffer->page.head, lines) {
+	TAILQ_FOREACH(l, &buffer->head, lines) {
 		prfx = line_prefixes[l->type].prfx1;
 		switch (l->type) {
 		case LINE_TEXT:
@@ -210,7 +210,7 @@ wrap_page(struct buffer *buffer, int width)
 
 		if (top_orig == l && buffer->top_line == NULL) {
 			buffer->line_off = buffer->line_max-1;
-			buffer->top_line = TAILQ_LAST(&buffer->head, vhead);
+			buffer->top_line = TAILQ_LAST(&buffer->vhead, vhead);
 
 			while (1) {
 				vl = TAILQ_PREV(buffer->top_line, vhead, vlines);
@@ -222,7 +222,7 @@ wrap_page(struct buffer *buffer, int width)
 		}
 
 		if (orig == l && buffer->current_line == NULL) {
-			buffer->current_line = TAILQ_LAST(&buffer->head, vhead);
+			buffer->current_line = TAILQ_LAST(&buffer->vhead, vhead);
 
 			while (1) {
 				vl = TAILQ_PREV(buffer->current_line, vhead, vlines);
@@ -234,7 +234,7 @@ wrap_page(struct buffer *buffer, int width)
 	}
 
 	if (buffer->current_line == NULL)
-		buffer->current_line = TAILQ_FIRST(&buffer->head);
+		buffer->current_line = TAILQ_FIRST(&buffer->vhead);
 
 	if (buffer->top_line == NULL)
 		buffer->top_line = buffer->current_line;