hokusai-zero 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Dockerfile +26 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +91 -0
- data/LICENSE +21 -0
- data/README.md +28 -0
- data/ast/genheader +3 -0
- data/ast/include/hashmap.c +1151 -0
- data/ast/include/hashmap.c.license +20 -0
- data/ast/include/hashmap.h +54 -0
- data/ast/src/core/ast.c +448 -0
- data/ast/src/core/ast.h +259 -0
- data/ast/src/core/common.h +24 -0
- data/ast/src/core/component.c +85 -0
- data/ast/src/core/component.h +35 -0
- data/ast/src/core/hml.c +665 -0
- data/ast/src/core/hml.h +11 -0
- data/ast/src/core/input.c +458 -0
- data/ast/src/core/input.h +118 -0
- data/ast/src/core/style.c +101 -0
- data/ast/src/core/style.h +41 -0
- data/ast/src/core/text.c +784 -0
- data/ast/src/core/text.h +93 -0
- data/ast/src/core/util.c +140 -0
- data/ast/src/core/util.h +48 -0
- data/ast/src/hokusai.c +6 -0
- data/ast/src/hokusai.h +6 -0
- data/ast/test/fixtures/test.ui +13 -0
- data/ast/test/greatest.h +1266 -0
- data/ast/test/hokusai.c +14 -0
- data/ast/test/parser.c +234 -0
- data/ast/test/text.c +116 -0
- data/ext/extconf.rb +27 -0
- data/grammar/Cargo.lock +80 -0
- data/grammar/Cargo.toml +26 -0
- data/grammar/binding.gyp +20 -0
- data/grammar/bindings/node/binding.cc +28 -0
- data/grammar/bindings/node/index.js +19 -0
- data/grammar/bindings/rust/build.rs +40 -0
- data/grammar/bindings/rust/lib.rs +52 -0
- data/grammar/corpus/1_document.txt +131 -0
- data/grammar/corpus/2_selectors.txt +58 -0
- data/grammar/corpus/3_spaces.txt +69 -0
- data/grammar/corpus/4_errors.txt +10 -0
- data/grammar/corpus/5_macros.txt +175 -0
- data/grammar/corpus/6_styles.txt +81 -0
- data/grammar/grammar.js +275 -0
- data/grammar/package-lock.json +34 -0
- data/grammar/package.json +33 -0
- data/grammar/src/grammar.json +1269 -0
- data/grammar/src/node-types.json +474 -0
- data/grammar/src/parser.c +5772 -0
- data/grammar/src/scanner.c +258 -0
- data/grammar/src/tree_sitter/parser.h +230 -0
- data/grammar/src/tree_sitter/scanner.h +12 -0
- data/grammar/test.nml +10 -0
- data/hokusai.gemspec +19 -0
- data/ui/examples/assets/DigitalDisplay.ttf +0 -0
- data/ui/examples/assets/OpenSans-Regular.ttf +0 -0
- data/ui/examples/assets/addy.png +0 -0
- data/ui/examples/assets/baby_sean.png +0 -0
- data/ui/examples/assets/football-troll.png +0 -0
- data/ui/examples/assets/gear.png +0 -0
- data/ui/examples/assets/icecold.ttf +0 -0
- data/ui/examples/assets/science-troll.png +0 -0
- data/ui/examples/buddy.rb +31 -0
- data/ui/examples/clock.rb +58 -0
- data/ui/examples/counter.rb +123 -0
- data/ui/examples/dynamic.rb +147 -0
- data/ui/examples/foobar.rb +236 -0
- data/ui/examples/stock.rb +115 -0
- data/ui/examples/stock_decider/option.rb +74 -0
- data/ui/examples/tic_tac_toe.rb +246 -0
- data/ui/lib/lib_hokusai.rb +425 -0
- data/ui/spec/hokusai/ast_spec.rb +88 -0
- data/ui/spec/hokusai/automation/keys_transcoder_spec.rb +50 -0
- data/ui/spec/hokusai/automation/selector_spec.rb +68 -0
- data/ui/spec/hokusai/block_spec.rb +126 -0
- data/ui/spec/hokusai/directives_spec.rb +327 -0
- data/ui/spec/hokusai/e2e/client_spec.rb +58 -0
- data/ui/spec/hokusai/e2e/meta_spec.rb +42 -0
- data/ui/spec/hokusai/publisher_spec.rb +38 -0
- data/ui/spec/hokusai/slots_spec.rb +150 -0
- data/ui/spec/hokusai/util/piece_table_spec.rb +90 -0
- data/ui/spec/hokusai_spec.rb +0 -0
- data/ui/spec/spec_helper.rb +30 -0
- data/ui/src/hokusai/ast.rb +446 -0
- data/ui/src/hokusai/automation/client.rb +167 -0
- data/ui/src/hokusai/automation/constants.rb +98 -0
- data/ui/src/hokusai/automation/converters/selector_converter.rb +61 -0
- data/ui/src/hokusai/automation/driver.rb +54 -0
- data/ui/src/hokusai/automation/driver_command_queue.rb +50 -0
- data/ui/src/hokusai/automation/driver_commands/base.rb +79 -0
- data/ui/src/hokusai/automation/driver_commands/get_attribute.rb +41 -0
- data/ui/src/hokusai/automation/driver_commands/invoke.rb +33 -0
- data/ui/src/hokusai/automation/driver_commands/locate.rb +48 -0
- data/ui/src/hokusai/automation/driver_commands/trigger_keyboard.rb +94 -0
- data/ui/src/hokusai/automation/driver_commands/trigger_mouse.rb +213 -0
- data/ui/src/hokusai/automation/keys_transcoder.rb +128 -0
- data/ui/src/hokusai/automation/selector.rb +39 -0
- data/ui/src/hokusai/automation/server.rb +114 -0
- data/ui/src/hokusai/automation.rb +3 -0
- data/ui/src/hokusai/backends/raylib/config.rb +47 -0
- data/ui/src/hokusai/backends/raylib/font.rb +113 -0
- data/ui/src/hokusai/backends/raylib/keys.rb +124 -0
- data/ui/src/hokusai/backends/raylib.rb +449 -0
- data/ui/src/hokusai/backends/sdl2/Monaco.ttf +0 -0
- data/ui/src/hokusai/backends/sdl2/color.rb +12 -0
- data/ui/src/hokusai/backends/sdl2/config.rb +31 -0
- data/ui/src/hokusai/backends/sdl2/font.rb +127 -0
- data/ui/src/hokusai/backends/sdl2/keys.rb +119 -0
- data/ui/src/hokusai/backends/sdl2.rb +529 -0
- data/ui/src/hokusai/block.rb +237 -0
- data/ui/src/hokusai/blocks/button.rb +100 -0
- data/ui/src/hokusai/blocks/checkbox.rb +51 -0
- data/ui/src/hokusai/blocks/circle.rb +28 -0
- data/ui/src/hokusai/blocks/clipped.rb +23 -0
- data/ui/src/hokusai/blocks/cursor.rb +49 -0
- data/ui/src/hokusai/blocks/dynamic.rb +37 -0
- data/ui/src/hokusai/blocks/empty.rb +10 -0
- data/ui/src/hokusai/blocks/hblock.rb +35 -0
- data/ui/src/hokusai/blocks/image.rb +18 -0
- data/ui/src/hokusai/blocks/input.rb +200 -0
- data/ui/src/hokusai/blocks/label.rb +39 -0
- data/ui/src/hokusai/blocks/panel.rb +126 -0
- data/ui/src/hokusai/blocks/rect.rb +24 -0
- data/ui/src/hokusai/blocks/scissor_begin.rb +18 -0
- data/ui/src/hokusai/blocks/scissor_end.rb +12 -0
- data/ui/src/hokusai/blocks/scrollbar.rb +103 -0
- data/ui/src/hokusai/blocks/selectable.rb +77 -0
- data/ui/src/hokusai/blocks/svg.rb +20 -0
- data/ui/src/hokusai/blocks/text.rb +214 -0
- data/ui/src/hokusai/blocks/titlebar/osx.rb +145 -0
- data/ui/src/hokusai/blocks/toggle.rb +55 -0
- data/ui/src/hokusai/blocks/vblock.rb +35 -0
- data/ui/src/hokusai/commands/base.rb +22 -0
- data/ui/src/hokusai/commands/circle.rb +47 -0
- data/ui/src/hokusai/commands/image.rb +45 -0
- data/ui/src/hokusai/commands/rect.rb +158 -0
- data/ui/src/hokusai/commands/scissor.rb +22 -0
- data/ui/src/hokusai/commands/text.rb +92 -0
- data/ui/src/hokusai/commands.rb +87 -0
- data/ui/src/hokusai/diff.rb +124 -0
- data/ui/src/hokusai/error.rb +3 -0
- data/ui/src/hokusai/event.rb +54 -0
- data/ui/src/hokusai/events/keyboard.rb +84 -0
- data/ui/src/hokusai/events/mouse.rb +172 -0
- data/ui/src/hokusai/font.rb +280 -0
- data/ui/src/hokusai/meta.rb +152 -0
- data/ui/src/hokusai/mounting/loop_entry.rb +230 -0
- data/ui/src/hokusai/mounting/mount_entry.rb +74 -0
- data/ui/src/hokusai/mounting/update_entry.rb +101 -0
- data/ui/src/hokusai/node.rb +98 -0
- data/ui/src/hokusai/node_mounter.rb +102 -0
- data/ui/src/hokusai/painter.rb +214 -0
- data/ui/src/hokusai/publisher.rb +32 -0
- data/ui/src/hokusai/style.rb +72 -0
- data/ui/src/hokusai/types.rb +266 -0
- data/ui/src/hokusai/util/clamping_iterator.rb +202 -0
- data/ui/src/hokusai/util/piece_table.rb +111 -0
- data/ui/src/hokusai/util/selection.rb +145 -0
- data/ui/src/hokusai.rb +120 -0
- data/ui/vendor/.gitkeep +0 -0
- data/vendor/.gitkeep +0 -0
- data/xmake.lua +192 -0
- metadata +222 -0
data/ast/src/core/text.c
ADDED
@@ -0,0 +1,784 @@
|
|
1
|
+
#ifndef HOKU_TEXT
|
2
|
+
#define HOKU_TEXT
|
3
|
+
|
4
|
+
#include "text.h"
|
5
|
+
|
6
|
+
int hoku_text_char_init(hoku_char** character, int offset, int width)
|
7
|
+
{
|
8
|
+
hoku_char* init = malloc(sizeof(hoku_char));
|
9
|
+
if (init == NULL) return -1;
|
10
|
+
|
11
|
+
init->offset = offset;
|
12
|
+
init->width = width;
|
13
|
+
init->next_char = NULL;
|
14
|
+
|
15
|
+
*character = init;
|
16
|
+
|
17
|
+
return 0;
|
18
|
+
}
|
19
|
+
|
20
|
+
int hoku_text_segment_init(hoku_segment** segment, int offset)
|
21
|
+
{
|
22
|
+
hoku_segment* init = malloc(sizeof(hoku_segment));
|
23
|
+
if (init == NULL) return -1;
|
24
|
+
|
25
|
+
init->offset = offset;
|
26
|
+
init->chars = NULL;
|
27
|
+
init->groups = NULL;
|
28
|
+
init->size = 0;
|
29
|
+
init->select_begin = 0;
|
30
|
+
init->select_end = 0;
|
31
|
+
init->next_segment = NULL;
|
32
|
+
|
33
|
+
*segment = init;
|
34
|
+
|
35
|
+
return 0;
|
36
|
+
}
|
37
|
+
|
38
|
+
int hoku_text_clamping_init(hoku_clamping** clamping, char* text, float width)
|
39
|
+
{
|
40
|
+
hoku_clamping* init = malloc(sizeof(hoku_clamping));
|
41
|
+
if (init == NULL) return -1;
|
42
|
+
init->text = strdup(text);
|
43
|
+
if (init->text == NULL) return -1;
|
44
|
+
init->width = width;
|
45
|
+
init->segments = NULL;
|
46
|
+
|
47
|
+
*clamping = init;
|
48
|
+
|
49
|
+
return 0;
|
50
|
+
}
|
51
|
+
|
52
|
+
hoku_char* hoku_text_segment_split(hoku_segment* segment, int at)
|
53
|
+
{
|
54
|
+
hoku_segment* head = segment;
|
55
|
+
hoku_char* current_char = head->chars;
|
56
|
+
if (at > head->size) return NULL;
|
57
|
+
|
58
|
+
printf("at: %d\n", at);
|
59
|
+
int i = 0;
|
60
|
+
for (i = 1; i < at; i++)
|
61
|
+
{
|
62
|
+
printf("%d- %d\n", i, head->size);
|
63
|
+
if (current_char == NULL) printf("BADDD\n");
|
64
|
+
current_char = current_char->next_char;
|
65
|
+
}
|
66
|
+
|
67
|
+
hoku_segment* insert;
|
68
|
+
if (hoku_text_segment_init(&insert, head->offset + at) != 0) return NULL;
|
69
|
+
|
70
|
+
if (current_char) insert->chars = current_char->next_char;
|
71
|
+
insert->size = head->size - at;
|
72
|
+
insert->select_begin = 0;
|
73
|
+
insert->select_end = 0;
|
74
|
+
insert->next_segment = head->next_segment;
|
75
|
+
head->next_segment = insert;
|
76
|
+
head->size = at;
|
77
|
+
if (current_char) current_char->next_char = NULL;
|
78
|
+
|
79
|
+
printf("split ret\n");
|
80
|
+
return current_char;
|
81
|
+
// return insert;
|
82
|
+
}
|
83
|
+
|
84
|
+
void hoku_text_char_free(hoku_char* chars)
|
85
|
+
{
|
86
|
+
hoku_char* head;
|
87
|
+
|
88
|
+
while (chars)
|
89
|
+
{
|
90
|
+
head = chars;
|
91
|
+
chars = chars->next_char;
|
92
|
+
free(head);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
void hoku_text_group_free(hoku_group* group)
|
97
|
+
{
|
98
|
+
hoku_group* head;
|
99
|
+
while (group)
|
100
|
+
{
|
101
|
+
hoku_text_char_free(group->chars);
|
102
|
+
|
103
|
+
// if (group->payload != NULL) free(group->payload);
|
104
|
+
|
105
|
+
head = group;
|
106
|
+
group = group->next_group;
|
107
|
+
free(head);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
void hoku_text_segment_free(hoku_segment* segment)
|
112
|
+
{
|
113
|
+
hoku_segment* head;
|
114
|
+
while (segment)
|
115
|
+
{
|
116
|
+
hoku_text_group_free(segment->groups);
|
117
|
+
hoku_text_char_free(segment->chars);
|
118
|
+
head = segment;
|
119
|
+
segment = segment->next_segment;
|
120
|
+
free(head);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
124
|
+
void hoku_text_clamping_free(hoku_clamping* clamping)
|
125
|
+
{
|
126
|
+
hoku_text_segment_free(clamping->segments);
|
127
|
+
free(clamping->text);
|
128
|
+
free(clamping);
|
129
|
+
}
|
130
|
+
|
131
|
+
int hoku_text_select(hoku_clamping* clamping, int begin, int end)
|
132
|
+
{
|
133
|
+
return 0;
|
134
|
+
}
|
135
|
+
|
136
|
+
float hoku_text_char_sum(hoku_char* character)
|
137
|
+
{
|
138
|
+
float width = 0.0;
|
139
|
+
|
140
|
+
while (character != NULL)
|
141
|
+
{
|
142
|
+
width += character->width;
|
143
|
+
character = character->next_char;
|
144
|
+
}
|
145
|
+
|
146
|
+
return width;
|
147
|
+
}
|
148
|
+
|
149
|
+
void hoku_text_clamp_debug(hoku_clamping* clamp)
|
150
|
+
{
|
151
|
+
printf("clamping:\n");
|
152
|
+
hoku_segment* seg = clamp->segments;
|
153
|
+
while (seg)
|
154
|
+
{
|
155
|
+
printf("\tseg: %d %d\n", seg->offset, seg->size);
|
156
|
+
|
157
|
+
hoku_group* g = seg->groups;
|
158
|
+
while (g)
|
159
|
+
{
|
160
|
+
printf("\t\tgroup: (%d..%d)", g->offset, g->size);
|
161
|
+
|
162
|
+
|
163
|
+
if (g->type & HOKU_GROUP_NORMAL) printf(" NORMAL");
|
164
|
+
if (g->type & HOKU_GROUP_BOLD) printf(" BOLD");
|
165
|
+
if (g->type & HOKU_GROUP_ITALICS) printf(" ITALICS");
|
166
|
+
if (g->type & HOKU_GROUP_LINK) printf(" LINK (%s)", (char*) g->payload);
|
167
|
+
|
168
|
+
printf("\n");
|
169
|
+
hoku_char* c = g->chars;
|
170
|
+
|
171
|
+
while (c)
|
172
|
+
{
|
173
|
+
printf("\t\t\tchar (%c): %d %d\n", clamp->text[c->offset], c->offset, c->width);
|
174
|
+
c = c->next_char;
|
175
|
+
}
|
176
|
+
|
177
|
+
g = g->next_group;
|
178
|
+
}
|
179
|
+
|
180
|
+
hoku_char* c = seg->chars;
|
181
|
+
|
182
|
+
while (c)
|
183
|
+
{
|
184
|
+
printf("\t\tchar (%c): %d %d\n", clamp->text[c->offset], c->offset, c->width);
|
185
|
+
c = c->next_char;
|
186
|
+
}
|
187
|
+
|
188
|
+
seg = seg->next_segment;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
typedef struct HokuMdState
|
193
|
+
{
|
194
|
+
float width;
|
195
|
+
int total_offset;
|
196
|
+
float line_width;
|
197
|
+
void* char_width_payload;
|
198
|
+
hoku_char_width_cb char_width_callback;
|
199
|
+
hoku_segment* root_segment;
|
200
|
+
enum HOKU_GROUP_TYPE current_group_type;
|
201
|
+
hoku_segment* current_segment;
|
202
|
+
hoku_group* current_group;
|
203
|
+
hoku_char* current_char;
|
204
|
+
void* current_group_payload;
|
205
|
+
char* parsed;
|
206
|
+
int parsed_len;
|
207
|
+
int parsed_counter;
|
208
|
+
} hoku_md_state;
|
209
|
+
|
210
|
+
|
211
|
+
int hoku_text_md_append(hoku_md_state* userdata, const char* text, int size)
|
212
|
+
{
|
213
|
+
if (userdata->parsed_counter + size >= userdata->parsed_len)
|
214
|
+
{
|
215
|
+
int plen = size + 200 + userdata->parsed_len;
|
216
|
+
char* tmp = realloc(userdata->parsed, sizeof(char) * plen);
|
217
|
+
if (tmp == NULL) return -1;
|
218
|
+
userdata->parsed = tmp;
|
219
|
+
userdata->parsed_len += size + 200;
|
220
|
+
}
|
221
|
+
|
222
|
+
strncat(userdata->parsed, text, size);
|
223
|
+
userdata->parsed_counter += size;
|
224
|
+
return 0;
|
225
|
+
}
|
226
|
+
|
227
|
+
int hoku_text_md_enter_block(MD_BLOCKTYPE type, void* detail, void* data)
|
228
|
+
{
|
229
|
+
// printf("enter block\n");
|
230
|
+
return 0;
|
231
|
+
|
232
|
+
}
|
233
|
+
|
234
|
+
int hoku_text_md_leave_block(MD_BLOCKTYPE type, void* detail, void* data)
|
235
|
+
{
|
236
|
+
hoku_md_state* userdata = (hoku_md_state*) data;
|
237
|
+
|
238
|
+
if (userdata->current_group == NULL) return 0;
|
239
|
+
|
240
|
+
for (int i=0; i < 2; i++)
|
241
|
+
{
|
242
|
+
// make a new segment
|
243
|
+
hoku_segment* next;
|
244
|
+
if (hoku_text_segment_init(&next, userdata->total_offset + 1) != 0) return -1;
|
245
|
+
|
246
|
+
// make a new group
|
247
|
+
hoku_group* group;
|
248
|
+
if (hoku_text_group_init(&group, userdata->total_offset + 1, HOKU_GROUP_NORMAL, NULL) != 0) return -1;
|
249
|
+
|
250
|
+
next->groups = group;
|
251
|
+
|
252
|
+
// init a char
|
253
|
+
hoku_char* insert;
|
254
|
+
if (hoku_text_char_init(&insert, userdata->total_offset, 0) != 0) return -1;
|
255
|
+
|
256
|
+
hoku_text_group_append_char(group, insert);
|
257
|
+
next->size += 1;
|
258
|
+
group->size += 1;
|
259
|
+
userdata->total_offset += 1;
|
260
|
+
|
261
|
+
userdata->current_segment->next_segment = next;
|
262
|
+
userdata->current_segment = next;
|
263
|
+
}
|
264
|
+
|
265
|
+
userdata->current_group = NULL;
|
266
|
+
if (hoku_text_md_append(userdata, "\n\n", 2) != 0) return -1;
|
267
|
+
// printf("parsed: %s\n", userdata->parsed);
|
268
|
+
// printf("leave block\n");
|
269
|
+
return 0;
|
270
|
+
}
|
271
|
+
|
272
|
+
int hoku_text_md_enter_span(MD_SPANTYPE type, void* detail, void* data)
|
273
|
+
{
|
274
|
+
hoku_md_state* userdata = (hoku_md_state*) data;
|
275
|
+
|
276
|
+
// printf("enter span\n");
|
277
|
+
switch(type)
|
278
|
+
{
|
279
|
+
case MD_SPAN_EM:
|
280
|
+
{
|
281
|
+
userdata->current_group_type = userdata->current_group_type | HOKU_GROUP_ITALICS;
|
282
|
+
break;
|
283
|
+
}
|
284
|
+
case MD_SPAN_STRONG:
|
285
|
+
{
|
286
|
+
userdata->current_group_type = userdata->current_group_type | HOKU_GROUP_BOLD;
|
287
|
+
break;
|
288
|
+
}
|
289
|
+
case MD_SPAN_U:
|
290
|
+
{
|
291
|
+
|
292
|
+
}
|
293
|
+
case MD_SPAN_A:
|
294
|
+
{
|
295
|
+
userdata->current_group_type = userdata->current_group_type | HOKU_GROUP_LINK;
|
296
|
+
|
297
|
+
MD_ATTRIBUTE href = ((MD_SPAN_A_DETAIL*) detail)->href;
|
298
|
+
char* link = strndup(href.text, href.size);
|
299
|
+
userdata->current_group_payload = link;
|
300
|
+
|
301
|
+
break;
|
302
|
+
}
|
303
|
+
case MD_SPAN_IMG:
|
304
|
+
{
|
305
|
+
userdata->current_group_type = userdata->current_group_type | HOKU_GROUP_IMAGE;
|
306
|
+
break;
|
307
|
+
}
|
308
|
+
case MD_SPAN_CODE:
|
309
|
+
{
|
310
|
+
userdata->current_group_type = userdata->current_group_type | HOKU_GROUP_CODE;
|
311
|
+
break;
|
312
|
+
}
|
313
|
+
}
|
314
|
+
return 0;
|
315
|
+
}
|
316
|
+
|
317
|
+
int hoku_text_md_leave_span(MD_SPANTYPE type, void* detail, void* data)
|
318
|
+
{
|
319
|
+
hoku_md_state* userdata = (hoku_md_state*) data;
|
320
|
+
|
321
|
+
// printf("leave span\n");
|
322
|
+
switch(type)
|
323
|
+
{
|
324
|
+
case MD_SPAN_EM:
|
325
|
+
{
|
326
|
+
userdata->current_group_type = userdata->current_group_type & ~HOKU_GROUP_ITALICS;
|
327
|
+
break;
|
328
|
+
}
|
329
|
+
case MD_SPAN_STRONG:
|
330
|
+
{
|
331
|
+
userdata->current_group_type = userdata->current_group_type & ~HOKU_GROUP_BOLD;
|
332
|
+
break;
|
333
|
+
}
|
334
|
+
case MD_SPAN_U:
|
335
|
+
{
|
336
|
+
|
337
|
+
}
|
338
|
+
case MD_SPAN_A:
|
339
|
+
{
|
340
|
+
userdata->current_group_type = userdata->current_group_type & ~HOKU_GROUP_LINK;
|
341
|
+
userdata->current_group_payload = NULL;
|
342
|
+
break;
|
343
|
+
}
|
344
|
+
case MD_SPAN_IMG:
|
345
|
+
{
|
346
|
+
userdata->current_group_type = userdata->current_group_type & ~HOKU_GROUP_IMAGE;
|
347
|
+
break;
|
348
|
+
}
|
349
|
+
case MD_SPAN_CODE:
|
350
|
+
{
|
351
|
+
userdata->current_group_type = userdata->current_group_type & ~HOKU_GROUP_CODE;
|
352
|
+
break;
|
353
|
+
}
|
354
|
+
}
|
355
|
+
return 0;
|
356
|
+
}
|
357
|
+
int hoku_text_group_init(hoku_group** group, int offset, enum HOKU_GROUP_TYPE type, void* payload)
|
358
|
+
{
|
359
|
+
hoku_group* init = malloc(sizeof(hoku_group));
|
360
|
+
if (init == NULL) return -1;
|
361
|
+
|
362
|
+
init->offset = offset;
|
363
|
+
init->size = 0;
|
364
|
+
init->type = type;
|
365
|
+
init->chars = NULL;
|
366
|
+
init->next_group = NULL;
|
367
|
+
init->payload = payload;
|
368
|
+
|
369
|
+
*group = init;
|
370
|
+
|
371
|
+
return 0;
|
372
|
+
}
|
373
|
+
|
374
|
+
void hoku_text_group_append_char(hoku_group* group, hoku_char* character)
|
375
|
+
{
|
376
|
+
hoku_char* head = group->chars;
|
377
|
+
|
378
|
+
if (head == NULL)
|
379
|
+
{
|
380
|
+
group->chars = character;
|
381
|
+
}
|
382
|
+
else
|
383
|
+
{
|
384
|
+
while (head->next_char != NULL)
|
385
|
+
{
|
386
|
+
head = head->next_char;
|
387
|
+
}
|
388
|
+
|
389
|
+
head->next_char = character;
|
390
|
+
}
|
391
|
+
}
|
392
|
+
|
393
|
+
int hoku_text_md_text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* data)
|
394
|
+
{
|
395
|
+
hoku_md_state* userdata = (hoku_md_state*) data;
|
396
|
+
// we always cut a new group / char here...
|
397
|
+
hoku_group* new_group;
|
398
|
+
if (hoku_text_group_init(&new_group, userdata->total_offset, userdata->current_group_type, userdata->current_group_payload) != 0) return -1;
|
399
|
+
|
400
|
+
if (userdata->current_group == NULL)
|
401
|
+
{
|
402
|
+
userdata->current_group = new_group;
|
403
|
+
userdata->current_segment->groups = userdata->current_group;
|
404
|
+
}
|
405
|
+
else
|
406
|
+
{
|
407
|
+
userdata->current_group->next_group = new_group;
|
408
|
+
userdata->current_group = userdata->current_group->next_group;
|
409
|
+
}
|
410
|
+
|
411
|
+
hoku_char* current_char = NULL;
|
412
|
+
|
413
|
+
int i = 0;
|
414
|
+
|
415
|
+
while (i < size)
|
416
|
+
{
|
417
|
+
char letter = text[i];
|
418
|
+
int letter_width = (int) userdata->char_width_callback(letter, userdata->char_width_payload);
|
419
|
+
// printf("callback complete\n");
|
420
|
+
/*
|
421
|
+
Part 1, clamp new segment if the total_width is greater than boundary
|
422
|
+
*/
|
423
|
+
if ((userdata->line_width + letter_width) > userdata->width)
|
424
|
+
{
|
425
|
+
// printf("part 1: '%c'\n", letter);
|
426
|
+
userdata->line_width = 0.0;
|
427
|
+
// make a new segment
|
428
|
+
hoku_segment* segment;
|
429
|
+
if (hoku_text_segment_init(&segment, userdata->total_offset) != 0) return -1;
|
430
|
+
|
431
|
+
// make a new group
|
432
|
+
hoku_group* group;
|
433
|
+
if (hoku_text_group_init(&group, userdata->total_offset, userdata->current_group_type, userdata->current_group_payload) != 0) return -1;
|
434
|
+
|
435
|
+
// init a char
|
436
|
+
hoku_char* ichar;
|
437
|
+
if (hoku_text_char_init(&ichar, userdata->total_offset, letter_width) != 0) return -1;
|
438
|
+
|
439
|
+
group->chars = ichar;
|
440
|
+
segment->groups = group;
|
441
|
+
group->size += 1;
|
442
|
+
segment->size += 1;
|
443
|
+
|
444
|
+
// append to the segment list and reset current
|
445
|
+
userdata->current_segment->next_segment = segment;
|
446
|
+
userdata->current_segment = segment;
|
447
|
+
// printf("set current segment %p\n", userdata->current_segment);
|
448
|
+
|
449
|
+
userdata->current_group = group;
|
450
|
+
|
451
|
+
current_char = ichar;
|
452
|
+
|
453
|
+
userdata->line_width = (float) letter_width;
|
454
|
+
userdata->total_offset += 1;
|
455
|
+
i += 1;
|
456
|
+
continue;
|
457
|
+
}
|
458
|
+
|
459
|
+
/*
|
460
|
+
Part 2, clamp new segment on newline
|
461
|
+
*/
|
462
|
+
switch(letter)
|
463
|
+
{
|
464
|
+
case '\n':
|
465
|
+
{
|
466
|
+
// printf("part 2, new line\n");
|
467
|
+
// make a new segment
|
468
|
+
hoku_segment* next;
|
469
|
+
if (hoku_text_segment_init(&next, userdata->total_offset + 1) != 0) return -1;
|
470
|
+
|
471
|
+
// make a new group
|
472
|
+
hoku_group* group;
|
473
|
+
if (hoku_text_group_init(&group, userdata->total_offset + 1, userdata->current_group_type, userdata->current_group_payload) != 0) return -1;
|
474
|
+
|
475
|
+
next->groups = group;
|
476
|
+
|
477
|
+
// init a char
|
478
|
+
hoku_char* insert;
|
479
|
+
if (hoku_text_char_init(&insert, userdata->total_offset, letter_width) != 0) return -1;
|
480
|
+
|
481
|
+
if (current_char == NULL)
|
482
|
+
{
|
483
|
+
hoku_text_group_append_char(userdata->current_group, insert);
|
484
|
+
userdata->current_segment->size += 1;
|
485
|
+
userdata->current_group->size += 1;
|
486
|
+
}
|
487
|
+
else
|
488
|
+
{
|
489
|
+
current_char->next_char = insert;
|
490
|
+
userdata->current_segment->size += 1;
|
491
|
+
userdata->current_group->size += 1;
|
492
|
+
}
|
493
|
+
|
494
|
+
// the current group already has a reference to the current_char, so we can set it to NULL here.
|
495
|
+
userdata->current_segment->next_segment = next;
|
496
|
+
userdata->current_segment = next;
|
497
|
+
// printf("set current segment %p\n", userdata->current_segment);
|
498
|
+
|
499
|
+
|
500
|
+
userdata->current_group = group;
|
501
|
+
current_char = NULL;
|
502
|
+
|
503
|
+
userdata->line_width = 0.0;
|
504
|
+
userdata->total_offset += 1;
|
505
|
+
i += 1;
|
506
|
+
continue;
|
507
|
+
}
|
508
|
+
}
|
509
|
+
|
510
|
+
// printf("part 3: add char '%c' %d %d\n", letter, userdata->total_offset, letter_width);
|
511
|
+
/*
|
512
|
+
Part 3, add the next character.
|
513
|
+
*/
|
514
|
+
hoku_char* ichar;
|
515
|
+
if (hoku_text_char_init(&ichar, userdata->total_offset, letter_width) != 0) return -1;
|
516
|
+
|
517
|
+
// printf("after init char\n");
|
518
|
+
if (current_char == NULL)
|
519
|
+
{
|
520
|
+
userdata->current_group->chars = ichar;
|
521
|
+
current_char = userdata->current_group->chars;
|
522
|
+
}
|
523
|
+
else
|
524
|
+
{
|
525
|
+
current_char->next_char = ichar;
|
526
|
+
current_char = current_char->next_char;
|
527
|
+
}
|
528
|
+
|
529
|
+
userdata->current_segment->size += 1;
|
530
|
+
userdata->current_group->size += 1;
|
531
|
+
userdata->total_offset += 1;
|
532
|
+
i += 1;
|
533
|
+
// printf("line width: %f %d\n", userdata->line_width, letter_width);
|
534
|
+
userdata->line_width += (float) letter_width;
|
535
|
+
}
|
536
|
+
|
537
|
+
if (hoku_text_md_append(userdata, text, size) != 0) return -1;
|
538
|
+
|
539
|
+
// printf("appending text: %d\n", size);
|
540
|
+
return 0;
|
541
|
+
}
|
542
|
+
|
543
|
+
void hoku_text_md_debug(const char* message, void* userdata)
|
544
|
+
{
|
545
|
+
printf("debug: %s\n", message);
|
546
|
+
}
|
547
|
+
|
548
|
+
int hoku_text_md_clamp(hoku_clamping** out, char* text, float width, float initial, void* payload, hoku_char_width_cb cb)
|
549
|
+
{
|
550
|
+
MD_PARSER parser = {
|
551
|
+
.abi_version = 0,
|
552
|
+
.flags = MD_FLAG_NOHTML | MD_FLAG_PERMISSIVEAUTOLINKS | MD_FLAG_HARD_SOFT_BREAKS,
|
553
|
+
.enter_block = hoku_text_md_enter_block,
|
554
|
+
.leave_block = hoku_text_md_leave_block,
|
555
|
+
.enter_span = hoku_text_md_enter_span,
|
556
|
+
.leave_span = hoku_text_md_leave_span,
|
557
|
+
.text = hoku_text_md_text,
|
558
|
+
.debug_log = hoku_text_md_debug,
|
559
|
+
.syntax = NULL
|
560
|
+
};
|
561
|
+
|
562
|
+
hoku_segment* current_segment;
|
563
|
+
if (hoku_text_segment_init(¤t_segment, 0) != 0) return -1;
|
564
|
+
|
565
|
+
hoku_group* current_group;
|
566
|
+
if (hoku_text_group_init(¤t_group, 0, HOKU_GROUP_NORMAL, NULL) != 0) return -1;
|
567
|
+
|
568
|
+
char* parsed = (char*) calloc(101, sizeof(char));
|
569
|
+
if (parsed == NULL) return -1;
|
570
|
+
|
571
|
+
// hoku_md_state* state = malloc(sizeof(hoku_md_state));
|
572
|
+
// if (state == NULL) return -1;
|
573
|
+
//
|
574
|
+
// state->width = width;
|
575
|
+
// state->total_offset = 0;
|
576
|
+
// state->line_width = initial;
|
577
|
+
// state->char_width_callback = cb;
|
578
|
+
// state->char_width_payload = payload;
|
579
|
+
// state->root_segment = current_segment;
|
580
|
+
// state->current_segment = current_segment;
|
581
|
+
// state->current_group = NULL;
|
582
|
+
// state->current_char = NULL;
|
583
|
+
// state->current_group_payload = NULL;
|
584
|
+
// state->parsed = parsed;
|
585
|
+
// state->parsed_len = 100;
|
586
|
+
// state->parsed_counter = 0;
|
587
|
+
|
588
|
+
hoku_md_state state = {
|
589
|
+
.width = width,
|
590
|
+
.total_offset = 0,
|
591
|
+
.line_width = initial,
|
592
|
+
.char_width_payload = payload,
|
593
|
+
.char_width_callback = cb,
|
594
|
+
.root_segment = current_segment,
|
595
|
+
.current_group_type = HOKU_GROUP_NORMAL,
|
596
|
+
.current_segment = current_segment,
|
597
|
+
.current_group = NULL,
|
598
|
+
.current_char = NULL,
|
599
|
+
.current_group_payload = NULL,
|
600
|
+
.parsed = parsed,
|
601
|
+
.parsed_len = 100,
|
602
|
+
.parsed_counter = 0
|
603
|
+
};
|
604
|
+
|
605
|
+
// printf("start parse! %s\n", text);
|
606
|
+
int md_ret = md_parse(text, strlen(text), &parser, &state);
|
607
|
+
// printf("done parse!\n");
|
608
|
+
if (md_ret != 0) return -1;
|
609
|
+
|
610
|
+
hoku_clamping* clamping;
|
611
|
+
hoku_text_clamping_init(&clamping, state.parsed, width);
|
612
|
+
|
613
|
+
if (clamping == NULL) return -1;
|
614
|
+
|
615
|
+
clamping->segments = state.root_segment;
|
616
|
+
// hoku_text_clamp_debug(clamping);
|
617
|
+
|
618
|
+
*out = clamping;
|
619
|
+
return 0;
|
620
|
+
}
|
621
|
+
|
622
|
+
int hoku_text_clamp(hoku_clamping** out, char* text, float width, float initial, void* payload, hoku_char_width_cb cb)
|
623
|
+
{
|
624
|
+
hoku_clamping* clamping;
|
625
|
+
hoku_text_clamping_init(&clamping, text, width);
|
626
|
+
|
627
|
+
int l = 0;
|
628
|
+
int len = strlen(clamping->text);
|
629
|
+
|
630
|
+
int total_offset = 0; // the sum of the offsets, used to mark the total chars before the start of current line
|
631
|
+
float line_width = initial; // the aggregate width of the current line
|
632
|
+
int last = 0; // the last known space or newline
|
633
|
+
|
634
|
+
hoku_segment* current;
|
635
|
+
hoku_text_segment_init(¤t, 0);
|
636
|
+
clamping->segments = current;
|
637
|
+
|
638
|
+
hoku_char* character = NULL;
|
639
|
+
|
640
|
+
// iterate through the whole string
|
641
|
+
while (total_offset < len)
|
642
|
+
{
|
643
|
+
// printf("t: %d - %d (%f) %c\n", total_offset, len, line_width, clamping->text[total_offset]);
|
644
|
+
char letter = clamping->text[total_offset];
|
645
|
+
int letter_width = (int) cb(letter, payload);
|
646
|
+
// printf("lw %c, %d\n", clamping->text[total_offset], letter_width);
|
647
|
+
|
648
|
+
if ((line_width + letter_width) > width)
|
649
|
+
{
|
650
|
+
// printf("last: %d > %d (%d)\n", last, current->offset, total_offset);
|
651
|
+
if ((last > current->offset) && ((last - current->offset) > ((total_offset - current->offset) / 2.0)))
|
652
|
+
{
|
653
|
+
// hoku_text_clamp_debug(clamping);
|
654
|
+
|
655
|
+
// printf("split branch %d\n", last - current->offset);
|
656
|
+
int split_index = last - current->offset;
|
657
|
+
|
658
|
+
// printf("current size: %d\n", current->size);
|
659
|
+
|
660
|
+
hoku_text_segment_split(current, split_index);
|
661
|
+
current = current->next_segment;
|
662
|
+
|
663
|
+
|
664
|
+
hoku_char* cn;
|
665
|
+
if (hoku_text_char_init(&cn, total_offset, letter_width) != 0) return -1;
|
666
|
+
if (current->chars != NULL)
|
667
|
+
{
|
668
|
+
// printf("Oky\n");
|
669
|
+
current->chars->next_char = cn;
|
670
|
+
character = cn;
|
671
|
+
}
|
672
|
+
else
|
673
|
+
{
|
674
|
+
// printf("wha\n");
|
675
|
+
current->chars = cn;
|
676
|
+
character = cn;
|
677
|
+
}
|
678
|
+
|
679
|
+
// printf("af\n");
|
680
|
+
|
681
|
+
hoku_text_clamp_debug(clamping);
|
682
|
+
|
683
|
+
float split_width = 0.0;
|
684
|
+
|
685
|
+
// sum the last split characters
|
686
|
+
line_width = hoku_text_char_sum(current->chars);
|
687
|
+
current->size += 1;
|
688
|
+
|
689
|
+
total_offset += 1;
|
690
|
+
continue;
|
691
|
+
}
|
692
|
+
// hard break on line
|
693
|
+
else
|
694
|
+
{
|
695
|
+
printf("easy branch %d\n", total_offset);
|
696
|
+
|
697
|
+
// make a new segment
|
698
|
+
hoku_segment* segment;
|
699
|
+
if (hoku_text_segment_init(&segment, total_offset) != 0) return -1;
|
700
|
+
|
701
|
+
// init a char
|
702
|
+
hoku_char* ichar;
|
703
|
+
if (hoku_text_char_init(&ichar, total_offset, letter_width) != 0) return -1;
|
704
|
+
|
705
|
+
segment->chars = ichar;
|
706
|
+
segment->size += 1;
|
707
|
+
|
708
|
+
|
709
|
+
// append to the segment list and reset current
|
710
|
+
current->next_segment = segment;
|
711
|
+
current = current->next_segment;
|
712
|
+
|
713
|
+
character = current->chars;
|
714
|
+
|
715
|
+
line_width = letter_width;
|
716
|
+
total_offset += 1;
|
717
|
+
// printf("eadsy done\n");
|
718
|
+
continue;
|
719
|
+
}
|
720
|
+
}
|
721
|
+
|
722
|
+
// printf("Switch\n");
|
723
|
+
switch(clamping->text[total_offset])
|
724
|
+
{
|
725
|
+
case '\n':
|
726
|
+
{
|
727
|
+
hoku_segment* next;
|
728
|
+
if (hoku_text_segment_init(&next, total_offset + 1) != 0) return -1;
|
729
|
+
|
730
|
+
hoku_char* insert;
|
731
|
+
if (hoku_text_char_init(&insert, total_offset, letter_width) != 0) return -1;
|
732
|
+
|
733
|
+
if (character == NULL)
|
734
|
+
{
|
735
|
+
character = insert;
|
736
|
+
current->size += 1;
|
737
|
+
}
|
738
|
+
else
|
739
|
+
{
|
740
|
+
character->next_char = insert;
|
741
|
+
current->size += 1;
|
742
|
+
}
|
743
|
+
|
744
|
+
current->next_segment = next;
|
745
|
+
current = current->next_segment;
|
746
|
+
character = NULL;
|
747
|
+
|
748
|
+
line_width = 0.0;
|
749
|
+
total_offset += 1;
|
750
|
+
continue;
|
751
|
+
}
|
752
|
+
}
|
753
|
+
|
754
|
+
// printf("okay %d %d %p\n", total_offset, letter_width, current);
|
755
|
+
hoku_char* ichar;
|
756
|
+
if (hoku_text_char_init(&ichar, total_offset, letter_width) != 0) return -1;
|
757
|
+
|
758
|
+
if (character == NULL)
|
759
|
+
{
|
760
|
+
// printf("whoa\n");
|
761
|
+
current->chars = ichar;
|
762
|
+
character = current->chars;
|
763
|
+
// printf("okay\n");
|
764
|
+
}
|
765
|
+
else
|
766
|
+
{
|
767
|
+
// printf("shouldn't happen\n");
|
768
|
+
character->next_char = ichar;
|
769
|
+
character = character->next_char;
|
770
|
+
// printf("done\n");
|
771
|
+
}
|
772
|
+
|
773
|
+
|
774
|
+
current->size += 1;
|
775
|
+
total_offset += 1;
|
776
|
+
line_width += letter_width;
|
777
|
+
}
|
778
|
+
|
779
|
+
// printf("out\n");
|
780
|
+
*out = clamping;
|
781
|
+
return 0;
|
782
|
+
}
|
783
|
+
|
784
|
+
#endif
|