apex-ruby 1.0.17 → 1.0.20

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 (207) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -3
  3. data/ext/apex_ext/apex_ext.c +260 -91
  4. data/ext/apex_ext/apex_src/CHANGELOG.md +440 -0
  5. data/ext/apex_ext/apex_src/CMakeLists.txt +15 -1
  6. data/ext/apex_ext/apex_src/Formula/apex.rb +7 -2
  7. data/ext/apex_ext/apex_src/Package.swift +15 -4
  8. data/ext/apex_ext/apex_src/README.md +94 -35
  9. data/ext/apex_ext/apex_src/VERSION +1 -1
  10. data/ext/apex_ext/apex_src/apex-debug.log +4 -0
  11. data/ext/apex_ext/apex_src/apex.code-workspace +38 -0
  12. data/ext/apex_ext/apex_src/apex.taskpaper +12 -0
  13. data/ext/apex_ext/apex_src/apex_deflist_debug.log +25 -0
  14. data/ext/apex_ext/apex_src/buildnotes.md +1435 -0
  15. data/ext/apex_ext/apex_src/cli/main.c +262 -33
  16. data/ext/apex_ext/apex_src/debug.log +7 -0
  17. data/ext/apex_ext/apex_src/docs/CITATIONS_EXAMPLES.md +274 -0
  18. data/ext/apex_ext/apex_src/docs/CITATIONS_IMPLEMENTATION_PLAN.md +749 -0
  19. data/ext/apex_ext/apex_src/docs/CITATIONS_PLAN.md +744 -0
  20. data/ext/apex_ext/apex_src/docs/INDEX_IMPLEMENTATION_ANALYSIS.md +382 -0
  21. data/ext/apex_ext/apex_src/docs/plans/2025-02-27-man-page-output-implementation.md +351 -0
  22. data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-12-toc-output-format.md +745 -0
  23. data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-18-bear-image-attributes.md +829 -0
  24. data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-19-apex-node-npm.md +1148 -0
  25. data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-12-toc-output-format-design.md +161 -0
  26. data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-18-bear-image-attributes-design.md +184 -0
  27. data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-19-apex-node-npm-design.md +211 -0
  28. data/ext/apex_ext/apex_src/documentation/app-settings-table.md +67 -0
  29. data/ext/apex_ext/apex_src/documentation/app-transformed/Citations.md +340 -0
  30. data/ext/apex_ext/apex_src/documentation/app-transformed/Credits.md +11 -0
  31. data/ext/apex_ext/apex_src/documentation/app-transformed/Header-IDs.md +234 -0
  32. data/ext/apex_ext/apex_src/documentation/app-transformed/Inline-Attribute-Lists.md +516 -0
  33. data/ext/apex_ext/apex_src/documentation/app-transformed/Metadata-Transforms.md +461 -0
  34. data/ext/apex_ext/apex_src/documentation/app-transformed/Modes.md +193 -0
  35. data/ext/apex_ext/apex_src/documentation/app-transformed/Multi-File-Documents.md +201 -0
  36. data/ext/apex_ext/apex_src/documentation/app-transformed/Plugins.md +678 -0
  37. data/ext/apex_ext/apex_src/documentation/app-transformed/Syntax.md +1367 -0
  38. data/ext/apex_ext/apex_src/documentation/docsets/Apex Command Line Options.cheatsheet.txt +6 -0
  39. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/C-API.html +774 -300
  40. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Callouts.html +1194 -0
  41. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Citations.html +416 -216
  42. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Command-Line-Options.html +3544 -1094
  43. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Configuration.html +371 -97
  44. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Credits.html +153 -23
  45. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Examples.html +358 -124
  46. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Filters.html +1656 -0
  47. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Generating-Man-Pages.html +1226 -0
  48. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Getting-Started.html +201 -56
  49. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Header-IDs.html +279 -109
  50. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Home.html +200 -53
  51. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Indices.html +2327 -0
  52. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Inline-Attribute-Lists.html +690 -271
  53. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Installation.html +201 -55
  54. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Limitations-and-Roadmap.html +238 -68
  55. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Metadata-Transforms.html +421 -221
  56. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Modes.html +340 -78
  57. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-File-Documents.html +251 -86
  58. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-Format-Images.html +1362 -0
  59. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Pandoc-Integration.html +277 -90
  60. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Plugins.html +673 -346
  61. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Quarto-Mode.html +1405 -0
  62. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Rendering-Markdown-In-Terminal.html +1902 -0
  63. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Syntax.html +1939 -1698
  64. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Tables.html +1781 -0
  65. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Troubleshooting.html +315 -140
  66. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Usage.html +307 -113
  67. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Using-Apex-with-Jekyll.html +1132 -0
  68. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Writing-Tests.html +1754 -0
  69. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Xcode-Integration.html +872 -376
  70. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/docSet.dsidx +0 -0
  71. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/optimizedIndex.dsidx +0 -0
  72. data/ext/apex_ext/apex_src/documentation/html/apex-app-docs.html +8746 -0
  73. data/ext/apex_ext/apex_src/documentation/shared_styles.css +20 -15
  74. data/ext/apex_ext/apex_src/documentation/transform_for_app.md +55 -0
  75. data/ext/apex_ext/apex_src/escaping-repro.md +103 -0
  76. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/Info.plist +8 -0
  77. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/QuickLook/Preview.png +0 -0
  78. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/document.wflow +547 -0
  79. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown-to-RTF.workflow.zip +0 -0
  80. data/ext/apex_ext/apex_src/examples/quick-actions/README.md +33 -0
  81. data/ext/apex_ext/apex_src/include/apex/apex.h +92 -6
  82. data/ext/apex_ext/apex_src/include/apex/ast_rtf.h +23 -0
  83. data/ext/apex_ext/apex_src/include/apex/ast_terminal.h +6 -0
  84. data/ext/apex_ext/apex_src/include/apex/module.modulemap +5 -0
  85. data/ext/apex_ext/apex_src/include/apex/plugins.h +105 -0
  86. data/ext/apex_ext/apex_src/include/apexc.h +1 -0
  87. data/ext/apex_ext/apex_src/man/apex.1 +82 -78
  88. data/ext/apex_ext/apex_src/man/apex.1.md +81 -4
  89. data/ext/apex_ext/apex_src/objc/Apex.swift +73 -0
  90. data/ext/apex_ext/apex_src/objc/ApexPlugins.swift +79 -0
  91. data/ext/apex_ext/apex_src/objc/NSString+Apex.h +83 -5
  92. data/ext/apex_ext/apex_src/objc/NSString+Apex.m +244 -1
  93. data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.h +76 -0
  94. data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.m +169 -0
  95. data/ext/apex_ext/apex_src/output.html +87 -0
  96. data/ext/apex_ext/apex_src/plans/quarto-mode.md +442 -0
  97. data/ext/apex_ext/apex_src/src/_README.md +85 -32
  98. data/ext/apex_ext/apex_src/src/apex.c +770 -200
  99. data/ext/apex_ext/apex_src/src/ast_rtf.c +848 -0
  100. data/ext/apex_ext/apex_src/src/ast_terminal.c +184 -7
  101. data/ext/apex_ext/apex_src/src/extensions/abbreviations.c +10 -3
  102. data/ext/apex_ext/apex_src/src/extensions/advanced_tables.c +7 -11
  103. data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.c +467 -0
  104. data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.h +27 -0
  105. data/ext/apex_ext/apex_src/src/extensions/callouts.c +400 -4
  106. data/ext/apex_ext/apex_src/src/extensions/callouts.h +15 -5
  107. data/ext/apex_ext/apex_src/src/extensions/citations.c +26 -5
  108. data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.c +632 -0
  109. data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.h +22 -0
  110. data/ext/apex_ext/apex_src/src/extensions/concordance.c +632 -0
  111. data/ext/apex_ext/apex_src/src/extensions/definition_list.c +129 -15
  112. data/ext/apex_ext/apex_src/src/extensions/grid_tables.c +1050 -121
  113. data/ext/apex_ext/apex_src/src/extensions/html_markdown.c +569 -16
  114. data/ext/apex_ext/apex_src/src/extensions/ial.c +502 -52
  115. data/ext/apex_ext/apex_src/src/extensions/ial.h +2 -1
  116. data/ext/apex_ext/apex_src/src/extensions/includes.c +532 -33
  117. data/ext/apex_ext/apex_src/src/extensions/includes.h +7 -1
  118. data/ext/apex_ext/apex_src/src/extensions/index.c +1427 -140
  119. data/ext/apex_ext/apex_src/src/extensions/index.h +28 -0
  120. data/ext/apex_ext/apex_src/src/extensions/metadata.c +200 -161
  121. data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.c +251 -0
  122. data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.h +22 -0
  123. data/ext/apex_ext/apex_src/src/extensions/quarto_lists.c +624 -0
  124. data/ext/apex_ext/apex_src/src/extensions/quarto_lists.h +35 -0
  125. data/ext/apex_ext/apex_src/src/extensions/quarto_polish.c +264 -0
  126. data/ext/apex_ext/apex_src/src/extensions/quarto_polish.h +23 -0
  127. data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.c +307 -0
  128. data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.h +21 -0
  129. data/ext/apex_ext/apex_src/src/extensions/raw_content.c +351 -0
  130. data/ext/apex_ext/apex_src/src/extensions/raw_content.h +20 -0
  131. data/ext/apex_ext/apex_src/src/extensions/relaxed_tables.c +117 -3
  132. data/ext/apex_ext/apex_src/src/extensions/special_markers.c +53 -0
  133. data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.c +23 -1
  134. data/ext/apex_ext/apex_src/src/extensions/table_html_postprocess.c +83 -92
  135. data/ext/apex_ext/apex_src/src/extensions/toc.c +446 -25
  136. data/ext/apex_ext/apex_src/src/extensions/toc.h +26 -1
  137. data/ext/apex_ext/apex_src/src/extensions/wiki_links.c +28 -0
  138. data/ext/apex_ext/apex_src/src/html_renderer.c +387 -17
  139. data/ext/apex_ext/apex_src/src/plugin_catalog.c +517 -0
  140. data/ext/apex_ext/apex_src/src/plugins_remote.c +88 -14
  141. data/ext/apex_ext/apex_src/src/plugins_remote.h +34 -0
  142. data/ext/apex_ext/apex_src/src/pretty_html.c +6 -1
  143. data/ext/apex_ext/apex_src/tests/fixtures/comprehensive_test.md +21 -0
  144. data/ext/apex_ext/apex_src/tests/fixtures/images/bear_image_attributes.md +10 -0
  145. data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.md +19 -0
  146. data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.txt +11 -0
  147. data/ext/apex_ext/apex_src/tests/fixtures/minimal_pb.md +2 -0
  148. data/ext/apex_ext/apex_src/tests/fixtures/obsidian-callouts.md +46 -0
  149. data/ext/apex_ext/apex_src/tests/fixtures/pagebreak_html_repro.md +5 -0
  150. data/ext/apex_ext/apex_src/tests/fixtures/python-callouts.md +47 -0
  151. data/ext/apex_ext/apex_src/tests/fixtures/quarto/callouts.md +3 -0
  152. data/ext/apex_ext/apex_src/tests/fixtures/quarto/code-attrs.md +3 -0
  153. data/ext/apex_ext/apex_src/tests/fixtures/quarto/diagrams.md +8 -0
  154. data/ext/apex_ext/apex_src/tests/fixtures/quarto/lists.md +19 -0
  155. data/ext/apex_ext/apex_src/tests/fixtures/quarto/raw-content.md +5 -0
  156. data/ext/apex_ext/apex_src/tests/fixtures/quarto/shortcodes.md +7 -0
  157. data/ext/apex_ext/apex_src/tests/fixtures/quarto/smoke.md +81 -0
  158. data/ext/apex_ext/apex_src/tests/fixtures/quarto/spans.md +5 -0
  159. data/ext/apex_ext/apex_src/tests/fixtures/quarto-callouts.md +47 -0
  160. data/ext/apex_ext/apex_src/tests/fixtures/speed.md +192 -0
  161. data/ext/apex_ext/apex_src/tests/fixtures/tables/grid-tables.md +37 -0
  162. data/ext/apex_ext/apex_src/tests/paginate_cli_test.sh +16 -0
  163. data/ext/apex_ext/apex_src/tests/test_bear_image_attrs.c +301 -0
  164. data/ext/apex_ext/apex_src/tests/test_concordance.tsv +4 -0
  165. data/ext/apex_ext/apex_src/tests/test_escaping_repro.c +82 -0
  166. data/ext/apex_ext/apex_src/tests/test_extensions.c +821 -1
  167. data/ext/apex_ext/apex_src/tests/test_ial.c +7 -0
  168. data/ext/apex_ext/apex_src/tests/test_marked_integration.c +25 -0
  169. data/ext/apex_ext/apex_src/tests/test_metadata.c +129 -0
  170. data/ext/apex_ext/apex_src/tests/test_output.c +568 -2
  171. data/ext/apex_ext/apex_src/tests/test_runner.c +11 -0
  172. data/ext/apex_ext/apex_src/tests/test_tables.c +420 -0
  173. data/ext/apex_ext/apex_src/vendor/cmark-gfm/CMakeLists.txt +1 -1
  174. data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/autolink.c +77 -1
  175. data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/table.c +135 -5
  176. data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/blocks.c +56 -1
  177. data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/config.h +38 -0
  178. data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/main.c +1 -1
  179. data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/cmark.cpython-314.pyc +0 -0
  180. data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/normalize.cpython-314.pyc +0 -0
  181. data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/extensions.txt +69 -0
  182. data/ext/apex_ext/apex_src/xcode_build/CMakeScripts/ReRunCMake.make +74 -0
  183. data/ext/apex_ext/apex_src/xcode_build/CTestTestfile.cmake +22 -0
  184. data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Apex +0 -0
  185. data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Resources/Info.plist +44 -0
  186. data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/_CodeSignature/CodeResources +128 -0
  187. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.pbxproj +5118 -0
  188. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  189. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  190. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/WorkspaceSettings.xcsettings +8 -0
  191. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/xcuserdata/ttscoff.xcuserdatad/xcschemes/xcschememanagement.plist +99 -0
  192. data/ext/apex_ext/apex_src/xcode_build/cmake_install.cmake +452 -0
  193. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/CMakeScripts/ReRunCMake.make +52 -0
  194. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmake_install.cmake +55 -0
  195. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.pbxproj +2455 -0
  196. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  197. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/extensions/cmake_install.cmake +171 -0
  198. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/man/cmake_install.cmake +55 -0
  199. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmake_install.cmake +220 -0
  200. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_export.h +43 -0
  201. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_version.h +7 -0
  202. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/config.h +76 -0
  203. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/libcmark-gfm.pc +10 -0
  204. data/ext/apex_ext/extconf.rb +35 -0
  205. data/lib/apex/version.rb +2 -2
  206. metadata +117 -2
  207. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/tempOptimizedIndex.dsidx +0 -0
