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
@@ -5,10 +5,210 @@
5
5
 
6
6
  #include "toc.h"
7
7
  #include "header_ids.h"
8
+ #include "apex/apex.h"
8
9
  #include <string.h>
9
10
  #include <stdlib.h>
10
11
  #include <stdio.h>
11
12
  #include <ctype.h>
13
+ #include <stdbool.h>
14
+
15
+ /* Placeholders for backslash-escaped {{TOC...}} markers preserved through parsing. */
16
+ static char **escaped_toc_originals = NULL;
17
+ static size_t escaped_toc_count = 0;
18
+
19
+ static void clear_escaped_toc_store(void) {
20
+ if (escaped_toc_originals) {
21
+ for (size_t i = 0; i < escaped_toc_count; i++) {
22
+ free(escaped_toc_originals[i]);
23
+ }
24
+ free(escaped_toc_originals);
25
+ }
26
+ escaped_toc_originals = NULL;
27
+ escaped_toc_count = 0;
28
+ }
29
+
30
+ static bool is_escaped_mmd_toc_start(const char *p) {
31
+ return p[0] == '\\' && p[1] == '{' && p[2] == '\\' && p[3] == '{' &&
32
+ strncmp(p + 4, "TOC", 3) == 0;
33
+ }
34
+
35
+ static const char *find_escaped_mmd_toc_end(const char *start) {
36
+ const char *p = start + 7;
37
+ while (*p) {
38
+ if (p[0] == '\\' && p[1] == '}' && p[2] == '\\' && p[3] == '}') {
39
+ return p + 3;
40
+ }
41
+ p++;
42
+ }
43
+ return NULL;
44
+ }
45
+
46
+ static char *build_unescaped_toc_marker(const char *escaped_start, const char *escaped_end) {
47
+ /* \{\{ ... \}\} -> {{ ... }} */
48
+ const char *inner = escaped_start + 4;
49
+ size_t inner_len = (size_t)(escaped_end - inner - 3);
50
+ size_t out_len = inner_len + 4;
51
+ char *out = malloc(out_len + 1);
52
+ if (!out) return NULL;
53
+ out[0] = '{';
54
+ out[1] = '{';
55
+ memcpy(out + 2, inner, inner_len);
56
+ out[2 + inner_len] = '}';
57
+ out[3 + inner_len] = '}';
58
+ out[out_len] = '\0';
59
+ return out;
60
+ }
61
+
62
+ char *apex_protect_escaped_toc_markers(const char *text) {
63
+ if (!text) return NULL;
64
+
65
+ clear_escaped_toc_store();
66
+
67
+ size_t len = strlen(text);
68
+ size_t capacity = len + 64;
69
+ char *output = malloc(capacity);
70
+ if (!output) return NULL;
71
+
72
+ const char *read = text;
73
+ char *write = output;
74
+ size_t remaining = capacity;
75
+
76
+ while (*read) {
77
+ if (is_escaped_mmd_toc_start(read)) {
78
+ const char *end = find_escaped_mmd_toc_end(read);
79
+ if (end) {
80
+ char *original = build_unescaped_toc_marker(read, end);
81
+ if (!original) {
82
+ free(output);
83
+ clear_escaped_toc_store();
84
+ return NULL;
85
+ }
86
+
87
+ char **new_store = realloc(escaped_toc_originals,
88
+ (escaped_toc_count + 1) * sizeof(char *));
89
+ if (!new_store) {
90
+ free(original);
91
+ free(output);
92
+ clear_escaped_toc_store();
93
+ return NULL;
94
+ }
95
+ escaped_toc_originals = new_store;
96
+ escaped_toc_originals[escaped_toc_count++] = original;
97
+
98
+ char placeholder[64];
99
+ int ph_len = snprintf(placeholder, sizeof(placeholder),
100
+ "@APEX_ESCAPED_TOC_%zu@", escaped_toc_count - 1);
101
+ if ((size_t)ph_len >= remaining) {
102
+ size_t written = (size_t)(write - output);
103
+ capacity = written + (size_t)ph_len + len + 64;
104
+ char *new_output = realloc(output, capacity);
105
+ if (!new_output) {
106
+ free(output);
107
+ clear_escaped_toc_store();
108
+ return NULL;
109
+ }
110
+ output = new_output;
111
+ write = output + written;
112
+ remaining = capacity - written;
113
+ }
114
+ memcpy(write, placeholder, (size_t)ph_len);
115
+ write += ph_len;
116
+ remaining -= (size_t)ph_len;
117
+ read = end + 1;
118
+ continue;
119
+ }
120
+ }
121
+
122
+ if (remaining == 0) {
123
+ size_t written = (size_t)(write - output);
124
+ capacity = (written + len + 64) * 2;
125
+ char *new_output = realloc(output, capacity);
126
+ if (!new_output) {
127
+ free(output);
128
+ clear_escaped_toc_store();
129
+ return NULL;
130
+ }
131
+ output = new_output;
132
+ write = output + written;
133
+ remaining = capacity - written;
134
+ }
135
+ *write++ = *read++;
136
+ remaining--;
137
+ }
138
+
139
+ *write = '\0';
140
+ return output;
141
+ }
142
+
143
+ char *apex_restore_escaped_toc_markers(const char *html) {
144
+ if (!html) return NULL;
145
+ if (escaped_toc_count == 0) return strdup(html);
146
+
147
+ size_t len = strlen(html);
148
+ size_t capacity = len + escaped_toc_count * 32;
149
+ char *output = malloc(capacity);
150
+ if (!output) return NULL;
151
+
152
+ const char *read = html;
153
+ char *write = output;
154
+ size_t remaining = capacity;
155
+
156
+ while (*read) {
157
+ if (strncmp(read, "@APEX_ESCAPED_TOC_", 18) == 0) {
158
+ const char *idx_start = read + 18;
159
+ const char *idx_end = strchr(idx_start, '@');
160
+ if (idx_end && idx_end > idx_start) {
161
+ char idx_buf[32];
162
+ size_t idx_len = (size_t)(idx_end - idx_start);
163
+ if (idx_len < sizeof(idx_buf)) {
164
+ memcpy(idx_buf, idx_start, idx_len);
165
+ idx_buf[idx_len] = '\0';
166
+ size_t index = (size_t)atoi(idx_buf);
167
+ if (index < escaped_toc_count && escaped_toc_originals[index]) {
168
+ const char *original = escaped_toc_originals[index];
169
+ size_t orig_len = strlen(original);
170
+ if (orig_len >= remaining) {
171
+ size_t written = (size_t)(write - output);
172
+ capacity = written + orig_len + 64;
173
+ char *new_output = realloc(output, capacity);
174
+ if (!new_output) {
175
+ free(output);
176
+ return NULL;
177
+ }
178
+ output = new_output;
179
+ write = output + written;
180
+ remaining = capacity - written;
181
+ }
182
+ memcpy(write, original, orig_len);
183
+ write += orig_len;
184
+ remaining -= orig_len;
185
+ read = idx_end + 1;
186
+ continue;
187
+ }
188
+ }
189
+ }
190
+ }
191
+
192
+ if (remaining == 0) {
193
+ size_t written = (size_t)(write - output);
194
+ capacity = (written + len + 64) * 2;
195
+ char *new_output = realloc(output, capacity);
196
+ if (!new_output) {
197
+ free(output);
198
+ return NULL;
199
+ }
200
+ output = new_output;
201
+ write = output + written;
202
+ remaining = capacity - written;
203
+ }
204
+ *write++ = *read++;
205
+ remaining--;
206
+ }
207
+
208
+ *write = '\0';
209
+ clear_escaped_toc_store();
210
+ return output;
211
+ }
12
212
 
