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
@@ -259,6 +259,13 @@ void test_bracketed_spans(void) {
259
259
  assert_not_contains(html, "[Text with [nested brackets]]{.nested}", "Bracketed span syntax removed");
260
260
  apex_free_string(html);
261
261
 
262
+ /* Class-only span must not produce <spanclass=...> (space before class attribute) */
263
+ const char *class_only = "[smallcaps text]{.smallcaps}";
264
+ html = apex_markdown_to_html(class_only, strlen(class_only), &opts);
265
+ assert_contains(html, "<span class=\"smallcaps\">", "Class-only bracketed span has valid class attribute");
266
+ assert_not_contains(html, "<spanclass", "Class-only bracketed span does not merge tag and class");
267
+ apex_free_string(html);
268
+
262
269
  /* Test that spans are disabled when flag is off */
263
270
  apex_options no_spans = apex_options_default();
264
271
  no_spans.enable_spans = false;
@@ -260,6 +260,31 @@ void test_marked_integration_features(void) {
260
260
  }
261
261
  apex_free_string(html);
262
262
 
263
+ /* Indented {::pagebreak /} must not break markdown-in-html blockquote processing */
264
+ opts = apex_options_default();
265
+ opts.enable_markdown_in_html = true;
266
+ opts.enable_marked_extensions = true;
267
+ const char *pagebreak_html =
268
+ "<blockquote class=\"tip\" markdown=\"1\">\n"
269
+ "Tip with [link](doc.html) and <span>HTML</span>.\n"
270
+ "</blockquote>\n"
271
+ "## Page breaks\n"
272
+ " {::pagebreak /}";
273
+ html = apex_markdown_to_html(pagebreak_html, strlen(pagebreak_html), &opts);
274
+ assert_contains(html, "<blockquote", "Blockquote preserved with markdown-in-html");
275
+ assert_contains(html, "<a href=\"doc.html\">link</a>", "Blockquote markdown parsed inside markdown=\"1\"");
276
+ assert_contains(html, "<h2", "Heading after blockquote rendered");
277
+ assert_contains(html, "<pre><code>{::pagebreak /}", "Indented Leanpub pagebreak marker in code block");
278
+ assert_not_contains(html, "class=\"mkpagebreak", "Indented Leanpub pagebreak marker not converted");
279
+ const char *bq_h2 = strstr(html, "<h2");
280
+ const char *bq_pre = strstr(html, "<pre>");
281
+ if (bq_h2 && bq_pre && bq_h2 < bq_pre) {
282
+ test_result(true, "Heading before code block in markdown-in-html pagebreak repro");
283
+ } else {
284
+ test_result(false, "Heading should appear before code block in markdown-in-html pagebreak repro");
285
+ }
286
+ apex_free_string(html);
287
+
263
288
  bool had_failures = suite_end(suite_failures);
264
289
  print_suite_title("Marked Integration Features Tests", had_failures, false);
265
290
  }
