apex-ruby 1.0.18 → 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,351 @@
1
+ /**
2
+ * Pandoc/Quarto raw content ({=format}) preprocessing
3
+ */
4
+
5
+ #include "raw_content.h"
6
+ #include <ctype.h>
7
+ #include <stdbool.h>
8
+ #include <stdlib.h>
9
+ #include <string.h>
10
+ #include <strings.h>
11
+
12
+ static bool append_chunk(char **out, size_t *len, size_t *cap, const char *chunk, size_t chunk_len) {
13
+ if (chunk_len == 0) {
14
+ return true;
15
+ }
16
+ if (*len + chunk_len + 1 > *cap) {
17
+ size_t new_cap = (*cap == 0 ? 256 : *cap * 2);
18
+ while (*len + chunk_len + 1 > new_cap) {
19
+ new_cap *= 2;
20
+ }
21
+ char *grown = realloc(*out, new_cap);
22
+ if (!grown) {
23
+ return false;
24
+ }
25
+ *out = grown;
26
+ *cap = new_cap;
27
+ }
28
+ memcpy(*out + *len, chunk, chunk_len);
29
+ *len += chunk_len;
30
+ (*out)[*len] = '\0';
31
+ return true;
32
+ }
33
+
34
+ static bool append_str(char **out, size_t *len, size_t *cap, const char *str) {
35
+ if (!str) {
36
+ return true;
37
+ }
38
+ return append_chunk(out, len, cap, str, strlen(str));
39
+ }
40
+
41
+ static bool parse_raw_format(const char *start, const char *end,
42
+ char *format_buf, size_t format_buf_size) {
43
+ if (!start || !end || end <= start || !format_buf || format_buf_size == 0) {
44
+ return false;
45
+ }
46
+
47
+ const char *p = start;
48
+ while (p < end && isspace((unsigned char)*p)) {
49
+ p++;
50
+ }
51
+ if (p >= end) {
52
+ return false;
53
+ }
54
+
55
+ const char *fmt_start = NULL;
56
+ const char *fmt_end = NULL;
57
+
58
+ if (*p == '{') {
59
+ p++;
60
+ if (p >= end || *p != '=') {
61
+ return false;
62
+ }
63
+ p++;
64
+ fmt_start = p;
65
+ while (p < end && (isalnum((unsigned char)*p) || *p == '_' || *p == '-')) {
66
+ p++;
67
+ }
68
+ fmt_end = p;
69
+ if (fmt_end == fmt_start || p >= end || *p != '}') {
70
+ return false;
71
+ }
72
+ p++;
73
+ while (p < end && isspace((unsigned char)*p)) {
74
+ p++;
75
+ }
76
+ if (p != end) {
77
+ return false;
78
+ }
79
+ } else if (*p == '=') {
80
+ p++;
81
+ fmt_start = p;
82
+ while (p < end && (isalnum((unsigned char)*p) || *p == '_' || *p == '-')) {
83
+ p++;
84
+ }
85
+ fmt_end = p;
86
+ if (fmt_end == fmt_start) {
87
+ return false;
88
+ }
89
+ while (p < end && isspace((unsigned char)*p)) {
90
+ p++;
91
+ }
92
+ if (p != end) {
93
+ return false;
94
+ }
95
+ } else {
96
+ return false;
97
+ }
98
+
99
+ size_t fmt_len = (size_t)(fmt_end - fmt_start);
100
+ if (fmt_len == 0 || fmt_len >= format_buf_size) {
101
+ return false;
102
+ }
103
+ for (size_t i = 0; i < fmt_len; i++) {
104
+ format_buf[i] = (char)tolower((unsigned char)fmt_start[i]);
105
+ }
106
+ format_buf[fmt_len] = '\0';
107
+ return true;
108
+ }
109
+
110
+ static bool is_html_format(const char *format) {
111
+ return format && strcasecmp(format, "html") == 0;
112
+ }
113
+
114
+ static bool emit_raw_block(char **out, size_t *len, size_t *cap,
115
+ const char *body, size_t body_len,
116
+ const char *format, bool unsafe) {
117
+ if (is_html_format(format) && unsafe) {
118
+ if (body_len > 0 && !append_chunk(out, len, cap, body, body_len)) {
119
+ return false;
120
+ }
121
+ if (body_len == 0 || body[body_len - 1] != '\n') {
122
+ if (!append_chunk(out, len, cap, "\n", 1)) {
123
+ return false;
124
+ }
125
+ }
126
+ return true;
127
+ }
128
+
129
+ if (!append_str(out, len, cap, "<!-- raw format=")) {
130
+ return false;
131
+ }
132
+ if (!append_str(out, len, cap, format)) {
133
+ return false;
134
+ }
135
+ if (!append_str(out, len, cap, " -->\n")) {
136
+ return false;
137
+ }
138
+ if (body_len > 0 && !append_chunk(out, len, cap, body, body_len)) {
139
+ return false;
140
+ }
141
+ if (body_len == 0 || body[body_len - 1] != '\n') {
142
+ if (!append_chunk(out, len, cap, "\n", 1)) {
143
+ return false;
144
+ }
145
+ }
146
+ return append_str(out, len, cap, "<!-- /raw -->\n");
147
+ }
148
+
149
+ static bool emit_raw_inline(char **out, size_t *len, size_t *cap,
150
+ const char *content, size_t content_len,
151
+ const char *format, bool unsafe) {
152
+ if (is_html_format(format) && unsafe) {
153
+ return append_chunk(out, len, cap, content, content_len);
154
+ }
155
+
156
+ if (!append_str(out, len, cap, "<!-- raw format=")) {
157
+ return false;
158
+ }
159
+ if (!append_str(out, len, cap, format)) {
160
+ return false;
161
+ }
162
+ if (!append_str(out, len, cap, " -->")) {
163
+ return false;
164
+ }
165
+ if (!append_chunk(out, len, cap, content, content_len)) {
166
+ return false;
167
+ }
168
+ return append_str(out, len, cap, "<!-- /raw -->");
169
+ }
170
+
171
+ static const char *line_end_ptr(const char *p) {
172
+ const char *e = strchr(p, '\n');
173
+ return e ? e : p + strlen(p);
174
+ }
175
+
176
+ static bool try_raw_block_fence(const char *line_start, const char *line_end,
177
+ const char **read_out, char **out, size_t *len, size_t *cap,
178
+ bool unsafe, bool *changed) {
179
+ const char *content = line_start;
180
+ while (content < line_end && (*content == ' ' || *content == '\t')) {
181
+ content++;
182
+ }
183
+ if ((size_t)(line_end - content) < 3 || strncmp(content, "```", 3) != 0) {
184
+ return false;
185
+ }
186
+
187
+ int tick_count = 0;
188
+ const char *ticks = content;
189
+ while (ticks < line_end && *ticks == '`') {
190
+ tick_count++;
191
+ ticks++;
192
+ }
193
+ if (tick_count < 3) {
194
+ return false;
195
+ }
196
+ while (ticks < line_end && (*ticks == ' ' || *ticks == '\t')) {
197
+ ticks++;
198
+ }
199
+
200
+ char format[64];
201
+ if (!parse_raw_format(ticks, line_end, format, sizeof(format))) {
202
+ return false;
203
+ }
204
+
205
+ const char *body_start = (line_end < line_start + strlen(line_start) && *line_end == '\n')
206
+ ? line_end + 1 : line_end;
207
+ const char *scan = body_start;
208
+ while (*scan) {
209
+ const char *cl_start = scan;
210
+ const char *cl_end = line_end_ptr(scan);
211
+ const char *cl_content = cl_start;
212
+ while (cl_content < cl_end && (*cl_content == ' ' || *cl_content == '\t')) {
213
+ cl_content++;
214
+ }
215
+ int close_ticks = 0;
216
+ while (cl_content + close_ticks < cl_end && cl_content[close_ticks] == '`') {
217
+ close_ticks++;
218
+ }
219
+ if (close_ticks >= tick_count) {
220
+ const char *after_ticks = cl_content + close_ticks;
221
+ while (after_ticks < cl_end && (*after_ticks == ' ' || *after_ticks == '\t')) {
222
+ after_ticks++;
223
+ }
224
+ if (after_ticks == cl_end) {
225
+ size_t body_len = (size_t)(cl_start - body_start);
226
+ if (!emit_raw_block(out, len, cap, body_start, body_len, format, unsafe)) {
227
+ return false;
228
+ }
229
+ *changed = true;
230
+ *read_out = (*cl_end == '\n') ? cl_end + 1 : cl_end;
231
+ return true;
232
+ }
233
+ }
234
+ scan = (*cl_end == '\n') ? cl_end + 1 : cl_end;
235
+ }
236
+
237
+ return false;
238
+ }
239
+
240
+ char *apex_preprocess_raw_content(const char *text, bool unsafe) {
241
+ if (!text) {
242
+ return NULL;
243
+ }
244
+
245
+ size_t cap = strlen(text) * 2 + 256;
246
+ char *out = malloc(cap);
247
+ if (!out) {
248
+ return NULL;
249
+ }
250
+ size_t len = 0;
251
+ out[0] = '\0';
252
+
253
+ bool changed = false;
254
+ bool in_fenced_code = false;
255
+ const char *read = text;
256
+
257
+ while (*read) {
258
+ const char *line_start = read;
259
+ const char *line_end = line_end_ptr(read);
260
+ bool at_line_start = (read == text || read[-1] == '\n');
261
+
262
+ if (!in_fenced_code && at_line_start) {
263
+ const char *after_block = read;
264
+ if (try_raw_block_fence(line_start, line_end, &after_block, &out, &len, &cap, unsafe, &changed)) {
265
+ read = after_block;
266
+ continue;
267
+ }
268
+ }
269
+
270
+ if (at_line_start) {
271
+ const char *content = line_start;
272
+ while (content < line_end && (*content == ' ' || *content == '\t')) {
273
+ content++;
274
+ }
275
+ if ((size_t)(line_end - content) >= 3 && strncmp(content, "```", 3) == 0) {
276
+ in_fenced_code = !in_fenced_code;
277
+ }
278
+ }
279
+
280
+ if (!in_fenced_code && *read == '`') {
281
+ int tick_count = 0;
282
+ const char *tick_start = read;
283
+ while (read[tick_count] == '`') {
284
+ tick_count++;
285
+ }
286
+ if (tick_count > 0) {
287
+ const char *content_start = tick_start + tick_count;
288
+ const char *content_end = content_start;
289
+ while (*content_end) {
290
+ if (*content_end == '`') {
291
+ int close_ticks = 0;
292
+ while (content_end[close_ticks] == '`') {
293
+ close_ticks++;
294
+ }
295
+ if (close_ticks == tick_count) {
296
+ break;
297
+ }
298
+ }
299
+ content_end++;
300
+ }
301
+
302
+ if (*content_end == '`') {
303
+ const char *after_ticks = content_end + tick_count;
304
+ const char *fmt_scan = after_ticks;
305
+ while (*fmt_scan == ' ' || *fmt_scan == '\t') {
306
+ fmt_scan++;
307
+ }
308
+
309
+ const char *fmt_end = fmt_scan;
310
+ if (*fmt_scan == '{') {
311
+ fmt_end = strchr(fmt_scan, '}');
312
+ if (fmt_end) {
313
+ fmt_end++;
314
+ } else {
315
+ fmt_end = fmt_scan;
316
+ }
317
+ } else if (*fmt_scan == '=') {
318
+ fmt_end = fmt_scan + 1;
319
+ while (*fmt_end && (isalnum((unsigned char)*fmt_end) || *fmt_end == '_' || *fmt_end == '-')) {
320
+ fmt_end++;
321
+ }
322
+ }
323
+
324
+ char format[64];
325
+ if (parse_raw_format(fmt_scan, fmt_end, format, sizeof(format))) {
326
+ size_t content_len = (size_t)(content_end - content_start);
327
+ if (!emit_raw_inline(&out, &len, &cap, content_start, content_len, format, unsafe)) {
328
+ free(out);
329
+ return NULL;
330
+ }
331
+ changed = true;
332
+ read = fmt_end;
333
+ continue;
334
+ }
335
+ }
336
+ }
337
+ }
338
+
339
+ if (!append_chunk(&out, &len, &cap, read, 1)) {
340
+ free(out);
341
+ return NULL;
342
+ }
343
+ read++;
344
+ }
345
+
346
+ if (!changed) {
347
+ free(out);
348
+ return NULL;
349
+ }
350
+ return out;
351
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Pandoc/Quarto raw content ({=format}) preprocessing
3
+ */
4
+
5
+ #ifndef APEX_RAW_CONTENT_H
6
+ #define APEX_RAW_CONTENT_H
7
+
8
+ #include <stdbool.h>
9
+
10
+ /**
11
+ * Convert Pandoc/Quarto raw content blocks and inline spans.
12
+ *
13
+ * Block: ```{=html} ... ``` -> raw HTML (when unsafe) or HTML comment wrapper
14
+ * Inline: `code`{=html} -> raw HTML inline (when unsafe)
15
+ *
16
+ * Returns newly allocated text, or NULL when no changes were made.
17
+ */
18
+ char *apex_preprocess_raw_content(const char *text, bool unsafe);
19
+
20
+ #endif /* APEX_RAW_CONTENT_H */
@@ -91,6 +91,64 @@ static bool is_blank_line(const char *line, size_t len) {
91
91
  return true;
92
92
  }
93
93
 
94
+ /*
95
+ * Detect a fenced code marker line (` ``` ` or `~~~`) with up to 3 leading spaces.
96
+ * Returns true and fills fence_char/fence_len when a marker is present.
97
+ */
98
+ static bool parse_fence_marker(const char *line, size_t len, char *fence_char, int *fence_len) {
99
+ if (!line || len == 0 || !fence_char || !fence_len) return false;
100
+
101
+ size_t i = 0;
102
+ int indent = 0;
103
+ while (i < len && line[i] == ' ' && indent < 4) {
104
+ i++;
105
+ indent++;
106
+ }
107
+ if (indent > 3 || i >= len) return false;
108
+
109
+ char c = line[i];
110
+ if (c != '`' && c != '~') return false;
111
+
112
+ size_t j = i;
113
+ while (j < len && line[j] == c) {
114
+ j++;
115
+ }
116
+ int run = (int)(j - i);
117
+ if (run < 3) return false;
118
+
119
+ *fence_char = c;
120
+ *fence_len = run;
121
+ return true;
122
+ }
123
+
124
+ /* Closing fence must be only fence chars followed by optional spaces/tabs. */
125
+ static bool is_closing_fence(const char *line, size_t len, char fence_char, int fence_len) {
126
+ if (!line || len == 0 || !fence_char || fence_len < 3) return false;
127
+
128
+ size_t i = 0;
129
+ int indent = 0;
130
+ while (i < len && line[i] == ' ' && indent < 4) {
131
+ i++;
132
+ indent++;
133
+ }
134
+ if (indent > 3 || i >= len || line[i] != fence_char) return false;
135
+
136
+ size_t j = i;
137
+ while (j < len && line[j] == fence_char) {
138
+ j++;
139
+ }
140
+ if ((int)(j - i) < fence_len) return false;
141
+
142
+ while (j < len) {
143
+ if (line[j] != ' ' && line[j] != '\t') {
144
+ return false;
145
+ }
146
+ j++;
147
+ }
148
+
149
+ return true;
150
+ }
151
+
94
152
  /**
95
153
  * Check if a line is a horizontal rule (--- on a line by itself)
96
154
  */
@@ -290,6 +348,9 @@ static char *apex_process_relaxed_tables_impl(const char *text,
290
348
  char *write = output;
291
349
  size_t remaining = output_capacity;
292
350
  size_t output_len = 0;
351
+ bool in_fenced_code = false;
352
+ char fenced_char = 0;
353
+ int fenced_len = 0;
293
354
 
294
355
  /* Track potential table rows */
295
356
  typedef struct {
@@ -316,6 +377,59 @@ static char *apex_process_relaxed_tables_impl(const char *text,
316
377
 
317
378
  size_t line_len = line_end - line_start;
318
379
  bool has_newline = (*line_end == '\n');
380
+ char marker_char = 0;
381
+ int marker_len = 0;
382
+ bool has_fence_marker = parse_fence_marker(line_start, line_len, &marker_char, &marker_len);
383
+
384
+ if (!in_fenced_code && has_fence_marker) {
385
+ in_fenced_code = true;
386
+ fenced_char = marker_char;
387
+ fenced_len = marker_len;
388
+ } else if (in_fenced_code && is_closing_fence(line_start, line_len, fenced_char, fenced_len)) {
389
+ in_fenced_code = false;
390
+ fenced_char = 0;
391
+ fenced_len = 0;
392
+ }
393
+
394
+ /* Skip grid tables (lines starting with +) so relaxed table detection
395
+ * does not treat grid borders as pipe table rows. */
396
+ if (!in_fenced_code) {
397
+ const char *line_check = line_start;
398
+ while (line_check < line_end && (*line_check == ' ' || *line_check == '\t')) {
399
+ line_check++;
400
+ }
401
+ if (line_check < line_end && *line_check == '+') {
402
+ if (rows_count > 0) {
403
+ for (size_t i = 0; i < rows_count; i++) {
404
+ if (rows[i].len < remaining) {
405
+ memcpy(write, rows[i].start, rows[i].len);
406
+ write += rows[i].len;
407
+ remaining -= rows[i].len;
408
+ output_len += rows[i].len;
409
+ if (has_newline && remaining > 0) {
410
+ *write++ = '\n';
411
+ remaining--;
412
+ output_len++;
413
+ }
414
+ }
415
+ }
416
+ rows_count = 0;
417
+ }
418
+ if (line_len < remaining) {
419
+ memcpy(write, line_start, line_len);
420
+ write += line_len;
421
+ remaining -= line_len;
422
+ output_len += line_len;
423
+ if (has_newline && remaining > 0) {
424
+ *write++ = '\n';
425
+ remaining--;
426
+ output_len++;
427
+ }
428
+ }
429
+ read = has_newline ? line_end + 1 : line_end;
430
+ continue;
431
+ }
432
+ }
319
433
 
320
434
  /* Check if this is a blank line */
321
435
  if (is_blank_line(line_start, line_len)) {
@@ -455,7 +569,7 @@ static char *apex_process_relaxed_tables_impl(const char *text,
455
569
  }
456
570
 
457
571
  /* Check if this is a separator row */
458
- if (is_separator_row(line_start, line_len)) {
572
+ if (!in_fenced_code && is_separator_row(line_start, line_len)) {
459
573
  /* Separator row: if we have accumulated rows, write them as-is */
460
574
  if (rows_count > 0) {
461
575
  for (size_t i = 0; i < rows_count; i++) {
@@ -637,7 +751,7 @@ static char *apex_process_relaxed_tables_impl(const char *text,
637
751
  bool starts_with_pipe = (p < line_end && *p == '|');
638
752
 
639
753
  /* Check if this is a separator row - if so, skip relaxed table processing for previous rows */
640
- if (is_separator_row(line_start, line_len)) {
754
+ if (!in_fenced_code && is_separator_row(line_start, line_len)) {
641
755
  /* Separator row found - if we have accumulated rows, they're already a valid table */
642
756
  /* Write them as-is and reset */
643
757
  if (rows_count > 0) {
@@ -724,7 +838,7 @@ static char *apex_process_relaxed_tables_impl(const char *text,
724
838
  }
725
839
 
726
840
  /* Process rows with or without leading pipes - both need separators if missing */
727
- int columns = count_columns(line_start, line_len);
841
+ int columns = in_fenced_code ? -1 : count_columns(line_start, line_len);
728
842
  if (columns > 0) {
729
843
  /* Potential table row - add to accumulator */
730
844
  if (rows_count == 0) {
@@ -10,6 +10,30 @@
10
10
  #include <ctype.h>
11
11
  #include <stdbool.h>
12
12
 
13
+ /** True if content at p looks like a list marker (- , * , + , or digit+. ) */
14
+ static int looks_like_list_marker(const char *p) {
15
+ if (!*p) return 0;
16
+ if (*p == '-' || *p == '*' || *p == '+')
17
+ return (p[1] == ' ' || p[1] == '\t');
18
+ if (isdigit((unsigned char)*p)) {
19
+ while (isdigit((unsigned char)*p)) p++;
20
+ return (*p == '.' && (p[1] == ' ' || p[1] == '\t'));
21
+ }
22
+ return 0;
23
+ }
24
+
25
+ /** True if we're at the start of a line that is an indented code block (4+ spaces or tab). */
26
+ static int line_is_indented_code_block(const char *read) {
27
+ if (!*read) return 0;
28
+ if (*read == '\t')
29
+ return !looks_like_list_marker(read + 1);
30
+ if (read[0] != ' ' || read[1] != ' ' || read[2] != ' ' || read[3] != ' ')
31
+ return 0;
32
+ const char *content = read + 4;
33
+ while (*content == ' ') content++;
34
+ return *content && !looks_like_list_marker(content);
35
+ }
36
+
13
37
  /**
14
38
  * Process special markers in text
15
39
  */
@@ -26,7 +50,36 @@ char *apex_process_special_markers(const char *text) {
26
50
  char *write = output;
27
51
  size_t remaining = capacity;
28
52
 
53
+ bool in_code_block = false;
54
+ bool in_inline_code = false;
55
+ bool in_indented_code_block = false;
56
+
29
57
  while (*read) {
58
+ /* At line start: indented code block only if 4+ spaces/tab and not a list line */
59
+ if (read == text || read[-1] == '\n') {
60
+ in_indented_code_block = line_is_indented_code_block(read);
61
+ }
62
+
63
+ /* Track fenced code blocks (```) and inline code (`) */
64
+ if (*read == '`') {
65
+ if (read[1] == '`' && read[2] == '`') {
66
+ in_code_block = !in_code_block;
67
+ } else if (!in_code_block) {
68
+ in_inline_code = !in_inline_code;
69
+ }
70
+ }
71
+
72
+ /* Skip special marker processing inside any code context */
73
+ if (in_code_block || in_inline_code || in_indented_code_block) {
74
+ if (remaining > 0) {
75
+ *write++ = *read++;
76
+ remaining--;
77
+ } else {
78
+ read++;
79
+ }
80
+ continue;
81
+ }
82
+
30
83
  /* Check for End of Block marker (Kramdown) */
31
84
  /* Pattern: ^ on a line by itself (with optional leading whitespace) */
32
85
  if (*read == '^') {
@@ -443,8 +443,30 @@ char *apex_apply_syntax_highlighting(const char *html, const char *tool, bool li
443
443
  continue;
444
444
  }
445
445
 
446
+ /* Per-block line numbers from Quarto/Pandoc fence attr markers */
447
+ bool block_line_numbers = line_numbers;
448
+ if (!block_line_numbers && pre_start > html) {
449
+ size_t lookback = (size_t)(pre_start - html);
450
+ if (lookback > 512) {
451
+ lookback = 512;
452
+ }
453
+ const char *region_start = pre_start - lookback;
454
+ char region_buf[513];
455
+ memcpy(region_buf, region_start, lookback);
456
+ region_buf[lookback] = '\0';
457
+ if (strstr(region_buf, "data-linenos=\"true\"")) {
458
+ block_line_numbers = true;
459
+ }
460
+ }
461
+ if (!block_line_numbers) {
462
+ const char *linenos_attr = strstr(pre_start, "data-linenos=\"true\"");
463
+ if (linenos_attr && linenos_attr < pre_tag_end) {
464
+ block_line_numbers = true;
465
+ }
466
+ }
467
+
446
468
  /* Run syntax highlighter */
447
- char *highlighted = highlight_code_block(code, language, tool, line_numbers, ansi_output, theme);
469
+ char *highlighted = highlight_code_block(code, language, tool, block_line_numbers, ansi_output, theme);
448
470
  free(code);
449
471
 
450
472
  if (highlighted && *highlighted) {