13
213
  /**
14
214
  * Collect headers from AST
@@ -20,6 +220,61 @@ typedef struct header_item {
20
220
  struct header_item *next;
21
221
  } header_item;
22
222
 
223
+ /* Normalize heading text for TOC labels:
224
+ * - trim leading/trailing whitespace
225
+ * - collapse internal whitespace runs to a single space
226
+ */
227
+ static char *normalize_toc_text(const char *text) {
228
+ if (!text) return strdup("");
229
+
230
+ size_t len = strlen(text);
231
+ char *out = malloc(len + 1);
232
+ if (!out) return strdup("");
233
+
234
+ const unsigned char *read = (const unsigned char *)text;
235
+ while (*read && isspace(*read)) read++;
236
+
237
+ char *write = out;
238
+ int pending_space = 0;
239
+
240
+ while (*read) {
241
+ if (isspace(*read)) {
242
+ pending_space = 1;
243
+ } else {
244
+ if (pending_space && write > out) {
245
+ *write++ = ' ';
246
+ }
247
+ *write++ = (char)*read;
248
+ pending_space = 0;
249
+ }
250
+ read++;
251
+ }
252
+
253
+ *write = '\0';
254
+ return out;
255
+ }
256
+
257
+ static char *heading_id_from_attrs_or_text(const char *attrs, const char *text,
258
+ apex_id_format_t id_format) {
259
+ if (attrs) {
260
+ const char *id_attr = strstr(attrs, "id=\"");
261
+ if (id_attr) {
262
+ const char *id_start = id_attr + 4;
263
+ const char *id_end = strchr(id_start, '"');
264
+ if (id_end && id_end > id_start) {
265
+ size_t id_len = (size_t)(id_end - id_start);
266
+ char *id = malloc(id_len + 1);
267
+ if (id) {
268
+ memcpy(id, id_start, id_len);
269
+ id[id_len] = '\0';
270
+ return id;
271
+ }
272
+ }
273
+ }
274
+ }
275
+ return apex_generate_header_id(text, id_format);
276
+ }
277
+
23
278
  static void free_headers(header_item *headers) {
24
279
  while (headers) {
25
280
  header_item *next = headers->next;
@@ -30,12 +285,42 @@ static void free_headers(header_item *headers) {
30
285
  }
31
286
  }
32
287
 
288
+ static void clamp_toc_levels(int *min_level, int *max_level) {
289
+ if (*min_level < 1) *min_level = 1;
290
+ if (*max_level < 1) *max_level = 1;
291
+ if (*min_level > 6) *min_level = 6;
292
+ if (*max_level > 6) *max_level = 6;
293
+ if (*min_level > *max_level) *min_level = *max_level;
294
+ }
295
+
296
+ static bool append_toc_markdown(char **buffer, size_t *capacity, size_t *length,
297
+ const char *text, size_t text_len) {
298
+ if (!buffer || !*buffer || !capacity || !length) return false;
299
+
300
+ if (*length + text_len + 1 > *capacity) {
301
+ size_t new_capacity = *capacity;
302
+ while (*length + text_len + 1 > new_capacity) {
303
+ new_capacity *= 2;
304
+ }
305
+ char *new_buffer = realloc(*buffer, new_capacity);
306
+ if (!new_buffer) return false;
307
+ *buffer = new_buffer;
308
+ *capacity = new_capacity;
309
+ }
310
+
311
+ memcpy(*buffer + *length, text, text_len);
312
+ *length += text_len;
313
+ (*buffer)[*length] = '\0';
314
+ return true;
315
+ }
316
+
33
317
 
34
318
 
35
319
  /**
36
320
  * Collect all headers from document
37
321
  */
38
- static header_item *collect_headers(cmark_node *node, header_item **tail) {
322
+ static header_item *collect_headers(cmark_node *node, header_item **tail,
323
+ apex_id_format_t id_format) {
39
324
  if (!node) return NULL;
40
325
 
41
326
  header_item *headers = NULL;
@@ -54,8 +339,10 @@ static header_item *collect_headers(cmark_node *node, header_item **tail) {
54
339
  header_item *item = malloc(sizeof(header_item));
55
340
  if (item) {
56
341
  item->level = cmark_node_get_heading_level(node);
57
- item->text = apex_extract_heading_text(node);
58
- item->id = NULL; /* Will be set later with format */
342
+ char *raw_text = apex_extract_heading_text(node);
343
+ item->text = normalize_toc_text(raw_text);
344
+ free(raw_text);
345
+ item->id = heading_id_from_attrs_or_text(attrs, item->text, id_format);
59
346
  item->next = NULL;
60
347
 
61
348
  if (*tail) {
@@ -70,7 +357,7 @@ static header_item *collect_headers(cmark_node *node, header_item **tail) {
70
357
 
71
358
  /* Recursively process children */
72
359
  for (cmark_node *child = cmark_node_first_child(node); child; child = cmark_node_next(child)) {
73
- header_item *child_headers = collect_headers(child, tail);
360
+ header_item *child_headers = collect_headers(child, tail, id_format);
74
361
  if (!headers) headers = child_headers;
75
362
  }
76
363
 
@@ -91,7 +378,7 @@ static char *generate_toc_html(header_item *headers, int min_level, int max_leve
91
378
  char *write = html;
92
379
  size_t remaining = capacity;
93
380
  int current_level = 0;
94
- int last_level = 0; /* level of last item added (0 = none yet) */
381
+ int last_level = 0; /* normalized level of last item added (0 = none yet) */
95
382
 
96
383
  #define APPEND(str) do { \
97
384
  size_t len = strlen(str); \
@@ -107,9 +394,11 @@ static char *generate_toc_html(header_item *headers, int min_level, int max_leve
107
394
  for (header_item *h = headers; h; h = h->next) {
108
395
  /* Skip headers outside min/max range */
109
396
  if (h->level < min_level || h->level > max_level) continue;
397
+ int target_level = h->level - min_level + 1;
398
+ if (target_level < 1) target_level = 1;
110
399
 
111
400
  /* Going up: close </ul></li> for each level (nested ul inside parent li) */
112
- while (current_level > h->level) {
401
+ while (current_level > target_level) {
113
402
  APPEND("</ul>\n</li>\n");
114
403
  current_level--;
115
404
  }
@@ -117,7 +406,7 @@ static char *generate_toc_html(header_item *headers, int min_level, int max_leve
117
406
  /* Going down: open one <ul> inside the previous li before adding child.
118
407
  * At root (current_level 0): only open one ul - never ul > ul.
119
408
  * When going deeper: open exactly one ul per step - never ul > ul. */
120
- while (current_level < h->level) {
409
+ while (current_level < target_level) {
121
410
  if (current_level == 0) {
122
411
  APPEND("<ul>\n");
123
412
  current_level = 1;
@@ -133,7 +422,7 @@ static char *generate_toc_html(header_item *headers, int min_level, int max_leve
133
422
  }
134
423
 
135
424
  /* Close previous li when adding sibling (same or shallower level) */
136
- if (last_level > 0 && h->level <= last_level) {
425
+ if (last_level > 0 && target_level <= last_level) {
137
426
  APPEND("</li>\n");
138
427
  }
139
428
 
@@ -142,7 +431,7 @@ static char *generate_toc_html(header_item *headers, int min_level, int max_leve
142
431
  snprintf(item, sizeof(item), "<li><a href=\"#%s\">%s</a>",
143
432
  h->id, h->text);
144
433
  APPEND(item);
145
- last_level = h->level;
434
+ last_level = target_level;
146
435
  }
147
436
 
148
437
  /* Close remaining: </li></ul> for each open level */
@@ -159,6 +448,108 @@ static char *generate_toc_html(header_item *headers, int min_level, int max_leve
159
448
  return html;
160
449
  }
161
450
 
451
+ void apex_toc_entries_free(apex_toc_entry *entries, size_t count) {
452
+ if (!entries) return;
453
+ for (size_t i = 0; i < count; i++) {
454
+ free(entries[i].text);
455
+ free(entries[i].id);
456
+ }
457
+ free(entries);
458
+ }
459
+
460
+ apex_toc_entry *apex_generate_toc_entries(cmark_node *document, int id_format,
461
+ int min_level, int max_level,
462
+ size_t *out_count) {
463
+ if (out_count) *out_count = 0;
464
+ if (!document || !out_count) return NULL;
465
+
466
+ clamp_toc_levels(&min_level, &max_level);
467
+
468
+ header_item *tail = NULL;
469
+ header_item *headers = collect_headers(document, &tail, (apex_id_format_t)id_format);
470
+ if (!headers) return NULL;
471
+
472
+ size_t count = 0;
473
+ for (header_item *h = headers; h; h = h->next) {
474
+ if (h->level >= min_level && h->level <= max_level) count++;
475
+ }
476
+
477
+ if (count == 0) {
478
+ free_headers(headers);
479
+ return NULL;
480
+ }
481
+
482
+ apex_toc_entry *entries = calloc(count, sizeof(apex_toc_entry));
483
+ if (!entries) {
484
+ free_headers(headers);
485
+ return NULL;
486
+ }
487
+
488
+ size_t idx = 0;
489
+ for (header_item *h = headers; h; h = h->next) {
490
+ if (h->level < min_level || h->level > max_level) continue;
491
+ entries[idx].level = h->level;
492
+ entries[idx].text = h->text ? strdup(h->text) : strdup("");
493
+ entries[idx].id = h->id ? strdup(h->id) : strdup("");
494
+ if (!entries[idx].text || !entries[idx].id) {
495
+ apex_toc_entries_free(entries, idx + 1);
496
+ free_headers(headers);
497
+ return NULL;
498
+ }
499
+ idx++;
500
+ }
501
+
502
+ free_headers(headers);
503
+ *out_count = count;
504
+ return entries;
505
+ }
506
+
507
+ char *apex_generate_toc_markdown(cmark_node *document, int id_format,
508
+ int min_level, int max_level) {
509
+ size_t count = 0;
510
+ apex_toc_entry *entries = apex_generate_toc_entries(document, id_format,
511
+ min_level, max_level,
512
+ &count);
513
+ if (!entries || count == 0) {
514
+ apex_toc_entries_free(entries, count);
515
+ return strdup("");
516
+ }
517
+
518
+ size_t capacity = 1024;
519
+ size_t length = 0;
520
+ char *markdown = malloc(capacity);
521
+ if (!markdown) {
522
+ apex_toc_entries_free(entries, count);
523
+ return strdup("");
524
+ }
525
+ markdown[0] = '\0';
526
+
527
+ clamp_toc_levels(&min_level, &max_level);
528
+
529
+ for (size_t i = 0; i < count; i++) {
530
+ int indent = (entries[i].level - min_level) * 2;
531
+ for (int j = 0; j < indent; j++) {
532
+ if (!append_toc_markdown(&markdown, &capacity, &length, " ", 1)) goto fail;
533
+ }
534
+
535
+ const char *text = entries[i].text ? entries[i].text : "";
536
+ const char *id = entries[i].id ? entries[i].id : "";
537
+ if (!append_toc_markdown(&markdown, &capacity, &length, "- [", 3)) goto fail;
538
+ if (!append_toc_markdown(&markdown, &capacity, &length, text, strlen(text))) goto fail;
539
+ if (!append_toc_markdown(&markdown, &capacity, &length, "](#", 3)) goto fail;
540
+ if (!append_toc_markdown(&markdown, &capacity, &length, id, strlen(id))) goto fail;
541
+ if (!append_toc_markdown(&markdown, &capacity, &length, ")\n", 2)) goto fail;
542
+ }
543
+
544
+ apex_toc_entries_free(entries, count);
545
+ return markdown;
546
+
547
+ fail:
548
+ free(markdown);
549
+ apex_toc_entries_free(entries, count);
550
+ return strdup("");
551
+ }
552
+
162
553
  /**
163
554
  * Return true if position 'pos' in 'html' is inside a <code> or <pre> element.
164
555
  * Used to skip TOC markers that appear in code blocks or inline code.
@@ -218,42 +609,76 @@ static int is_inside_code_or_pre(const char *html, size_t pos) {
218
609
  /**
219
610
  * Parse TOC marker for min/max levels
220
611
  */
221
- static void parse_toc_marker(const char *marker, int *min_level, int *max_level) {
222
- *min_level = 1;
223
- *max_level = 6;
612
+ static void parse_toc_marker(const char *marker, int *min_level, int *max_level,
613
+ int default_min, int default_max) {
614
+ int specified_min = 0;
615
+ int specified_max = 0;
616
+
617
+ *min_level = default_min;
618
+ *max_level = default_max;
619
+
620
+ if (!marker) return;
621
+
622
+ /* Only parse inside the marker, never beyond marker end into following HTML. */
623
+ const char *marker_end = strstr(marker, "}}");
624
+ if (!marker_end) marker_end = strstr(marker, "-->");
625
+ if (!marker_end) {
626
+ marker_end = marker + strlen(marker);
627
+ }
628
+ size_t marker_len = (size_t)(marker_end - marker);
629
+ char *marker_copy = (char *)malloc(marker_len + 1);
630
+ if (!marker_copy) return;
631
+ memcpy(marker_copy, marker, marker_len);
632
+ marker_copy[marker_len] = '\0';
224
633
 
225
634
  /* Look for max and min parameters */
226
- const char *max_str = strstr(marker, "max");
227
- const char *min_str = strstr(marker, "min");
635
+ const char *max_str = strstr(marker_copy, "max");
636
+ const char *min_str = strstr(marker_copy, "min");
228
637
 
229
638
  if (max_str) {
230
639
  max_str += 3;
231
640
  while (*max_str && !isdigit((unsigned char)*max_str)) max_str++;
232
- if (*max_str) *max_level = atoi(max_str);
641
+ if (*max_str) {
642
+ *max_level = atoi(max_str);
643
+ specified_max = 1;
644
+ }
233
645
  }
234
646
 
235
647
  if (min_str) {
236
648
  min_str += 3;
237
649
  while (*min_str && !isdigit((unsigned char)*min_str)) min_str++;
238
- if (*min_str) *min_level = atoi(min_str);
650
+ if (*min_str) {
651
+ *min_level = atoi(min_str);
652
+ specified_min = 1;
653
+ }
239
654
  }
240
655
 
241
656
  /* Check for Pandoc style {{TOC:2-5}} */
242
- const char *colon = strchr(marker, ':');
657
+ const char *colon = strchr(marker_copy, ':');
243
658
  if (colon) {
244
659
  colon++;
245
660
  while (*colon && isspace((unsigned char)*colon)) colon++;
246
661
  if (isdigit((unsigned char)*colon)) {
247
662
  *min_level = atoi(colon);
663
+ specified_min = 1;
248
664
  const char *dash = strchr(colon, '-');
249
665
  if (dash) {
250
666
  dash++;
251
667
  if (isdigit((unsigned char)*dash)) {
252
668
  *max_level = atoi(dash);
669
+ specified_max = 1;
253
670
  }
254
671
  }
255
672
  }
256
673
  }
674
+ free(marker_copy);
675
+
676
+ if (specified_min || specified_max) {
677
+ if (!specified_min) *min_level = 1;
678
+ if (!specified_max) *max_level = 6;
679
+ }
680
+
681
+ clamp_toc_levels(min_level, max_level);
257
682
  }
258
683
 
259
684
  /**
@@ -299,7 +724,8 @@ static const char *find_toc_marker_not_in_code(const char *html, int *is_html_co
299
724
  /**
300
725
  * Process TOC markers in HTML
301
726
  */
302
- char *apex_process_toc(const char *html, cmark_node *document, int id_format) {
727
+ char *apex_process_toc(const char *html, cmark_node *document, int id_format,
728
+ int default_min, int default_max) {
303
729
  if (!html || !document) return html ? strdup(html) : NULL;
304
730
 
305
731
  int is_html_comment = 0;
@@ -311,17 +737,12 @@ char *apex_process_toc(const char *html, cmark_node *document, int id_format) {
311
737
 
312
738
  /* Collect headers from document */
313
739
  header_item *tail = NULL;
314
- header_item *headers = collect_headers(document, &tail);
740
+ header_item *headers = collect_headers(document, &tail, (apex_id_format_t)id_format);
315
741
  if (!headers) return strdup(html);
316
742
 
317
- /* Generate IDs for all headers using the specified format */
318
- for (header_item *h = headers; h; h = h->next) {
319
- h->id = apex_generate_header_id(h->text, (apex_id_format_t)id_format);
320
- }
321
-
322
743
  /* Parse the marker for min/max levels */
323
744
  int min_level, max_level;
324
- parse_toc_marker(marker, &min_level, &max_level);
745
+ parse_toc_marker(marker, &min_level, &max_level, default_min, default_max);
325
746
 
326
747
  /* Generate TOC HTML */
327
748
  char *toc_html = generate_toc_html(headers, min_level, max_level);
@@ -23,8 +23,33 @@ extern "C" {
23
23
  * @param html The HTML output
24
24
  * @param document The AST document
25
25
  * @param id_format 0=GFM (with dashes), 1=MMD (no dashes)
26
+ * @param default_min Default minimum heading level for bare TOC markers
27
+ * @param default_max Default maximum heading level for bare TOC markers
26
28
  */
27
- char *apex_process_toc(const char *html, cmark_node *document, int id_format);
29
+ char *apex_process_toc(const char *html, cmark_node *document, int id_format,
30
+ int default_min, int default_max);
31
+
32
+ /**
33
+ * Generate a Markdown table of contents from document headings.
34
+ * Returns a newly allocated string containing "- [text](#id)" entries.
35
+ * @param document The AST document
36
+ * @param id_format 0=GFM (with dashes), 1=MMD (no dashes)
37
+ * @param min_level Inclusive minimum heading level
38
+ * @param max_level Inclusive maximum heading level
39
+ */
40
+ char *apex_generate_toc_markdown(cmark_node *document, int id_format,
41
+ int min_level, int max_level);
42
+
43
+ /**
44
+ * Replace backslash-escaped {{TOC...}} markers with placeholders before parsing.
45
+ * Call before markdown parse when TOC processing will run later.
46
+ */
47
+ char *apex_protect_escaped_toc_markers(const char *text);
48
+
49
+ /**
50
+ * Restore placeholders to literal {{TOC...}} text in HTML after TOC processing.
51
+ */
52
+ char *apex_restore_escaped_toc_markers(const char *html);
28
53
 
29
54
  #ifdef __cplusplus
30
55
  }
@@ -332,6 +332,11 @@ static cmark_node *match_wiki_link(cmark_syntax_extension *self,
332
332
  const char *input = (const char *)chunk->data + pos;
333
333
  int remaining = chunk->len - pos;
334
334
 
335
+ /* Do not parse Obsidian embeds ![[...]] as regular wiki links. */
336
+ if (pos > 0 && chunk->data[pos - 1] == '!') {
337
+ return NULL;
338
+ }
339
+
335
340
  /* CRITICAL: Must check for [[ to distinguish from regular markdown links [text](url) */
336
341
  if (remaining < 2 || input[0] != '[' || input[1] != '[') {
337
342
  return NULL; /* Not a wiki link, let standard link parser handle it */
@@ -501,6 +506,29 @@ void apex_process_wiki_links_in_tree(cmark_node *node, wiki_link_config *config)
501
506
 
502
507
  size_t content_len = (size_t)(close - (open + 2));
503
508
 
509
+ /* Preserve Obsidian embeds ![[...]] as literal text so include
510
+ * preprocessing can handle them, and avoid rendering !<a ...>. */
511
+ if (open > literal && open[-1] == '!') {
512
+ size_t raw_len = (size_t)((close + 2) - open);
513
+ char *raw = malloc(raw_len + 1);
514
+ if (raw) {
515
+ memcpy(raw, open, raw_len);
516
+ raw[raw_len] = '\0';
517
+ cmark_node *text = cmark_node_new(CMARK_NODE_TEXT);
518
+ cmark_node_set_literal(text, raw);
519
+ free(raw);
520
+ if (!insert_after) {
521
+ cmark_node_insert_before(node, text);
522
+ } else {
523
+ cmark_node_insert_after(insert_after, text);
524
+ }
525
+ insert_after = text;
526
+ changed = true;
527
+ }
528
+ cursor = close + 2;
529
+ continue;
530
+ }
531
+
504
532
  /* If empty content, keep literal text and continue */
505
533
  if (content_len == 0) {
506
534
  size_t raw_len = (size_t)((close + 2) - open);