@@ -94,6 +94,86 @@ void test_metadata(void) {
94
94
  assert_contains(html, "<li>Third item</li>", "List with colon: third item rendered");
95
95
  apex_free_string(html);
96
96
 
97
+ /* H1 then a paragraph with ": " must not strip the paragraph as MMD metadata */
98
+ const char *h1_colon_para =
99
+ "# My Title\n"
100
+ "\n"
101
+ "This is a note: it has a colon in the first sentence.\n"
102
+ "\n"
103
+ "More content.\n";
104
+ html = apex_markdown_to_html(h1_colon_para, strlen(h1_colon_para), &unified_opts);
105
+ assert_contains(html, "<h1", "H1+colon para: heading rendered");
106
+ assert_contains(html, "My Title", "H1+colon para: heading text preserved");
107
+ assert_contains(html, "This is a note: it has a colon", "H1+colon para: paragraph preserved");
108
+ assert_contains(html, "More content.", "H1+colon para: following paragraph preserved");
109
+ apex_free_string(html);
110
+
111
+ /* Leading blank line disables undelimited MMD metadata */
112
+ const char *leading_blank_meta =
113
+ "\n"
114
+ "Title: Should Not Strip\n"
115
+ "\n"
116
+ "# Body\n";
117
+ html = apex_markdown_to_html(leading_blank_meta, strlen(leading_blank_meta), &opts);
118
+ assert_contains(html, "Title: Should Not Strip", "Leading blank: metadata-like line kept as content");
119
+ assert_contains(html, "Body", "Leading blank: body heading rendered");
120
+ apex_free_string(html);
121
+
122
+ /* Valid single short MMD key/value still works */
123
+ const char *single_mmd = "Title: Only Title\n\n# [%Title]\n";
124
+ html = apex_markdown_to_html(single_mmd, strlen(single_mmd), &opts);
125
+ assert_contains(html, "Only Title</h1>", "Single short MMD metadata still works");
126
+ assert_not_contains(html, "Title: Only Title", "Single short MMD metadata is stripped");
127
+ apex_free_string(html);
128
+
129
+ /* Keys with punctuation other than space/-/_ are not metadata */
130
+ const char *punct_key =
131
+ "Hello, world: not metadata\n"
132
+ "\n"
133
+ "# Body\n";
134
+ html = apex_markdown_to_html(punct_key, strlen(punct_key), &opts);
135
+ assert_contains(html, "Hello, world: not metadata", "Punctuation in key keeps line as content");
136
+ apex_free_string(html);
137
+
138
+ /* Single metadata-like line longer than 100 chars is treated as content */
139
+ {
140
+ char long_doc[256];
141
+ char key[41];
142
+ char val[71];
143
+ memset(key, 'a', 40); key[40] = '\0';
144
+ memset(val, 'b', 70); val[70] = '\0';
145
+ /* "aaaa...: bbbb..." is > 100 chars on the first line */
146
+ snprintf(long_doc, sizeof(long_doc), "%s: %s\n\n# Body\n", key, val);
147
+ assert_option_bool(strlen(key) + 2 + strlen(val) > 100, true,
148
+ "long-line fixture first line is >100 chars");
149
+ html = apex_markdown_to_html(long_doc, strlen(long_doc), &opts);
150
+ assert_contains(html, key, "Long single colon-line kept as content (key)");
151
+ assert_contains(html, "Body", "Long single colon-line: body heading rendered");
152
+ apex_free_string(html);
153
+ }
154
+
155
+ /* Multiple short metadata lines still work (including keys with spaces/-/_) */
156
+ const char *multi_mmd =
157
+ "Title: Multi Title\n"
158
+ "Base Header Level: 2\n"
159
+ "css-file: style.css\n"
160
+ "\n"
161
+ "# Section\n";
162
+ html = apex_markdown_to_html(multi_mmd, strlen(multi_mmd), &opts);
163
+ assert_not_contains(html, "Title: Multi Title", "Multi MMD: title stripped");
164
+ assert_not_contains(html, "Base Header Level:", "Multi MMD: spaced key stripped");
165
+ assert_contains(html, "Section", "Multi MMD: body remains");
166
+ apex_free_string(html);
167
+
168
+ /* No space after colon is not metadata (e.g. bare URLs / ratios) */
169
+ const char *no_space_after_colon =
170
+ "https://example.com/path\n"
171
+ "\n"
172
+ "# Body\n";
173
+ html = apex_markdown_to_html(no_space_after_colon, strlen(no_space_after_colon), &opts);
174
+ assert_contains(html, "https://example.com/path", "No space after colon: URL kept as content");
175
+ apex_free_string(html);
176
+
97
177
  bool had_failures = suite_end(suite_failures);
98
178
  print_suite_title("Metadata Tests", had_failures, false);
99
179
  }
