aboutsummaryrefslogtreecommitdiff
path: root/src/visualizer/grid.c
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-13 00:31:48 +0200
committerhachem <im@hachem.wtf>2026-09-13 00:31:48 +0200
commit220532b4818aadf7948ceaa9056d68b530dc38d1 (patch)
tree49edab04c259139721ee6cdd1b8250aacdf02d28 /src/visualizer/grid.c
parentc5cca4cb708cb10bb3143c57d161e75f85fea88f (diff)
feat: circuit visualizer
Diffstat (limited to 'src/visualizer/grid.c')
-rw-r--r--src/visualizer/grid.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/visualizer/grid.c b/src/visualizer/grid.c
new file mode 100644
index 0000000..5f95efc
--- /dev/null
+++ b/src/visualizer/grid.c
@@ -0,0 +1,136 @@
+#include "visualizer/grid.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+static size_t glyph_bytes(unsigned char lead)
+{
+ if (lead < 0x80)
+ return 1;
+ if ((lead >> 5) == 0x6)
+ return 2;
+ if ((lead >> 4) == 0xE)
+ return 3;
+ if ((lead >> 3) == 0x1E)
+ return 4;
+
+ return 1;
+}
+
+size_t psi_utf8_count(const char *s)
+{
+ size_t count = 0;
+ while (*s)
+ {
+ s += glyph_bytes((unsigned char)*s);
+ count++;
+ }
+
+ return count;
+}
+
+struct PsiStringBuilder psi_new_string_builder(void)
+{
+ return (struct PsiStringBuilder)
+ {
+ NULL,
+ 0,
+ 0,
+ };
+}
+
+void psi_string_builder_append(struct PsiStringBuilder *sb, const char *s)
+{
+ size_t n = strlen(s);
+ if (sb->len + n + 1 > sb->cap)
+ {
+ size_t new_cap = sb->cap == 0 ? 256 : sb->cap * 2;
+ while (new_cap < sb->len + n + 1)
+ new_cap *= 2;
+
+ sb->data = realloc(sb->data, new_cap);
+ assert(sb->data != NULL);
+ sb->cap = new_cap;
+ }
+
+ memcpy(sb->data + sb->len, s, n + 1);
+ sb->len += n;
+}
+
+char *psi_string_builder_finish(struct PsiStringBuilder *sb)
+{
+ if (sb->data == NULL)
+ psi_string_builder_append(sb, "");
+
+ return sb->data;
+}
+
+struct PsiGlyphRow psi_new_glyph_row(size_t width)
+{
+ char (*cells)[5] = malloc(width * sizeof(*cells));
+ assert(cells != NULL || width == 0);
+
+ for (size_t i = 0; i < width; i++)
+ memcpy(cells[i], " ", 2);
+
+ return (struct PsiGlyphRow)
+ {
+ cells,
+ width,
+ };
+}
+
+void psi_free_glyph_row(struct PsiGlyphRow *row)
+{
+ free(row->cells);
+ row->cells = NULL;
+ row->width = 0;
+}
+
+void psi_glyph_row_set(struct PsiGlyphRow *row, size_t index, const char *glyph)
+{
+ if (index >= row->width)
+ return;
+
+ size_t n = glyph_bytes((unsigned char)glyph[0]);
+ memcpy(row->cells[index], glyph, n);
+ row->cells[index][n] = '\0';
+}
+
+size_t psi_glyph_row_place(struct PsiGlyphRow *row, size_t start, const char *utf8)
+{
+ size_t count = 0;
+ const char *p = utf8;
+
+ while (*p)
+ {
+ size_t n = glyph_bytes((unsigned char)*p);
+ size_t index = start + count;
+ if (index < row->width)
+ {
+ memcpy(row->cells[index], p, n);
+ row->cells[index][n] = '\0';
+ }
+
+ p += n;
+ count++;
+ }
+
+ return count;
+}
+
+void psi_glyph_row_fill_space(struct PsiGlyphRow *row, size_t from, size_t to, const char *glyph)
+{
+ for (size_t i = from; i < to && i < row->width; i++)
+ if (strcmp(row->cells[i], " ") == 0)
+ psi_glyph_row_set(row, i, glyph);
+}
+
+void psi_glyph_row_render(struct PsiGlyphRow row, struct PsiStringBuilder *sb)
+{
+ for (size_t i = 0; i < row.width; i++)
+ psi_string_builder_append(sb, row.cells[i]);
+
+ psi_string_builder_append(sb, "\n");
+}