summary refs log tree commit diff
path: root/doc.c
diff options
context:
space:
mode:
Diffstat (limited to 'doc.c')
-rw-r--r--doc.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/doc.c b/doc.c
new file mode 100644
index 0000000..3478f8b
--- /dev/null
+++ b/doc.c
@@ -0,0 +1,143 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "doc.h"
+#include "err.h"
+
+/* text */
+
+static struct {
+	char *buf;
+	size_t len, cap;
+} txt;
+
+void txt_init(void) {
+	txt.buf = malloc(1);
+	if (!txt.buf) efatal("txt_init");
+	txt.buf[0] = 0;
+	txt.len = 0;
+	txt.cap = 1;
+}
+
+void txt_fini(void) {
+	free(txt.buf);
+}
+
+void txt_grow(size_t n) {
+	size_t cap = txt.cap;
+	size_t len = txt.len + n;
+	if (cap < len) {
+		while (cap < len) cap <<= 1;
+		char *s = realloc(txt.buf, cap);
+		if (!s) efatal("txt_grow");
+		txt.cap = cap;
+		txt.buf = s;
+	}
+}
+
+/* docs */
+
+struct doc {
+	size_t ofs, len, idx;
+};
+
+#define DOC_MAX 32
+
+static struct doc docv[DOC_MAX] = {
+	{
+		 
+		.ofs = 0,
+		.len = 0,
+		.idx = 0
+	}
+};
+
+static size_t docn = 0, doci = 0;
+
+void doc_pop(void) {
+	if (docn > 0) {
+		docn--;
+		if (doci > 0) doci--;
+	}
+}
+
+void doc_shift(void) {
+	if (docn > 0) {
+		docn--;
+		memmove(txt.buf, txt.buf + docv[0].len, txt.len - docv[0].len);
+		memmove(&docv[0], &docv[1], docn * sizeof(struct doc));
+		docv[0].ofs = 0;
+		for (int i = 1; i < docn; i++) {
+			docv[i].idx = docv[i - 1].ofs + (docv[i].idx - docv[i].ofs);
+			docv[i].ofs = docv[i - 1].ofs + docv[i - 1].len;
+		}
+		if (docn > 0 && doci >= docn) doci = docn - 1;
+	}
+}
+
+void doc_new(void) {
+	while (docn >= DOC_MAX) {
+		doc_shift();
+	}
+	if (doci < docn) {
+		txt.len = docv[doci].ofs;
+		docn = doci;
+	}
+	memset(&docv[docn], 0, sizeof(struct doc));
+	docv[docn].ofs = txt.len;
+	docv[docn].idx = txt.len;
+	doci = docn++;
+}
+
+void doc_add(const char *buf, size_t n) {
+	txt_grow(n);
+	memcpy(&txt.buf[txt.len], buf, n);
+	txt.len += n;
+	docv[doci].len += n;
+}
+
+void doc_adds(const char *s) {
+	doc_add(s, strlen(s));
+}
+
+void doc_prev(void) {
+	if (doci > 0) doci--;
+}
+
+void doc_next(void) {
+	if (doci < docn) doci++;
+}
+
+void doc_back_line(void) {
+	if (doci >= docn) return;
+	struct doc *d = &docv[doci];
+	size_t i = d->idx;
+	while (i > 0 && txt.buf[d->idx] != '\n') i--;
+	if (i > 0) i--;
+	while (i > 0 && txt.buf[d->idx] != '\n') i--;
+	if (i > 0) i++;
+	d->idx = i;
+}
+
+void doc_print_line(void) {
+	if (doci >= docn) return;
+	struct doc *d = &docv[doci];
+	size_t i = d->idx;
+	size_t n = d->ofs + d->len;
+	while (i < n && txt.buf[d->idx] != '\n') {
+		putchar(txt.buf[i++]);
+	}
+	if (i < n) i++;
+	d->idx = i;
+}
+
+void doc_init(void) {
+	txt_init();
+	doc_new();
+	doc_adds("Type ? for command help.\n");
+}
+
+void doc_fini(void) {
+	txt_fini();
+}