@@ -626,11 +706,19 @@ void test_metadata_control_options(void) {
626
706
  item->next = metadata;
627
707
  metadata = item;
628
708
 
709
+ item = malloc(sizeof(apex_metadata_item));
710
+ item->key = strdup("toc-min-max");
711
+ item->value = strdup("2,4");
712
+ item->next = metadata;
713
+ metadata = item;
714
+
629
715
  apex_apply_metadata_to_options(metadata, &opts);
630
716
 
631
717
  assert_option_string(opts.document_title, "My Test Document", "title sets document_title");
632
718
  assert_option_string(opts.csl_file, "apa.csl", "csl sets csl_file");
633
719
  assert_option_bool(opts.id_format == 1, true, "id-format: mmd sets id_format to 1 (MMD)");
720
+ assert_option_bool(opts.toc_min == 2, true, "toc-min-max: 2,4 sets toc_min to 2");
721
+ assert_option_bool(opts.toc_max == 4, true, "toc-min-max: 2,4 sets toc_max to 4");
634
722
 
635
723
  apex_free_metadata(metadata);
636
724
  metadata = NULL;
@@ -711,6 +799,33 @@ void test_metadata_control_options(void) {
711
799
 
712
800
  apex_free_metadata(metadata);
713
801
 
802
+ /* Test public API for loading and applying metadata from a file */
803
+ #ifdef TEST_FIXTURES_DIR
804
+ opts = apex_options_default();
805
+ opts.enable_indices = true;
806
+ char public_metadata_file_path[512];
807
+ snprintf(public_metadata_file_path, sizeof(public_metadata_file_path), "%s/metadata_options.yml", TEST_FIXTURES_DIR);
808
+
809
+ assert_option_bool(apex_options_apply_meta_file(NULL, public_metadata_file_path), false,
810
+ "metadata file API rejects NULL options");
811
+ assert_option_bool(apex_options_apply_meta_file(&opts, NULL), false,
812
+ "metadata file API rejects NULL path");
813
+ assert_option_bool(apex_options_apply_meta_file(&opts, ""), false,
814
+ "metadata file API rejects empty path");
815
+ assert_option_bool(apex_options_apply_meta_file(&opts, "/no/such/apex-metadata-file.yml"), false,
816
+ "metadata file API rejects missing file");
817
+ assert_option_bool(opts.enable_indices, true,
818
+ "metadata file API leaves options unchanged on failure");
819
+ assert_option_bool(apex_options_apply_meta_file(&opts, public_metadata_file_path), true,
820
+ "metadata file API loads a valid file");
821
+ assert_option_bool(opts.enable_indices, false,
822
+ "metadata file API applies boolean options");
823
+ assert_option_string(opts.csl_file, "test.csl",
824
+ "metadata file API owns csl after returning");
825
+ assert_option_string(opts.document_title, "Test Document from File",
826
+ "metadata file API owns title after returning");
827
+ #endif
828
+
714
829
  /* Test loading metadata from file */
715
830
  #ifdef TEST_FIXTURES_DIR
716
831
  opts = apex_options_default();
@@ -912,6 +1027,20 @@ void test_syntax_highlight_options(void) {
912
1027
  apex_free_metadata(metadata);
913
1028
  metadata = NULL;
914
1029
 
1030
+ /* paginate: symbols */
1031
+ opts = apex_options_default();
1032
+ item = malloc(sizeof(apex_metadata_item));
1033
+ item->key = strdup("paginate");
1034
+ item->value = strdup("symbols");
1035
+ item->next = NULL;
1036
+ metadata = item;
1037
+
1038
+ apex_apply_metadata_to_options(metadata, &opts);
1039
+ assert_option_bool(opts.paginate, true, "paginate: symbols enables paginate");
1040
+ assert_option_bool(opts.paginate_symbols, true, "paginate: symbols enables paginate_symbols");
1041
+ apex_free_metadata(metadata);
1042
+ metadata = NULL;
1043
+
915
1044
  /* Test code_line_numbers option with underscore (alternate key format) */
916
1045
  opts = apex_options_default();
917
1046
  item = malloc(sizeof(apex_metadata_item));