@@ -0,0 +1,624 @@
1
+ /**
2
+ * Quarto/Pandoc list extensions: example lists (@), line blocks, roman markers
3
+ */
4
+
5
+ #include "quarto_lists.h"
6
+ #include <ctype.h>
7
+ #include <stdbool.h>
8
+ #include <stdio.h>
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+
12
+ static const char ROMAN_COMMENT_LOWER[] = "<!-- apex-alpha-list-lower-roman -->";
13
+ static const char ROMAN_COMMENT_UPPER[] = "<!-- apex-alpha-list-upper-roman -->";
14
+
15
+ static const char *line_end_ptr(const char *p) {
16
+ const char *e = strchr(p, '\n');
17
+ return e ? e : p + strlen(p);
18
+ }
19
+
20
+ static bool append_chunk(char **out, size_t *len, size_t *cap, const char *chunk, size_t chunk_len) {
21
+ if (chunk_len == 0) {
22
+ return true;
23
+ }
24
+ if (*len + chunk_len + 1 > *cap) {
25
+ size_t new_cap = (*cap == 0 ? 256 : *cap * 2);
26
+ while (*len + chunk_len + 1 > new_cap) {
27
+ new_cap *= 2;
28
+ }
29
+ char *grown = realloc(*out, new_cap);
30
+ if (!grown) {
31
+ return false;
32
+ }
33
+ *out = grown;
34
+ *cap = new_cap;
35
+ }
36
+ memcpy(*out + *len, chunk, chunk_len);
37
+ *len += chunk_len;
38
+ (*out)[*len] = '\0';
39
+ return true;
40
+ }
41
+
42
+ static bool append_str(char **out, size_t *len, size_t *cap, const char *str) {
43
+ if (!str) {
44
+ return true;
45
+ }
46
+ return append_chunk(out, len, cap, str, strlen(str));
47
+ }
48
+
49
+ static const char *skip_indent(const char *line_start, const char *line_end, size_t *indent_out) {
50
+ const char *p = line_start;
51
+ while (p < line_end && (*p == ' ' || *p == '\t')) {
52
+ p++;
53
+ }
54
+ if (indent_out) {
55
+ *indent_out = (size_t)(p - line_start);
56
+ }
57
+ return p;
58
+ }
59
+
60
+ static bool line_is_blank(const char *line_start, const char *line_end) {
61
+ const char *p = skip_indent(line_start, line_end, NULL);
62
+ return p >= line_end;
63
+ }
64
+
65
+ static bool parse_example_list_marker(const char *line_start, const char *line_end,
66
+ const char **body_start) {
67
+ const char *p = skip_indent(line_start, line_end, NULL);
68
+ if (p >= line_end || *p != '(') {
69
+ return false;
70
+ }
71
+ p++;
72
+ if (p >= line_end || *p != '@') {
73
+ return false;
74
+ }
75
+ p++;
76
+ while (p < line_end &&
77
+ (isalnum((unsigned char)*p) || *p == '_' || *p == '-')) {
78
+ p++;
79
+ }
80
+ if (p >= line_end || *p != ')') {
81
+ return false;
82
+ }
83
+ p++;
84
+ if (p < line_end && *p != ' ' && *p != '\t') {
85
+ return false;
86
+ }
87
+ while (p < line_end && (*p == ' ' || *p == '\t')) {
88
+ p++;
89
+ }
90
+ if (body_start) {
91
+ *body_start = p;
92
+ }
93
+ return true;
94
+ }
95
+
96
+ char *apex_preprocess_example_lists(const char *text) {
97
+ if (!text) {
98
+ return NULL;
99
+ }
100
+
101
+ size_t cap = strlen(text) * 2 + 256;
102
+ char *out = malloc(cap);
103
+ if (!out) {
104
+ return NULL;
105
+ }
106
+ size_t len = 0;
107
+ out[0] = '\0';
108
+ bool changed = false;
109
+ int example_num = 1;
110
+
111
+ const char *read = text;
112
+ while (*read) {
113
+ const char *line_start = read;
114
+ const char *line_end = line_end_ptr(read);
115
+ bool has_newline = (*line_end == '\n');
116
+
117
+ const char *body_start = NULL;
118
+ if (parse_example_list_marker(line_start, line_end, &body_start)) {
119
+ const char *indent_end = skip_indent(line_start, line_end, NULL);
120
+ char num_buf[32];
121
+ int num_len = snprintf(num_buf, sizeof(num_buf), "%d. ", example_num++);
122
+ if (num_len <= 0 || num_len >= (int)sizeof(num_buf)) {
123
+ free(out);
124
+ return NULL;
125
+ }
126
+
127
+ if (!append_chunk(&out, &len, &cap, line_start, (size_t)(indent_end - line_start)) ||
128
+ !append_chunk(&out, &len, &cap, num_buf, (size_t)num_len)) {
129
+ free(out);
130
+ return NULL;
131
+ }
132
+
133
+ size_t body_len = (size_t)(line_end - body_start) + (has_newline ? 1 : 0);
134
+ if (!append_chunk(&out, &len, &cap, body_start, body_len)) {
135
+ free(out);
136
+ return NULL;
137
+ }
138
+
139
+ changed = true;
140
+ read = has_newline ? line_end + 1 : line_end;
141
+ continue;
142
+ }
143
+
144
+ size_t line_len = (size_t)(line_end - line_start) + (has_newline ? 1 : 0);
145
+ if (!append_chunk(&out, &len, &cap, line_start, line_len)) {
146
+ free(out);
147
+ return NULL;
148
+ }
149
+ read = has_newline ? line_end + 1 : line_end;
150
+ }
151
+
152
+ if (!changed) {
153
+ free(out);
154
+ return NULL;
155
+ }
156
+ return out;
157
+ }
158
+
159
+ static bool is_line_block_line(const char *line_start, const char *line_end) {
160
+ const char *p = skip_indent(line_start, line_end, NULL);
161
+ if (p >= line_end || *p != '|') {
162
+ return false;
163
+ }
164
+ p++;
165
+ for (const char *q = p; q < line_end; q++) {
166
+ if (*q == '|') {
167
+ return false;
168
+ }
169
+ }
170
+ return true;
171
+ }
172
+
173
+ static bool extract_line_block_content(const char *line_start, const char *line_end,
174
+ const char **content_start, size_t *content_len) {
175
+ const char *p = skip_indent(line_start, line_end, NULL);
176
+ if (p >= line_end || *p != '|') {
177
+ return false;
178
+ }
179
+ p++;
180
+ if (p < line_end && *p == ' ') {
181
+ p++;
182
+ }
183
+ const char *end = line_end;
184
+ while (end > p && (end[-1] == ' ' || end[-1] == '\t')) {
185
+ end--;
186
+ }
187
+ *content_start = p;
188
+ *content_len = (size_t)(end - p);
189
+ return true;
190
+ }
191
+
192
+ static int roman_digit_value(char c) {
193
+ switch (tolower((unsigned char)c)) {
194
+ case 'i': return 1;
195
+ case 'v': return 5;
196
+ case 'x': return 10;
197
+ case 'l': return 50;
198
+ case 'c': return 100;
199
+ case 'd': return 500;
200
+ case 'm': return 1000;
201
+ default: return 0;
202
+ }
203
+ }
204
+
205
+ static bool roman_to_int(const char *start, const char *end, bool *is_upper, int *value_out) {
206
+ if (!start || !end || start >= end || !value_out) {
207
+ return false;
208
+ }
209
+
210
+ bool upper = true;
211
+ bool lower = true;
212
+ for (const char *p = start; p < end; p++) {
213
+ if (*p >= 'a' && *p <= 'z') {
214
+ upper = false;
215
+ } else if (*p >= 'A' && *p <= 'Z') {
216
+ lower = false;
217
+ } else {
218
+ return false;
219
+ }
220
+ if (roman_digit_value(*p) == 0) {
221
+ return false;
222
+ }
223
+ }
224
+ if (!upper && !lower) {
225
+ return false;
226
+ }
227
+ if (is_upper) {
228
+ *is_upper = upper;
229
+ }
230
+
231
+ int total = 0;
232
+ int prev = 0;
233
+ for (const char *p = end - 1; p >= start; p--) {
234
+ int val = roman_digit_value(*p);
235
+ if (val < prev) {
236
+ total -= val;
237
+ } else {
238
+ total += val;
239
+ }
240
+ prev = val;
241
+ }
242
+ if (total <= 0) {
243
+ return false;
244
+ }
245
+ *value_out = total;
246
+ return true;
247
+ }
248
+
249
+ static bool parse_roman_list_marker(const char *line_start, const char *line_end,
250
+ size_t *indent_out, int *value_out, bool *is_upper) {
251
+ const char *p = skip_indent(line_start, line_end, indent_out);
252
+ if (p >= line_end) {
253
+ return false;
254
+ }
255
+ const char *digits_start = p;
256
+ while (p < line_end && (tolower((unsigned char)*p) == 'i' ||
257
+ tolower((unsigned char)*p) == 'v' ||
258
+ tolower((unsigned char)*p) == 'x' ||
259
+ tolower((unsigned char)*p) == 'l' ||
260
+ tolower((unsigned char)*p) == 'c' ||
261
+ tolower((unsigned char)*p) == 'd' ||
262
+ tolower((unsigned char)*p) == 'm')) {
263
+ p++;
264
+ }
265
+ if (p == digits_start || p >= line_end || *p != ')') {
266
+ return false;
267
+ }
268
+ p++;
269
+ if (p < line_end && *p != ' ' && *p != '\t') {
270
+ return false;
271
+ }
272
+ return roman_to_int(digits_start, p - 1, is_upper, value_out);
273
+ }
274
+
275
+ char *apex_preprocess_line_blocks(const char *text, bool unsafe) {
276
+ if (!text || !unsafe) {
277
+ return NULL;
278
+ }
279
+
280
+ size_t cap = strlen(text) * 3 + 256;
281
+ char *out = malloc(cap);
282
+ if (!out) {
283
+ return NULL;
284
+ }
285
+ size_t len = 0;
286
+ out[0] = '\0';
287
+ bool changed = false;
288
+ bool in_fenced_code = false;
289
+
290
+ const char *read = text;
291
+ while (*read) {
292
+ const char *line_start = read;
293
+ const char *line_end = line_end_ptr(read);
294
+ bool has_newline = (*line_end == '\n');
295
+ bool at_line_start = (read == text || read[-1] == '\n');
296
+
297
+ if (at_line_start) {
298
+ const char *content = skip_indent(line_start, line_end, NULL);
299
+ if ((size_t)(line_end - content) >= 3 && strncmp(content, "```", 3) == 0) {
300
+ in_fenced_code = !in_fenced_code;
301
+ }
302
+ }
303
+
304
+ if (!in_fenced_code && at_line_start && is_line_block_line(line_start, line_end)) {
305
+ const char *block_start = line_start;
306
+ const char *scan = has_newline ? line_end + 1 : line_end;
307
+ while (*scan) {
308
+ const char *next_start = scan;
309
+ const char *next_end = line_end_ptr(scan);
310
+ if (!is_line_block_line(next_start, next_end)) {
311
+ break;
312
+ }
313
+ bool next_has_newline = (*next_end == '\n');
314
+ scan = next_has_newline ? next_end + 1 : next_end;
315
+ }
316
+
317
+ if (block_start > text && block_start[-1] != '\n') {
318
+ if (!append_str(&out, &len, &cap, "\n")) {
319
+ free(out);
320
+ return NULL;
321
+ }
322
+ }
323
+ if (!append_str(&out, &len, &cap, "<div class=\"line-block\">\n")) {
324
+ free(out);
325
+ return NULL;
326
+ }
327
+
328
+ const char *line = block_start;
329
+ while (line < scan) {
330
+ const char *le = line_end_ptr(line);
331
+ const char *content = NULL;
332
+ size_t content_len = 0;
333
+ extract_line_block_content(line, le, &content, &content_len);
334
+ if (!append_str(&out, &len, &cap, "<div class=\"line\">")) {
335
+ free(out);
336
+ return NULL;
337
+ }
338
+ if (content_len > 0 && !append_chunk(&out, &len, &cap, content, content_len)) {
339
+ free(out);
340
+ return NULL;
341
+ }
342
+ if (!append_str(&out, &len, &cap, "</div>\n")) {
343
+ free(out);
344
+ return NULL;
345
+ }
346
+ line = (*le == '\n') ? le + 1 : le;
347
+ }
348
+
349
+ if (!append_str(&out, &len, &cap, "</div>\n")) {
350
+ free(out);
351
+ return NULL;
352
+ }
353
+
354
+ changed = true;
355
+ read = scan;
356
+ continue;
357
+ }
358
+
359
+ size_t line_len = (size_t)(line_end - line_start) + (has_newline ? 1 : 0);
360
+ if (!append_chunk(&out, &len, &cap, line_start, line_len)) {
361
+ free(out);
362
+ return NULL;
363
+ }
364
+ read = has_newline ? line_end + 1 : line_end;
365
+ }
366
+
367
+ if (!changed) {
368
+ free(out);
369
+ return NULL;
370
+ }
371
+ return out;
372
+ }
373
+
374
+ char *apex_preprocess_roman_lists(const char *text) {
375
+ if (!text) {
376
+ return NULL;
377
+ }
378
+
379
+ size_t cap = strlen(text) * 3 + 256;
380
+ char *out = malloc(cap);
381
+ if (!out) {
382
+ return NULL;
383
+ }
384
+ size_t len = 0;
385
+ out[0] = '\0';
386
+
387
+ bool in_roman_list = false;
388
+ size_t roman_list_indent = 0;
389
+ bool is_upper = false;
390
+ int item_number = 1;
391
+ int expected_value = 1;
392
+ int blank_lines_since_roman = 0;
393
+ bool changed = false;
394
+
395
+ const char *read = text;
396
+ while (*read) {
397
+ const char *line_start = read;
398
+ const char *line_end = line_end_ptr(read);
399
+ bool has_newline = (*line_end == '\n');
400
+
401
+ size_t current_indent = 0;
402
+ int roman_value = 0;
403
+ bool roman_upper = false;
404
+ bool is_roman_marker = parse_roman_list_marker(line_start, line_end, &current_indent,
405
+ &roman_value, &roman_upper);
406
+
407
+ if (is_roman_marker) {
408
+ bool continues_list = false;
409
+ if (in_roman_list && roman_upper == is_upper && current_indent == roman_list_indent &&
410
+ roman_value == expected_value) {
411
+ continues_list = true;
412
+ }
413
+
414
+ if (!continues_list) {
415
+ in_roman_list = true;
416
+ is_upper = roman_upper;
417
+ roman_list_indent = current_indent;
418
+ item_number = 1;
419
+ expected_value = roman_value;
420
+ blank_lines_since_roman = 0;
421
+
422
+ const char *indent_end = skip_indent(line_start, line_end, NULL);
423
+ if (!append_chunk(&out, &len, &cap, line_start, (size_t)(indent_end - line_start))) {
424
+ free(out);
425
+ return NULL;
426
+ }
427
+ const char *comment = is_upper ? ROMAN_COMMENT_UPPER : ROMAN_COMMENT_LOWER;
428
+ if (!append_str(&out, &len, &cap, comment) ||
429
+ !append_str(&out, &len, &cap, "\n\n")) {
430
+ free(out);
431
+ return NULL;
432
+ }
433
+ } else {
434
+ blank_lines_since_roman = 0;
435
+ }
436
+
437
+ const char *indent_end = skip_indent(line_start, line_end, NULL);
438
+ char num_buf[32];
439
+ int num_len = snprintf(num_buf, sizeof(num_buf), "%d. ", item_number);
440
+ if (num_len <= 0 || num_len >= (int)sizeof(num_buf)) {
441
+ free(out);
442
+ return NULL;
443
+ }
444
+ if (!append_chunk(&out, &len, &cap, line_start, (size_t)(indent_end - line_start)) ||
445
+ !append_chunk(&out, &len, &cap, num_buf, (size_t)num_len)) {
446
+ free(out);
447
+ return NULL;
448
+ }
449
+
450
+ const char *marker_end = indent_end;
451
+ while (marker_end < line_end && (tolower((unsigned char)*marker_end) == 'i' ||
452
+ tolower((unsigned char)*marker_end) == 'v' ||
453
+ tolower((unsigned char)*marker_end) == 'x' ||
454
+ tolower((unsigned char)*marker_end) == 'l' ||
455
+ tolower((unsigned char)*marker_end) == 'c' ||
456
+ tolower((unsigned char)*marker_end) == 'd' ||
457
+ tolower((unsigned char)*marker_end) == 'm')) {
458
+ marker_end++;
459
+ }
460
+ if (marker_end < line_end && *marker_end == ')') {
461
+ marker_end++;
462
+ }
463
+ while (marker_end < line_end && (*marker_end == ' ' || *marker_end == '\t')) {
464
+ marker_end++;
465
+ }
466
+
467
+ size_t rest_len = (size_t)(line_end - marker_end) + (has_newline ? 1 : 0);
468
+ if (!append_chunk(&out, &len, &cap, marker_end, rest_len)) {
469
+ free(out);
470
+ return NULL;
471
+ }
472
+
473
+ item_number++;
474
+ expected_value = roman_value + 1;
475
+ changed = true;
476
+ read = has_newline ? line_end + 1 : line_end;
477
+ continue;
478
+ }
479
+
480
+ if (in_roman_list) {
481
+ if (line_is_blank(line_start, line_end)) {
482
+ blank_lines_since_roman++;
483
+ if (blank_lines_since_roman >= 2) {
484
+ in_roman_list = false;
485
+ }
486
+ } else if (current_indent > roman_list_indent) {
487
+ blank_lines_since_roman = 0;
488
+ } else {
489
+ in_roman_list = false;
490
+ blank_lines_since_roman = 0;
491
+ }
492
+ }
493
+
494
+ size_t line_len = (size_t)(line_end - line_start) + (has_newline ? 1 : 0);
495
+ if (!append_chunk(&out, &len, &cap, line_start, line_len)) {
496
+ free(out);
497
+ return NULL;
498
+ }
499
+ read = has_newline ? line_end + 1 : line_end;
500
+ }
501
+
502
+ if (!changed) {
503
+ free(out);
504
+ return NULL;
505
+ }
506
+ return out;
507
+ }
508
+
509
+ static char *apply_list_style_to_following_ol(const char *html, const char *comment,
510
+ const char *style_attr) {
511
+ if (!html || !comment || !style_attr) {
512
+ return NULL;
513
+ }
514
+ if (!strstr(html, comment)) {
515
+ return NULL;
516
+ }
517
+
518
+ size_t html_len = strlen(html);
519
+ size_t cap = html_len + 1024;
520
+ char *out = malloc(cap);
521
+ if (!out) {
522
+ return NULL;
523
+ }
524
+ size_t len = 0;
525
+ out[0] = '\0';
526
+ bool changed = false;
527
+
528
+ const char *read = html;
529
+ const char *read_start = read;
530
+ const size_t comment_len = strlen(comment);
531
+ const size_t style_len = strlen(style_attr);
532
+
533
+ while (*read) {
534
+ if (strncmp(read, comment, comment_len) == 0) {
535
+ size_t copy_len = (size_t)(read - read_start);
536
+ if (len + copy_len + style_len + 64 > cap) {
537
+ cap = (len + copy_len + style_len + 64) * 2;
538
+ char *grown = realloc(out, cap);
539
+ if (!grown) {
540
+ free(out);
541
+ return NULL;
542
+ }
543
+ out = grown;
544
+ }
545
+ if (copy_len > 0) {
546
+ memcpy(out + len, read_start, copy_len);
547
+ len += copy_len;
548
+ }
549
+ read += comment_len;
550
+ read_start = read;
551
+ while (*read == ' ' || *read == '\t' || *read == '\n' || *read == '\r') {
552
+ read++;
553
+ }
554
+ read_start = read;
555
+
556
+ if (read[0] == '<' && read[1] == 'o' && read[2] == 'l' &&
557
+ (read[3] == '>' || read[3] == ' ' || read[3] == '\t' || read[3] == '\n')) {
558
+ const char *ol_start = read;
559
+ const char *tag_end = strchr(ol_start, '>');
560
+ if (tag_end) {
561
+ bool has_style = false;
562
+ for (const char *p = ol_start; p < tag_end; p++) {
563
+ if (strncmp(p, "style=", 6) == 0) {
564
+ has_style = true;
565
+ break;
566
+ }
567
+ }
568
+ size_t tag_len = (size_t)(tag_end - ol_start);
569
+ memcpy(out + len, ol_start, tag_len);
570
+ len += tag_len;
571
+ if (!has_style) {
572
+ memcpy(out + len, style_attr, style_len);
573
+ len += style_len;
574
+ } else {
575
+ out[len++] = '>';
576
+ }
577
+ read = tag_end + 1;
578
+ read_start = read;
579
+ changed = true;
580
+ continue;
581
+ }
582
+ }
583
+ continue;
584
+ }
585
+ read++;
586
+ }
587
+
588
+ if (!changed) {
589
+ free(out);
590
+ return NULL;
591
+ }
592
+
593
+ size_t tail_len = strlen(read_start);
594
+ if (len + tail_len + 1 > cap) {
595
+ cap = len + tail_len + 2;
596
+ char *grown = realloc(out, cap);
597
+ if (!grown) {
598
+ free(out);
599
+ return NULL;
600
+ }
601
+ out = grown;
602
+ }
603
+ memcpy(out + len, read_start, tail_len);
604
+ len += tail_len;
605
+ out[len] = '\0';
606
+ return out;
607
+ }
608
+
609
+ char *apex_postprocess_roman_lists_html(const char *html) {
610
+ if (!html) {
611
+ return NULL;
612
+ }
613
+
614
+ char *lower = apply_list_style_to_following_ol(html, ROMAN_COMMENT_LOWER,
615
+ " style=\"list-style-type: lower-roman\">");
616
+ const char *src = lower ? lower : html;
617
+ char *upper = apply_list_style_to_following_ol(src, ROMAN_COMMENT_UPPER,
618
+ " style=\"list-style-type: upper-roman\">");
619
+ if (lower && upper) {
620
+ free(lower);
621
+ return upper;
622
+ }
623
+ return upper ? upper : lower;
624
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Quarto/Pandoc list extensions: example lists (@), line blocks, roman markers
3
+ */
4
+
5
+ #ifndef APEX_QUARTO_LISTS_H
6
+ #define APEX_QUARTO_LISTS_H
7
+
8
+ #include <stdbool.h>
9
+
10
+ /**
11
+ * Convert Pandoc example list markers (@) to sequentially numbered ordered lists.
12
+ * Supports (@) and (@label) markers per the example_lists extension.
13
+ * Returns newly allocated text, or NULL if unchanged.
14
+ */
15
+ char *apex_preprocess_example_lists(const char *text);
16
+
17
+ /**
18
+ * Convert Pandoc line blocks (lines starting with |) to HTML div.line-block.
19
+ * Requires unsafe HTML mode for passthrough. Returns NULL if unchanged.
20
+ */
21
+ char *apex_preprocess_line_blocks(const char *text, bool unsafe);
22
+
23
+ /**
24
+ * Convert roman list markers (i), ii), I), etc.) to numbered lists with style hints.
25
+ * Returns NULL if unchanged.
26
+ */
27
+ char *apex_preprocess_roman_lists(const char *text);
28
+
29
+ /**
30
+ * Add list-style-type for roman list HTML comment markers.
31
+ * Returns NULL if unchanged.
32
+ */
33
+ char *apex_postprocess_roman_lists_html(const char *html);
34
+
35
+ #endif /* APEX_QUARTO_LISTS_H */