aboutsummaryrefslogtreecommitdiff
path: root/viz.c
diff options
context:
space:
mode:
Diffstat (limited to 'viz.c')
-rw-r--r--viz.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/viz.c b/viz.c
new file mode 100644
index 0000000..c133156
--- /dev/null
+++ b/viz.c
@@ -0,0 +1,158 @@
+/*
+ * viz.c - Visualize matches.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "types.h"
+#include "viz.h"
+
+
+/*
+static size_t utf8_len(const char *s)
+{
+ size_t len = 0;
+ while (*s) {
+ len += (*s++ & 0xC0) != 0x80;
+ }
+ return len;
+}
+*/
+
+static int match_height(match_t *m)
+{
+ int height = 0;
+ for (match_t *c = m->child; c; c = c->nextsibling) {
+ int childheight = match_height(c);
+ if (childheight > height) height = childheight;
+ }
+ return 1 + height;
+}
+
+static void _visualize_matches(match_node_t *firstmatch, int depth, const char *text, size_t textlen)
+{
+ if (!firstmatch) return;
+
+ const char *V = "│"; // Vertical bar
+ const char *H = "─"; // Horizontal bar
+ const char *color = (depth % 2 == 0) ? "34" : "33";
+
+ match_t *viz = firstmatch->m;
+ for (match_node_t *p = firstmatch; p; p = p->next)
+ if (match_height(p->m) > match_height(viz))
+ viz = p->m;
+ const char *viz_type = viz->op->start;
+ size_t viz_typelen = (size_t)(viz->op->end - viz->op->start);
+
+ printf("\033[%ldG\033[%s;1m", 2*textlen+3, color);
+ for (size_t i = 0; i < viz_typelen; i++) {
+ switch (viz_type[i]) {
+ case '\n': printf("↵"); break;
+ default: printf("%c", viz_type[i]); break;
+ }
+ }
+ printf("\033[0m");
+
+ match_node_t *children = NULL;
+ match_node_t **nextchild = &children;
+
+#define RIGHT_TYPE(m) (m->m->op->end == m->m->op->start + viz_typelen && strncmp(m->m->op->start, viz_type, viz_typelen) == 0)
+ // Print nonzero-width first:
+ for (match_node_t *m = firstmatch; m; m = m->next) {
+ //tree_text = byteslice(text, tree['start'], tree['end']).replace('\n', '↵')
+ if (RIGHT_TYPE(m)) {
+ //if (m->m->op->op != VM_REF) {
+ for (match_t *c = m->m->child; c; c = c->nextsibling) {
+ *nextchild = calloc(1, sizeof(match_node_t));
+ (*nextchild)->m = c;
+ nextchild = &((*nextchild)->next);
+ }
+ //}
+ if (m->m->end == m->m->start) continue;
+ printf("\033[%ldG\033[0;2m%s\033[0;7;%sm", 1+2*(m->m->start - text), V, color);
+ for (const char *c = m->m->start; c < m->m->end; ++c) {
+ // TODO: newline
+ if (c > m->m->start) printf(" ");
+ // TODO: utf8
+ //while ((*c & 0xC0) != 0x80) printf("%c", *(c++));
+ printf("%c", *c);
+ }
+ printf("\033[0;2m%s\033[0m", V);
+ } else {
+ *nextchild = calloc(1, sizeof(match_node_t));
+ (*nextchild)->m = m->m;
+ nextchild = &((*nextchild)->next);
+ printf("\033[%ldG\033[0;2m%s", 1+2*(m->m->start - text), V);
+ for (ssize_t i = (ssize_t)(2*(m->m->end - m->m->start)-1); i > 0; i--)
+ printf(" ");
+ if (m->m->end > m->m->start)
+ printf("\033[0;2m%s", V);
+ printf("\033[0m");
+ }
+ }
+
+ // Print stars for zero-width:
+ for (match_node_t *m = firstmatch; m; m = m->next) {
+ if (m->m->end > m->m->start) continue;
+ if (RIGHT_TYPE(m)) {
+ printf("\033[%ldG\033[7;%sm▒\033[0m", 1+2*(m->m->start - text), color);
+ } else {
+ printf("\033[%ldG\033[0;2m%s\033[0m", 1+2*(m->m->start - text), V);
+ }
+ }
+
+ printf("\n");
+
+ for (match_node_t *m = firstmatch; m; m = m->next) {
+ if (m->m->end == m->m->start) {
+ if (!RIGHT_TYPE(m))
+ printf("\033[%ldG\033[0;2m%s", 1 + 2*(m->m->start - text), V);
+ } else {
+ const char *l = "└";
+ const char *r = "┘";
+ for (match_node_t *c = children; c; c = c->next) {
+ if (c->m->start == m->m->start || c->m->end == m->m->start) l = V;
+ if (c->m->start == m->m->end || c->m->end == m->m->end) r = V;
+ }
+ printf("\033[%ldG\033[0;2m%s", 1 + 2*(m->m->start - text), l);
+ const char *h = RIGHT_TYPE(m) ? H : " ";
+ for (ssize_t n = (ssize_t)(2*(m->m->end - m->m->start) - 1); n > 0; n--)
+ printf("%s", h);
+ printf("%s\033[0m", r);
+ }
+ }
+#undef RIGHT_TYPE
+
+ printf("\n");
+
+ if (children)
+ _visualize_matches(children, depth+1, text, textlen);
+
+ for (match_node_t *c = children, *next = NULL; c; c = next) {
+ next = c->next;
+ free(c);
+ }
+}
+
+static void _visualize_patterns(match_t *m)
+{
+ if (m->op->op == VM_REF && strcmp(m->op->args.s, "pattern") == 0) {
+ m = m->child;
+ match_node_t first = {.m = m};
+ _visualize_matches(&first, 0, m->start, (size_t)(m->end - m->start));
+ } else {
+ for (match_t *c = m->child; c; c = c->nextsibling)
+ _visualize_patterns(c);
+ }
+}
+
+void visualize_match(match_t *m)
+{
+ printf("\033[?7l");
+ //match_node_t first = {.m = m};
+ //_visualize_matches(&first, 0, m->start, (m->end - m->start));
+ _visualize_patterns(m);
+ printf("\033[?7h");
+}