aboutsummaryrefslogtreecommitdiff
path: root/src/visualizer/grid.c
blob: 5f95efcb81b90df2aaf8cd34497f9c3b5d4219c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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");
}