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.
Files changed (166) hide show
  1. checksums.yaml +7 -0
  2. data/Dockerfile +26 -0
  3. data/Gemfile +15 -0
  4. data/Gemfile.lock +91 -0
  5. data/LICENSE +21 -0
  6. data/README.md +28 -0
  7. data/ast/genheader +3 -0
  8. data/ast/include/hashmap.c +1151 -0
  9. data/ast/include/hashmap.c.license +20 -0
  10. data/ast/include/hashmap.h +54 -0
  11. data/ast/src/core/ast.c +448 -0
  12. data/ast/src/core/ast.h +259 -0
  13. data/ast/src/core/common.h +24 -0
  14. data/ast/src/core/component.c +85 -0
  15. data/ast/src/core/component.h +35 -0
  16. data/ast/src/core/hml.c +665 -0
  17. data/ast/src/core/hml.h +11 -0
  18. data/ast/src/core/input.c +458 -0
  19. data/ast/src/core/input.h +118 -0
  20. data/ast/src/core/style.c +101 -0
  21. data/ast/src/core/style.h +41 -0
  22. data/ast/src/core/text.c +784 -0
  23. data/ast/src/core/text.h +93 -0
  24. data/ast/src/core/util.c +140 -0
  25. data/ast/src/core/util.h +48 -0
  26. data/ast/src/hokusai.c +6 -0
  27. data/ast/src/hokusai.h +6 -0
  28. data/ast/test/fixtures/test.ui +13 -0
  29. data/ast/test/greatest.h +1266 -0
  30. data/ast/test/hokusai.c +14 -0
  31. data/ast/test/parser.c +234 -0
  32. data/ast/test/text.c +116 -0
  33. data/ext/extconf.rb +27 -0
  34. data/grammar/Cargo.lock +80 -0
  35. data/grammar/Cargo.toml +26 -0
  36. data/grammar/binding.gyp +20 -0
  37. data/grammar/bindings/node/binding.cc +28 -0
  38. data/grammar/bindings/node/index.js +19 -0
  39. data/grammar/bindings/rust/build.rs +40 -0
  40. data/grammar/bindings/rust/lib.rs +52 -0
  41. data/grammar/corpus/1_document.txt +131 -0
  42. data/grammar/corpus/2_selectors.txt +58 -0
  43. data/grammar/corpus/3_spaces.txt +69 -0
  44. data/grammar/corpus/4_errors.txt +10 -0
  45. data/grammar/corpus/5_macros.txt +175 -0
  46. data/grammar/corpus/6_styles.txt +81 -0
  47. data/grammar/grammar.js +275 -0
  48. data/grammar/package-lock.json +34 -0
  49. data/grammar/package.json +33 -0
  50. data/grammar/src/grammar.json +1269 -0
  51. data/grammar/src/node-types.json +474 -0
  52. data/grammar/src/parser.c +5772 -0
  53. data/grammar/src/scanner.c +258 -0
  54. data/grammar/src/tree_sitter/parser.h +230 -0
  55. data/grammar/src/tree_sitter/scanner.h +12 -0
  56. data/grammar/test.nml +10 -0
  57. data/hokusai.gemspec +19 -0
  58. data/ui/examples/assets/DigitalDisplay.ttf +0 -0
  59. data/ui/examples/assets/OpenSans-Regular.ttf +0 -0
  60. data/ui/examples/assets/addy.png +0 -0
  61. data/ui/examples/assets/baby_sean.png +0 -0
  62. data/ui/examples/assets/football-troll.png +0 -0
  63. data/ui/examples/assets/gear.png +0 -0
  64. data/ui/examples/assets/icecold.ttf +0 -0
  65. data/ui/examples/assets/science-troll.png +0 -0
  66. data/ui/examples/buddy.rb +31 -0
  67. data/ui/examples/clock.rb +58 -0
  68. data/ui/examples/counter.rb +123 -0
  69. data/ui/examples/dynamic.rb +147 -0
  70. data/ui/examples/foobar.rb +236 -0
  71. data/ui/examples/stock.rb +115 -0
  72. data/ui/examples/stock_decider/option.rb +74 -0
  73. data/ui/examples/tic_tac_toe.rb +246 -0
  74. data/ui/lib/lib_hokusai.rb +425 -0
  75. data/ui/spec/hokusai/ast_spec.rb +88 -0
  76. data/ui/spec/hokusai/automation/keys_transcoder_spec.rb +50 -0
  77. data/ui/spec/hokusai/automation/selector_spec.rb +68 -0
  78. data/ui/spec/hokusai/block_spec.rb +126 -0
  79. data/ui/spec/hokusai/directives_spec.rb +327 -0
  80. data/ui/spec/hokusai/e2e/client_spec.rb +58 -0
  81. data/ui/spec/hokusai/e2e/meta_spec.rb +42 -0
  82. data/ui/spec/hokusai/publisher_spec.rb +38 -0
  83. data/ui/spec/hokusai/slots_spec.rb +150 -0
  84. data/ui/spec/hokusai/util/piece_table_spec.rb +90 -0
  85. data/ui/spec/hokusai_spec.rb +0 -0
  86. data/ui/spec/spec_helper.rb +30 -0
  87. data/ui/src/hokusai/ast.rb +446 -0
  88. data/ui/src/hokusai/automation/client.rb +167 -0
  89. data/ui/src/hokusai/automation/constants.rb +98 -0
  90. data/ui/src/hokusai/automation/converters/selector_converter.rb +61 -0
  91. data/ui/src/hokusai/automation/driver.rb +54 -0
  92. data/ui/src/hokusai/automation/driver_command_queue.rb +50 -0
  93. data/ui/src/hokusai/automation/driver_commands/base.rb +79 -0
  94. data/ui/src/hokusai/automation/driver_commands/get_attribute.rb +41 -0
  95. data/ui/src/hokusai/automation/driver_commands/invoke.rb +33 -0
  96. data/ui/src/hokusai/automation/driver_commands/locate.rb +48 -0
  97. data/ui/src/hokusai/automation/driver_commands/trigger_keyboard.rb +94 -0
  98. data/ui/src/hokusai/automation/driver_commands/trigger_mouse.rb +213 -0
  99. data/ui/src/hokusai/automation/keys_transcoder.rb +128 -0
  100. data/ui/src/hokusai/automation/selector.rb +39 -0
  101. data/ui/src/hokusai/automation/server.rb +114 -0
  102. data/ui/src/hokusai/automation.rb +3 -0
  103. data/ui/src/hokusai/backends/raylib/config.rb +47 -0
  104. data/ui/src/hokusai/backends/raylib/font.rb +113 -0
  105. data/ui/src/hokusai/backends/raylib/keys.rb +124 -0
  106. data/ui/src/hokusai/backends/raylib.rb +449 -0
  107. data/ui/src/hokusai/backends/sdl2/Monaco.ttf +0 -0
  108. data/ui/src/hokusai/backends/sdl2/color.rb +12 -0
  109. data/ui/src/hokusai/backends/sdl2/config.rb +31 -0
  110. data/ui/src/hokusai/backends/sdl2/font.rb +127 -0
  111. data/ui/src/hokusai/backends/sdl2/keys.rb +119 -0
  112. data/ui/src/hokusai/backends/sdl2.rb +529 -0
  113. data/ui/src/hokusai/block.rb +237 -0
  114. data/ui/src/hokusai/blocks/button.rb +100 -0
  115. data/ui/src/hokusai/blocks/checkbox.rb +51 -0
  116. data/ui/src/hokusai/blocks/circle.rb +28 -0
  117. data/ui/src/hokusai/blocks/clipped.rb +23 -0
  118. data/ui/src/hokusai/blocks/cursor.rb +49 -0
  119. data/ui/src/hokusai/blocks/dynamic.rb +37 -0
  120. data/ui/src/hokusai/blocks/empty.rb +10 -0
  121. data/ui/src/hokusai/blocks/hblock.rb +35 -0
  122. data/ui/src/hokusai/blocks/image.rb +18 -0
  123. data/ui/src/hokusai/blocks/input.rb +200 -0
  124. data/ui/src/hokusai/blocks/label.rb +39 -0
  125. data/ui/src/hokusai/blocks/panel.rb +126 -0
  126. data/ui/src/hokusai/blocks/rect.rb +24 -0
  127. data/ui/src/hokusai/blocks/scissor_begin.rb +18 -0
  128. data/ui/src/hokusai/blocks/scissor_end.rb +12 -0
  129. data/ui/src/hokusai/blocks/scrollbar.rb +103 -0
  130. data/ui/src/hokusai/blocks/selectable.rb +77 -0
  131. data/ui/src/hokusai/blocks/svg.rb +20 -0
  132. data/ui/src/hokusai/blocks/text.rb +214 -0
  133. data/ui/src/hokusai/blocks/titlebar/osx.rb +145 -0
  134. data/ui/src/hokusai/blocks/toggle.rb +55 -0
  135. data/ui/src/hokusai/blocks/vblock.rb +35 -0
  136. data/ui/src/hokusai/commands/base.rb +22 -0
  137. data/ui/src/hokusai/commands/circle.rb +47 -0
  138. data/ui/src/hokusai/commands/image.rb +45 -0
  139. data/ui/src/hokusai/commands/rect.rb +158 -0
  140. data/ui/src/hokusai/commands/scissor.rb +22 -0
  141. data/ui/src/hokusai/commands/text.rb +92 -0
  142. data/ui/src/hokusai/commands.rb +87 -0
  143. data/ui/src/hokusai/diff.rb +124 -0
  144. data/ui/src/hokusai/error.rb +3 -0
  145. data/ui/src/hokusai/event.rb +54 -0
  146. data/ui/src/hokusai/events/keyboard.rb +84 -0
  147. data/ui/src/hokusai/events/mouse.rb +172 -0
  148. data/ui/src/hokusai/font.rb +280 -0
  149. data/ui/src/hokusai/meta.rb +152 -0
  150. data/ui/src/hokusai/mounting/loop_entry.rb +230 -0
  151. data/ui/src/hokusai/mounting/mount_entry.rb +74 -0
  152. data/ui/src/hokusai/mounting/update_entry.rb +101 -0
  153. data/ui/src/hokusai/node.rb +98 -0
  154. data/ui/src/hokusai/node_mounter.rb +102 -0
  155. data/ui/src/hokusai/painter.rb +214 -0
  156. data/ui/src/hokusai/publisher.rb +32 -0
  157. data/ui/src/hokusai/style.rb +72 -0
  158. data/ui/src/hokusai/types.rb +266 -0
  159. data/ui/src/hokusai/util/clamping_iterator.rb +202 -0
  160. data/ui/src/hokusai/util/piece_table.rb +111 -0
  161. data/ui/src/hokusai/util/selection.rb +145 -0
  162. data/ui/src/hokusai.rb +120 -0
  163. data/ui/vendor/.gitkeep +0 -0
  164. data/vendor/.gitkeep +0 -0
  165. data/xmake.lua +192 -0
  166. metadata +222 -0
@@ -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(&current_segment, 0) != 0) return -1;
564
+
565
+ hoku_group* current_group;
566
+ if (hoku_text_group_init(&current_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(&current, 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