apex-ruby 1.0.17 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -3
  3. data/ext/apex_ext/apex_ext.c +260 -91
  4. data/ext/apex_ext/apex_src/CHANGELOG.md +440 -0
  5. data/ext/apex_ext/apex_src/CMakeLists.txt +15 -1
  6. data/ext/apex_ext/apex_src/Formula/apex.rb +7 -2
  7. data/ext/apex_ext/apex_src/Package.swift +15 -4
  8. data/ext/apex_ext/apex_src/README.md +94 -35
  9. data/ext/apex_ext/apex_src/VERSION +1 -1
  10. data/ext/apex_ext/apex_src/apex-debug.log +4 -0
  11. data/ext/apex_ext/apex_src/apex.code-workspace +38 -0
  12. data/ext/apex_ext/apex_src/apex.taskpaper +12 -0
  13. data/ext/apex_ext/apex_src/apex_deflist_debug.log +25 -0
  14. data/ext/apex_ext/apex_src/buildnotes.md +1435 -0
  15. data/ext/apex_ext/apex_src/cli/main.c +262 -33
  16. data/ext/apex_ext/apex_src/debug.log +7 -0
  17. data/ext/apex_ext/apex_src/docs/CITATIONS_EXAMPLES.md +274 -0
  18. data/ext/apex_ext/apex_src/docs/CITATIONS_IMPLEMENTATION_PLAN.md +749 -0
  19. data/ext/apex_ext/apex_src/docs/CITATIONS_PLAN.md +744 -0
  20. data/ext/apex_ext/apex_src/docs/INDEX_IMPLEMENTATION_ANALYSIS.md +382 -0
  21. data/ext/apex_ext/apex_src/docs/plans/2025-02-27-man-page-output-implementation.md +351 -0
  22. data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-12-toc-output-format.md +745 -0
  23. data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-18-bear-image-attributes.md +829 -0
  24. data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-19-apex-node-npm.md +1148 -0
  25. data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-12-toc-output-format-design.md +161 -0
  26. data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-18-bear-image-attributes-design.md +184 -0
  27. data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-19-apex-node-npm-design.md +211 -0
  28. data/ext/apex_ext/apex_src/documentation/app-settings-table.md +67 -0
  29. data/ext/apex_ext/apex_src/documentation/app-transformed/Citations.md +340 -0
  30. data/ext/apex_ext/apex_src/documentation/app-transformed/Credits.md +11 -0
  31. data/ext/apex_ext/apex_src/documentation/app-transformed/Header-IDs.md +234 -0
  32. data/ext/apex_ext/apex_src/documentation/app-transformed/Inline-Attribute-Lists.md +516 -0
  33. data/ext/apex_ext/apex_src/documentation/app-transformed/Metadata-Transforms.md +461 -0
  34. data/ext/apex_ext/apex_src/documentation/app-transformed/Modes.md +193 -0
  35. data/ext/apex_ext/apex_src/documentation/app-transformed/Multi-File-Documents.md +201 -0
  36. data/ext/apex_ext/apex_src/documentation/app-transformed/Plugins.md +678 -0
  37. data/ext/apex_ext/apex_src/documentation/app-transformed/Syntax.md +1367 -0
  38. data/ext/apex_ext/apex_src/documentation/docsets/Apex Command Line Options.cheatsheet.txt +6 -0
  39. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/C-API.html +774 -300
  40. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Callouts.html +1194 -0
  41. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Citations.html +416 -216
  42. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Command-Line-Options.html +3544 -1094
  43. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Configuration.html +371 -97
  44. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Credits.html +153 -23
  45. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Examples.html +358 -124
  46. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Filters.html +1656 -0
  47. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Generating-Man-Pages.html +1226 -0
  48. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Getting-Started.html +201 -56
  49. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Header-IDs.html +279 -109
  50. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Home.html +200 -53
  51. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Indices.html +2327 -0
  52. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Inline-Attribute-Lists.html +690 -271
  53. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Installation.html +201 -55
  54. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Limitations-and-Roadmap.html +238 -68
  55. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Metadata-Transforms.html +421 -221
  56. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Modes.html +340 -78
  57. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-File-Documents.html +251 -86
  58. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-Format-Images.html +1362 -0
  59. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Pandoc-Integration.html +277 -90
  60. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Plugins.html +673 -346
  61. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Quarto-Mode.html +1405 -0
  62. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Rendering-Markdown-In-Terminal.html +1902 -0
  63. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Syntax.html +1939 -1698
  64. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Tables.html +1781 -0
  65. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Troubleshooting.html +315 -140
  66. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Usage.html +307 -113
  67. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Using-Apex-with-Jekyll.html +1132 -0
  68. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Writing-Tests.html +1754 -0
  69. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Xcode-Integration.html +872 -376
  70. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/docSet.dsidx +0 -0
  71. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/optimizedIndex.dsidx +0 -0
  72. data/ext/apex_ext/apex_src/documentation/html/apex-app-docs.html +8746 -0
  73. data/ext/apex_ext/apex_src/documentation/shared_styles.css +20 -15
  74. data/ext/apex_ext/apex_src/documentation/transform_for_app.md +55 -0
  75. data/ext/apex_ext/apex_src/escaping-repro.md +103 -0
  76. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/Info.plist +8 -0
  77. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/QuickLook/Preview.png +0 -0
  78. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/document.wflow +547 -0
  79. data/ext/apex_ext/apex_src/examples/quick-actions/Markdown-to-RTF.workflow.zip +0 -0
  80. data/ext/apex_ext/apex_src/examples/quick-actions/README.md +33 -0
  81. data/ext/apex_ext/apex_src/include/apex/apex.h +92 -6
  82. data/ext/apex_ext/apex_src/include/apex/ast_rtf.h +23 -0
  83. data/ext/apex_ext/apex_src/include/apex/ast_terminal.h +6 -0
  84. data/ext/apex_ext/apex_src/include/apex/module.modulemap +5 -0
  85. data/ext/apex_ext/apex_src/include/apex/plugins.h +105 -0
  86. data/ext/apex_ext/apex_src/include/apexc.h +1 -0
  87. data/ext/apex_ext/apex_src/man/apex.1 +82 -78
  88. data/ext/apex_ext/apex_src/man/apex.1.md +81 -4
  89. data/ext/apex_ext/apex_src/objc/Apex.swift +73 -0
  90. data/ext/apex_ext/apex_src/objc/ApexPlugins.swift +79 -0
  91. data/ext/apex_ext/apex_src/objc/NSString+Apex.h +83 -5
  92. data/ext/apex_ext/apex_src/objc/NSString+Apex.m +244 -1
  93. data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.h +76 -0
  94. data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.m +169 -0
  95. data/ext/apex_ext/apex_src/output.html +87 -0
  96. data/ext/apex_ext/apex_src/plans/quarto-mode.md +442 -0
  97. data/ext/apex_ext/apex_src/src/_README.md +85 -32
  98. data/ext/apex_ext/apex_src/src/apex.c +770 -200
  99. data/ext/apex_ext/apex_src/src/ast_rtf.c +848 -0
  100. data/ext/apex_ext/apex_src/src/ast_terminal.c +184 -7
  101. data/ext/apex_ext/apex_src/src/extensions/abbreviations.c +10 -3
  102. data/ext/apex_ext/apex_src/src/extensions/advanced_tables.c +7 -11
  103. data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.c +467 -0
  104. data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.h +27 -0
  105. data/ext/apex_ext/apex_src/src/extensions/callouts.c +400 -4
  106. data/ext/apex_ext/apex_src/src/extensions/callouts.h +15 -5
  107. data/ext/apex_ext/apex_src/src/extensions/citations.c +26 -5
  108. data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.c +632 -0
  109. data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.h +22 -0
  110. data/ext/apex_ext/apex_src/src/extensions/concordance.c +632 -0
  111. data/ext/apex_ext/apex_src/src/extensions/definition_list.c +129 -15
  112. data/ext/apex_ext/apex_src/src/extensions/grid_tables.c +1050 -121
  113. data/ext/apex_ext/apex_src/src/extensions/html_markdown.c +569 -16
  114. data/ext/apex_ext/apex_src/src/extensions/ial.c +502 -52
  115. data/ext/apex_ext/apex_src/src/extensions/ial.h +2 -1
  116. data/ext/apex_ext/apex_src/src/extensions/includes.c +532 -33
  117. data/ext/apex_ext/apex_src/src/extensions/includes.h +7 -1
  118. data/ext/apex_ext/apex_src/src/extensions/index.c +1427 -140
  119. data/ext/apex_ext/apex_src/src/extensions/index.h +28 -0
  120. data/ext/apex_ext/apex_src/src/extensions/metadata.c +200 -161
  121. data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.c +251 -0
  122. data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.h +22 -0
  123. data/ext/apex_ext/apex_src/src/extensions/quarto_lists.c +624 -0
  124. data/ext/apex_ext/apex_src/src/extensions/quarto_lists.h +35 -0
  125. data/ext/apex_ext/apex_src/src/extensions/quarto_polish.c +264 -0
  126. data/ext/apex_ext/apex_src/src/extensions/quarto_polish.h +23 -0
  127. data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.c +307 -0
  128. data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.h +21 -0
  129. data/ext/apex_ext/apex_src/src/extensions/raw_content.c +351 -0
  130. data/ext/apex_ext/apex_src/src/extensions/raw_content.h +20 -0
  131. data/ext/apex_ext/apex_src/src/extensions/relaxed_tables.c +117 -3
  132. data/ext/apex_ext/apex_src/src/extensions/special_markers.c +53 -0
  133. data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.c +23 -1
  134. data/ext/apex_ext/apex_src/src/extensions/table_html_postprocess.c +83 -92
  135. data/ext/apex_ext/apex_src/src/extensions/toc.c +446 -25
  136. data/ext/apex_ext/apex_src/src/extensions/toc.h +26 -1
  137. data/ext/apex_ext/apex_src/src/extensions/wiki_links.c +28 -0
  138. data/ext/apex_ext/apex_src/src/html_renderer.c +387 -17
  139. data/ext/apex_ext/apex_src/src/plugin_catalog.c +517 -0
  140. data/ext/apex_ext/apex_src/src/plugins_remote.c +88 -14
  141. data/ext/apex_ext/apex_src/src/plugins_remote.h +34 -0
  142. data/ext/apex_ext/apex_src/src/pretty_html.c +6 -1
  143. data/ext/apex_ext/apex_src/tests/fixtures/comprehensive_test.md +21 -0
  144. data/ext/apex_ext/apex_src/tests/fixtures/images/bear_image_attributes.md +10 -0
  145. data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.md +19 -0
  146. data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.txt +11 -0
  147. data/ext/apex_ext/apex_src/tests/fixtures/minimal_pb.md +2 -0
  148. data/ext/apex_ext/apex_src/tests/fixtures/obsidian-callouts.md +46 -0
  149. data/ext/apex_ext/apex_src/tests/fixtures/pagebreak_html_repro.md +5 -0
  150. data/ext/apex_ext/apex_src/tests/fixtures/python-callouts.md +47 -0
  151. data/ext/apex_ext/apex_src/tests/fixtures/quarto/callouts.md +3 -0
  152. data/ext/apex_ext/apex_src/tests/fixtures/quarto/code-attrs.md +3 -0
  153. data/ext/apex_ext/apex_src/tests/fixtures/quarto/diagrams.md +8 -0
  154. data/ext/apex_ext/apex_src/tests/fixtures/quarto/lists.md +19 -0
  155. data/ext/apex_ext/apex_src/tests/fixtures/quarto/raw-content.md +5 -0
  156. data/ext/apex_ext/apex_src/tests/fixtures/quarto/shortcodes.md +7 -0
  157. data/ext/apex_ext/apex_src/tests/fixtures/quarto/smoke.md +81 -0
  158. data/ext/apex_ext/apex_src/tests/fixtures/quarto/spans.md +5 -0
  159. data/ext/apex_ext/apex_src/tests/fixtures/quarto-callouts.md +47 -0
  160. data/ext/apex_ext/apex_src/tests/fixtures/speed.md +192 -0
  161. data/ext/apex_ext/apex_src/tests/fixtures/tables/grid-tables.md +37 -0
  162. data/ext/apex_ext/apex_src/tests/paginate_cli_test.sh +16 -0
  163. data/ext/apex_ext/apex_src/tests/test_bear_image_attrs.c +301 -0
  164. data/ext/apex_ext/apex_src/tests/test_concordance.tsv +4 -0
  165. data/ext/apex_ext/apex_src/tests/test_escaping_repro.c +82 -0
  166. data/ext/apex_ext/apex_src/tests/test_extensions.c +821 -1
  167. data/ext/apex_ext/apex_src/tests/test_ial.c +7 -0
  168. data/ext/apex_ext/apex_src/tests/test_marked_integration.c +25 -0
  169. data/ext/apex_ext/apex_src/tests/test_metadata.c +129 -0
  170. data/ext/apex_ext/apex_src/tests/test_output.c +568 -2
  171. data/ext/apex_ext/apex_src/tests/test_runner.c +11 -0
  172. data/ext/apex_ext/apex_src/tests/test_tables.c +420 -0
  173. data/ext/apex_ext/apex_src/vendor/cmark-gfm/CMakeLists.txt +1 -1
  174. data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/autolink.c +77 -1
  175. data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/table.c +135 -5
  176. data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/blocks.c +56 -1
  177. data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/config.h +38 -0
  178. data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/main.c +1 -1
  179. data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/cmark.cpython-314.pyc +0 -0
  180. data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/normalize.cpython-314.pyc +0 -0
  181. data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/extensions.txt +69 -0
  182. data/ext/apex_ext/apex_src/xcode_build/CMakeScripts/ReRunCMake.make +74 -0
  183. data/ext/apex_ext/apex_src/xcode_build/CTestTestfile.cmake +22 -0
  184. data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Apex +0 -0
  185. data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Resources/Info.plist +44 -0
  186. data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/_CodeSignature/CodeResources +128 -0
  187. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.pbxproj +5118 -0
  188. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  189. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  190. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/WorkspaceSettings.xcsettings +8 -0
  191. data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/xcuserdata/ttscoff.xcuserdatad/xcschemes/xcschememanagement.plist +99 -0
  192. data/ext/apex_ext/apex_src/xcode_build/cmake_install.cmake +452 -0
  193. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/CMakeScripts/ReRunCMake.make +52 -0
  194. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmake_install.cmake +55 -0
  195. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.pbxproj +2455 -0
  196. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  197. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/extensions/cmake_install.cmake +171 -0
  198. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/man/cmake_install.cmake +55 -0
  199. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmake_install.cmake +220 -0
  200. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_export.h +43 -0
  201. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_version.h +7 -0
  202. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/config.h +76 -0
  203. data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/libcmark-gfm.pc +10 -0
  204. data/ext/apex_ext/extconf.rb +35 -0
  205. data/lib/apex/version.rb +2 -2
  206. metadata +117 -2
  207. data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/tempOptimizedIndex.dsidx +0 -0
@@ -25,20 +25,41 @@ typedef enum {
25
25
  APEX_INDEX_LEANPUB = 2
26
26
  } apex_index_syntax_t;
27
27
 
28
+ /* TextIndex cross-reference (see / see also) */
29
+ typedef struct apex_index_xref {
30
+ char *target; /* Display path, e.g. "safety: of functions" */
31
+ bool also; /* true = see also; false = see */
32
+ bool inbound; /* @ / @+ inbound (applied to target entry) */
33
+ struct apex_index_xref *next;
34
+ } apex_index_xref;
35
+
36
+ /* TextIndex alias (#name / ##name) */
37
+ typedef struct apex_index_alias {
38
+ char *name; /* alias id without '#' */
39
+ char *path; /* raw path, e.g. Apple (company)>"OS platforms" */
40
+ char *item; /* top-level heading (HTML) */
41
+ char *subitem; /* nested heading (HTML), optional */
42
+ char *display; /* "item: subitem" display form */
43
+ struct apex_index_alias *next;
44
+ } apex_index_alias;
45
+
28
46
  /* Index entry structure */
29
47
  typedef struct apex_index_entry {
30
48
  char *item; /* Main index term */
31
49
  char *subitem; /* Sub-item (optional) */
32
50
  bool primary; /* Primary entry flag (mmark) */
51
+ bool suppress_locator; /* TextIndex see-type mark: no locator */
33
52
  int position; /* Position in document */
34
53
  char *anchor_id; /* Generated anchor ID (e.g., "idxref-0") */
35
54
  apex_index_syntax_t syntax_type; /* MMARK or TEXTINDEX */
55
+ apex_index_xref *xrefs; /* TextIndex see / see-also refs */
36
56
  struct apex_index_entry *next; /* Linked list */
37
57
  } apex_index_entry;
38
58
 
39
59
  /* Index registry */
40
60
  typedef struct {
41
61
  apex_index_entry *entries; /* Linked list of index entries */
62
+ apex_index_alias *aliases; /* TextIndex aliases */
42
63
  size_t count; /* Number of entries */
43
64
  int next_ref_id; /* Next reference ID for anchors */
44
65
  } apex_index_registry;
@@ -68,6 +89,13 @@ char *apex_generate_index_html(apex_index_registry *registry, const apex_options
68
89
  */
69
90
  char *apex_insert_index(const char *html, apex_index_registry *registry, const apex_options *options);
70
91
 
92
+ /**
93
+ * Apply TextIndex concordance file(s): scan the document for column-1 patterns
94
+ * and insert [match]{^col2} marks. Returns a new string if any marks were added,
95
+ * or NULL if unchanged / no concordance files.
96
+ */
97
+ char *apex_apply_concordance(const char *text, const apex_options *options);
98
+
71
99
  /**
72
100
  * Free index registry
73
101
  */
@@ -397,11 +397,51 @@ static apex_metadata_item *parse_yaml_metadata(const char *text, size_t *consume
397
397
  * Parse MultiMarkdown metadata
398
398
  * Format: key: value pairs at start of document, blank line to end
399
399
  */
400
+ /* Undelimited MMD keys may contain letters, digits, spaces, hyphens, and
401
+ * underscores only. Other ASCII punctuation means the line is ordinary text. */
402
+ static bool is_valid_mmd_metadata_key(const char *key) {
403
+ if (!key || !*key) return false;
404
+
405
+ for (const unsigned char *p = (const unsigned char *)key; *p; p++) {
406
+ if ((*p >= 'A' && *p <= 'Z') ||
407
+ (*p >= 'a' && *p <= 'z') ||
408
+ (*p >= '0' && *p <= '9') ||
409
+ *p == ' ' || *p == '-' || *p == '_') {
410
+ continue;
411
+ }
412
+ /* Allow UTF-8 bytes for non-ASCII keys; reject other ASCII punctuation. */
413
+ if (*p >= 0x80) continue;
414
+ return false;
415
+ }
416
+ return true;
417
+ }
418
+
419
+ /* Reject a sole long "Key: value" line that looks like a prose sentence. */
420
+ #define APEX_MMD_SINGLE_LINE_MAX 100
421
+
400
422
  static apex_metadata_item *parse_mmd_metadata(const char *text, size_t *consumed) {
401
423
  apex_metadata_item *items = NULL;
402
424
  const char *line_start = text;
403
425
  const char *line_end;
404
426
  bool found_metadata = false;
427
+ size_t metadata_count = 0;
428
+ size_t sole_line_len = 0;
429
+
430
+ /* Any non-metadata content before/after key:value ends or rejects the block.
431
+ * Undelimited MMD metadata must start at the very top of the file. */
432
+ #define APEX_MMD_ABORT_OR_END() do { \
433
+ if (found_metadata) { \
434
+ if (metadata_count == 1 && sole_line_len > APEX_MMD_SINGLE_LINE_MAX) { \
435
+ apex_free_metadata(items); \
436
+ *consumed = 0; \
437
+ return NULL; \
438
+ } \
439
+ *consumed = line_start - text; \
440
+ return items; \
441
+ } \
442
+ *consumed = 0; \
443
+ return NULL; \
444
+ } while (0)
405
445
 
406
446
  while ((line_end = strchr(line_start, '\n')) != NULL) {
407
447
  size_t len = line_end - line_start;
@@ -411,244 +451,132 @@ static apex_metadata_item *parse_mmd_metadata(const char *text, size_t *consumed
411
451
  memcpy(line, line_start, len);
412
452
  line[len] = '\0';
413
453
 
414
- /* Check for blank line (end of metadata) */
454
+ /* Check for blank line (end of metadata). A leading blank means the
455
+ * document does not start with undelimited MMD metadata. */
415
456
  char *trimmed = trim_whitespace(line);
416
457
  if (*trimmed == '\0') {
417
458
  if (found_metadata) {
459
+ if (metadata_count == 1 && sole_line_len > APEX_MMD_SINGLE_LINE_MAX) {
460
+ apex_free_metadata(items);
461
+ *consumed = 0;
462
+ return NULL;
463
+ }
418
464
  *consumed = (line_end + 1) - text;
419
465
  return items;
420
466
  }
421
- /* Skip leading blank lines */
422
- line_start = line_end + 1;
423
- continue;
467
+ *consumed = 0;
468
+ return NULL;
424
469
  }
425
470
 
426
- /* Skip abbreviation definitions (*[abbr]: expansion or [>abbr]: expansion) */
471
+ /* Abbreviation definitions (*[abbr]: expansion or [>abbr]: expansion) */
427
472
  if ((trimmed[0] == '*' && trimmed[1] == '[') ||
428
473
  (trimmed[0] == '[' && trimmed[1] == '>')) {
429
- /* This is an abbreviation, not metadata */
430
- if (found_metadata) {
431
- *consumed = line_start - text;
432
- return items;
433
- }
434
- /* Haven't found metadata yet, skip this line */
435
- line_start = line_end + 1;
436
- continue;
474
+ APEX_MMD_ABORT_OR_END();
437
475
  }
438
476
 
439
- /* Skip HTML comments (<!--...-->) */
477
+ /* HTML comments (<!--...-->) */
440
478
  if (strncmp(trimmed, "<!--", 4) == 0) {
441
- /* This is an HTML comment, not metadata */
442
- if (found_metadata) {
443
- *consumed = line_start - text;
444
- return items;
445
- }
446
- /* Haven't found metadata yet, skip this line */
447
- line_start = line_end + 1;
448
- continue;
479
+ APEX_MMD_ABORT_OR_END();
449
480
  }
450
481
 
451
- /* Skip Kramdown markers ({::...}) */
482
+ /* Kramdown markers ({::...}) */
452
483
  if (strncmp(trimmed, "{::", 3) == 0) {
453
- /* This is a Kramdown marker, not metadata */
454
- if (found_metadata) {
455
- *consumed = line_start - text;
456
- return items;
457
- }
458
- /* Haven't found metadata yet, skip this line */
459
- line_start = line_end + 1;
460
- continue;
484
+ APEX_MMD_ABORT_OR_END();
461
485
  }
462
486
 
463
- /* Skip Markdown headings (# or ##) */
487
+ /* Markdown headings (# or ##) */
464
488
  if (trimmed[0] == '#') {
465
- /* This is a Markdown heading, not metadata */
466
- if (found_metadata) {
467
- *consumed = line_start - text;
468
- return items;
469
- }
470
- /* Haven't found metadata yet, skip this line */
471
- line_start = line_end + 1;
472
- continue;
489
+ APEX_MMD_ABORT_OR_END();
473
490
  }
474
491
 
475
- /* Skip IAL/ALD syntax ({: ...}) */
492
+ /* IAL/ALD syntax ({: ...}) */
476
493
  if (strncmp(trimmed, "{:", 2) == 0) {
477
- /* This is IAL/ALD, not metadata */
478
- if (found_metadata) {
479
- *consumed = line_start - text;
480
- return items;
481
- }
482
- /* Haven't found metadata yet, skip this line */
483
- line_start = line_end + 1;
484
- continue;
494
+ APEX_MMD_ABORT_OR_END();
485
495
  }
486
496
 
487
- /* Skip Leanpub index syntax ({i: term}) - colon would be parsed as metadata key:value */
497
+ /* Leanpub index syntax ({i: term}) */
488
498
  if (strstr(trimmed, "{i:") != NULL) {
489
- if (found_metadata) {
490
- *consumed = line_start - text;
491
- return items;
492
- }
493
- *consumed = 0;
494
- return NULL;
499
+ APEX_MMD_ABORT_OR_END();
495
500
  }
496
501
 
497
- /* Skip TOC markers ({{TOC...}}) */
502
+ /* TOC markers ({{TOC...}}) */
498
503
  if (strncmp(trimmed, "{{TOC", 5) == 0) {
499
- /* This is a TOC marker, not metadata */
500
- if (found_metadata) {
501
- *consumed = line_start - text;
502
- return items;
503
- }
504
- /* Haven't found metadata yet, skip this line */
505
- line_start = line_end + 1;
506
- continue;
504
+ APEX_MMD_ABORT_OR_END();
507
505
  }
508
506
 
509
- /* Skip list markers (-, +, *, or numbered lists) */
510
- /* Check if line starts with a list marker */
507
+ /* List markers (-, +, *, or numbered lists) */
511
508
  const char *list_check = trimmed;
512
509
  if (*list_check == '-' || *list_check == '+' || *list_check == '*') {
513
- /* Check if followed by space (markdown list syntax) */
514
510
  if (list_check[1] == ' ' || list_check[1] == '\t') {
515
- /* This is a list item, not metadata */
516
- if (found_metadata) {
517
- *consumed = line_start - text;
518
- return items;
519
- }
520
- /* Haven't found metadata yet - this isn't metadata */
521
- *consumed = 0;
522
- return NULL;
511
+ APEX_MMD_ABORT_OR_END();
523
512
  }
524
513
  }
525
- /* Check for numbered lists (digit followed by . or ) and space) */
526
514
  if (isdigit((unsigned char)*list_check)) {
527
515
  const char *p = list_check + 1;
528
- /* Skip digits */
529
516
  while (isdigit((unsigned char)*p)) p++;
530
- /* Check for . or ) followed by space */
531
517
  if ((*p == '.' || *p == ')') && (p[1] == ' ' || p[1] == '\t')) {
532
- /* This is a numbered list item, not metadata */
533
- if (found_metadata) {
534
- *consumed = line_start - text;
535
- return items;
536
- }
537
- /* Haven't found metadata yet - this isn't metadata */
538
- *consumed = 0;
539
- return NULL;
518
+ APEX_MMD_ABORT_OR_END();
540
519
  }
541
520
  }
542
521
 
543
522
  /* Parse key: value */
544
523
  char *colon = strchr(line, ':');
545
524
  if (colon) {
546
- /* Skip lines that look like Markdown links or images (e.g. [text](url) or ![alt](url) or ...[](#){: .class })
547
- * so that "[![...](#){: .class }" is not parsed as metadata due to the ": " in "{: " */
525
+ /* Markdown links/images */
548
526
  if (strstr(line, "[!") != NULL ||
549
527
  (strchr(line, '[') && strchr(line, ']') && strstr(line, "]("))) {
550
- if (found_metadata) {
551
- *consumed = line_start - text;
552
- return items;
553
- }
554
- *consumed = 0;
555
- return NULL;
528
+ APEX_MMD_ABORT_OR_END();
556
529
  }
557
- /* Check if there's a protocol (http://, https://, mailto:) BEFORE the colon */
558
- /* If so, this is likely a URL in the key, not metadata */
530
+ /* Protocol / URL before the colon */
559
531
  size_t key_len = (size_t)(colon - line);
560
532
  if (key_len >= 7 && (
561
533
  (key_len >= 7 && strncmp(line, "http://", 7) == 0) ||
562
534
  (key_len >= 8 && strncmp(line, "https://", 8) == 0) ||
563
535
  (key_len >= 7 && strncmp(line, "mailto:", 7) == 0) ||
564
536
  strstr(line, "://") != NULL)) {
565
- /* Protocol found before colon - this is a URL, not metadata */
566
- if (found_metadata) {
567
- *consumed = line_start - text;
568
- return items;
569
- }
570
- *consumed = 0;
571
- return NULL;
537
+ APEX_MMD_ABORT_OR_END();
572
538
  }
573
539
 
574
- /* Check if there's a < character BEFORE the colon (HTML/autolink in key) */
540
+ /* HTML/autolink marker before the colon */
575
541
  if (memchr(line, '<', key_len) != NULL) {
576
- /* < found before colon - this is HTML/autolink, not metadata */
577
- if (found_metadata) {
578
- *consumed = line_start - text;
579
- return items;
580
- }
581
- *consumed = 0;
582
- return NULL;
542
+ APEX_MMD_ABORT_OR_END();
583
543
  }
584
544
 
585
- /* Check for space after colon (MMD requires "KEY: VALUE" format) */
545
+ /* Require space/tab after colon (MMD "KEY: VALUE"; also avoids URLs) */
586
546
  char *after_colon = colon + 1;
587
547
  if (*after_colon != ' ' && *after_colon != '\t') {
588
- /* No space after colon - likely not metadata */
589
- if (found_metadata) {
590
- *consumed = line_start - text;
591
- return items;
592
- }
593
- *consumed = 0;
594
- return NULL;
548
+ APEX_MMD_ABORT_OR_END();
595
549
  }
596
550
 
597
551
  *colon = '\0';
598
552
  char *key = trim_whitespace(line);
599
553
  char *value = trim_whitespace(colon + 1);
600
554
 
601
- if (*key && *value) {
555
+ if (*key && *value && is_valid_mmd_metadata_key(key)) {
602
556
  add_metadata_item(&items, key, value);
603
557
  found_metadata = true;
604
- } else {
605
- /* Line has colon but invalid key/value */
606
- if (found_metadata) {
607
- *consumed = line_start - text;
608
- return items;
558
+ metadata_count++;
559
+ if (metadata_count == 1) {
560
+ sole_line_len = len;
609
561
  }
610
- /* No metadata found yet - this isn't metadata */
611
- *consumed = 0;
612
- return NULL;
562
+ } else {
563
+ APEX_MMD_ABORT_OR_END();
613
564
  }
614
565
  } else {
615
- /* No colon - check if line contains URLs (bare URLs without angle brackets) */
616
- if (strstr(trimmed, "http://") || strstr(trimmed, "https://") || strstr(trimmed, "mailto:")) {
617
- /* This is a bare URL, not metadata */
618
- if (found_metadata) {
619
- *consumed = line_start - text;
620
- return items;
621
- }
622
- *consumed = 0;
623
- return NULL;
624
- }
625
-
626
- /* Skip lines with Markdown links or images */
627
- if (strchr(trimmed, '[') && strchr(trimmed, ']') && strchr(trimmed, '(')) {
628
- /* Contains markdown link/image syntax - not metadata */
629
- if (found_metadata) {
630
- *consumed = line_start - text;
631
- return items;
632
- }
633
- /* Haven't found metadata yet - this isn't metadata */
634
- *consumed = 0;
635
- return NULL;
636
- }
637
-
638
- /* Non-metadata line found (no colon) */
639
- if (found_metadata) {
640
- *consumed = line_start - text;
641
- return items;
642
- }
643
- /* No metadata found yet and hit non-metadata line - stop */
644
- *consumed = 0;
645
- return NULL;
566
+ APEX_MMD_ABORT_OR_END();
646
567
  }
647
568
 
569
+ #undef APEX_MMD_ABORT_OR_END
570
+
648
571
  line_start = line_end + 1;
649
572
  }
650
573
 
651
574
  if (found_metadata) {
575
+ if (metadata_count == 1 && sole_line_len > APEX_MMD_SINGLE_LINE_MAX) {
576
+ apex_free_metadata(items);
577
+ *consumed = 0;
578
+ return NULL;
579
+ }
652
580
  *consumed = strlen(text);
653
581
  }
654
582
  return items;
@@ -2627,6 +2555,8 @@ void apex_apply_metadata_to_options(apex_metadata_item *metadata, apex_options *
2627
2555
  *options = apex_options_for_mode(APEX_MODE_KRAMDOWN);
2628
2556
  } else if (strcmp(lower, "unified") == 0) {
2629
2557
  *options = apex_options_for_mode(APEX_MODE_UNIFIED);
2558
+ } else if (strcmp(lower, "quarto") == 0) {
2559
+ *options = apex_options_for_mode(APEX_MODE_QUARTO);
2630
2560
  }
2631
2561
  free(lower);
2632
2562
  }
@@ -2679,6 +2609,12 @@ void apex_apply_metadata_to_options(apex_metadata_item *metadata, apex_options *
2679
2609
  } else if (is_false_value(value)) {
2680
2610
  options->relaxed_tables = false;
2681
2611
  }
2612
+ } else if (strcasecmp(key, "grid-tables") == 0 || strcasecmp(key, "grid_tables") == 0) {
2613
+ if (is_true_value(value)) {
2614
+ options->enable_grid_tables = true;
2615
+ } else if (is_false_value(value)) {
2616
+ options->enable_grid_tables = false;
2617
+ }
2682
2618
  } else if (strcasecmp(key, "alpha-lists") == 0 || strcasecmp(key, "alpha_lists") == 0) {
2683
2619
  if (is_true_value(value)) {
2684
2620
  options->allow_alpha_lists = true;
@@ -2757,6 +2693,97 @@ void apex_apply_metadata_to_options(apex_metadata_item *metadata, apex_options *
2757
2693
  } else if (is_false_value(value)) {
2758
2694
  options->enable_math = false;
2759
2695
  }
2696
+ } else if (strcasecmp(key, "callouts") == 0) {
2697
+ if (is_true_value(value)) {
2698
+ options->enable_callouts = true;
2699
+ } else if (is_false_value(value)) {
2700
+ options->enable_callouts = false;
2701
+ }
2702
+ } else if (strcasecmp(key, "py-callouts") == 0 || strcasecmp(key, "py_callouts") == 0) {
2703
+ if (is_true_value(value)) {
2704
+ options->enable_py_callouts = true;
2705
+ } else if (is_false_value(value)) {
2706
+ options->enable_py_callouts = false;
2707
+ }
2708
+ } else if (strcasecmp(key, "quarto-extensions") == 0 || strcasecmp(key, "quarto_extensions") == 0) {
2709
+ if (is_true_value(value)) {
2710
+ options->enable_quarto_extensions = true;
2711
+ } else if (is_false_value(value)) {
2712
+ options->enable_quarto_extensions = false;
2713
+ }
2714
+ } else if (strcasecmp(key, "quarto-raw") == 0 || strcasecmp(key, "quarto_raw") == 0) {
2715
+ if (is_true_value(value)) {
2716
+ options->enable_quarto_raw = true;
2717
+ } else if (is_false_value(value)) {
2718
+ options->enable_quarto_raw = false;
2719
+ }
2720
+ } else if (strcasecmp(key, "quarto-list-continuation") == 0 || strcasecmp(key, "quarto_list_continuation") == 0 ||
2721
+ strcasecmp(key, "quarto-example-lists") == 0 || strcasecmp(key, "quarto_example_lists") == 0) {
2722
+ if (is_true_value(value)) {
2723
+ options->enable_quarto_example_lists = true;
2724
+ } else if (is_false_value(value)) {
2725
+ options->enable_quarto_example_lists = false;
2726
+ }
2727
+ } else if (strcasecmp(key, "quarto-line-blocks") == 0 || strcasecmp(key, "quarto_line_blocks") == 0) {
2728
+ if (is_true_value(value)) {
2729
+ options->enable_quarto_line_blocks = true;
2730
+ } else if (is_false_value(value)) {
2731
+ options->enable_quarto_line_blocks = false;
2732
+ }
2733
+ } else if (strcasecmp(key, "quarto-roman-lists") == 0 || strcasecmp(key, "quarto_roman_lists") == 0) {
2734
+ if (is_true_value(value)) {
2735
+ options->enable_quarto_roman_lists = true;
2736
+ } else if (is_false_value(value)) {
2737
+ options->enable_quarto_roman_lists = false;
2738
+ }
2739
+ } else if (strcasecmp(key, "quarto-code-attrs") == 0 || strcasecmp(key, "quarto_code_attrs") == 0) {
2740
+ if (is_true_value(value)) {
2741
+ options->enable_quarto_code_attrs = true;
2742
+ } else if (is_false_value(value)) {
2743
+ options->enable_quarto_code_attrs = false;
2744
+ }
2745
+ } else if (strcasecmp(key, "quarto-strict-lists") == 0 || strcasecmp(key, "quarto_strict_lists") == 0) {
2746
+ if (is_true_value(value)) {
2747
+ options->enable_quarto_strict_lists = true;
2748
+ } else if (is_false_value(value)) {
2749
+ options->enable_quarto_strict_lists = false;
2750
+ }
2751
+ } else if (strcasecmp(key, "quarto-xrefs") == 0 || strcasecmp(key, "quarto_xrefs") == 0) {
2752
+ if (is_true_value(value)) {
2753
+ options->enable_quarto_xrefs = true;
2754
+ } else if (is_false_value(value)) {
2755
+ options->enable_quarto_xrefs = false;
2756
+ }
2757
+ } else if (strcasecmp(key, "quarto-callouts") == 0 || strcasecmp(key, "quarto_callouts") == 0) {
2758
+ if (is_true_value(value)) {
2759
+ options->enable_quarto_callouts = true;
2760
+ } else if (is_false_value(value)) {
2761
+ options->enable_quarto_callouts = false;
2762
+ }
2763
+ } else if (strcasecmp(key, "quarto-diagrams") == 0 || strcasecmp(key, "quarto_diagrams") == 0) {
2764
+ if (is_true_value(value)) {
2765
+ options->enable_quarto_diagrams = true;
2766
+ } else if (is_false_value(value)) {
2767
+ options->enable_quarto_diagrams = false;
2768
+ }
2769
+ } else if (strcasecmp(key, "quarto-shortcodes") == 0 || strcasecmp(key, "quarto_shortcodes") == 0) {
2770
+ if (is_true_value(value)) {
2771
+ options->enable_quarto_shortcodes = true;
2772
+ } else if (is_false_value(value)) {
2773
+ options->enable_quarto_shortcodes = false;
2774
+ }
2775
+ } else if (strcasecmp(key, "divs") == 0) {
2776
+ if (is_true_value(value)) {
2777
+ options->enable_divs = true;
2778
+ } else if (is_false_value(value)) {
2779
+ options->enable_divs = false;
2780
+ }
2781
+ } else if (strcasecmp(key, "spans") == 0) {
2782
+ if (is_true_value(value)) {
2783
+ options->enable_spans = true;
2784
+ } else if (is_false_value(value)) {
2785
+ options->enable_spans = false;
2786
+ }
2760
2787
  } else if (strcasecmp(key, "ids") == 0 || strcasecmp(key, "header-ids") == 0) {
2761
2788
  if (is_true_value(value)) {
2762
2789
  options->generate_header_ids = true;
@@ -2943,6 +2970,13 @@ void apex_apply_metadata_to_options(apex_metadata_item *metadata, apex_options *
2943
2970
  }
2944
2971
  free(lower);
2945
2972
  }
2973
+ } else if (strcasecmp(key, "toc-min-max") == 0 || strcasecmp(key, "toc_min_max") == 0) {
2974
+ int min = 0, max = 0;
2975
+ if (sscanf(value, "%d,%d", &min, &max) == 2 &&
2976
+ min >= 1 && max <= 6 && min <= max) {
2977
+ options->toc_min = min;
2978
+ options->toc_max = max;
2979
+ }
2946
2980
  } else if (strcasecmp(key, "base-dir") == 0 || strcasecmp(key, "base_dir") == 0) {
2947
2981
  options->base_directory = value;
2948
2982
  } else if (strcasecmp(key, "wikilink-space") == 0 || strcasecmp(key, "wikilink_space") == 0) {
@@ -3001,10 +3035,15 @@ void apex_apply_metadata_to_options(apex_metadata_item *metadata, apex_options *
3001
3035
  } else if (strcasecmp(key, "paginate") == 0 ||
3002
3036
  strcasecmp(key, "terminal.paginate") == 0 ||
3003
3037
  strcasecmp(key, "terminal_paginate") == 0) {
3004
- if (is_true_value(value)) {
3038
+ if (strcasecmp(value, "symbols") == 0) {
3039
+ options->paginate = true;
3040
+ options->paginate_symbols = true;
3041
+ } else if (is_true_value(value)) {
3005
3042
  options->paginate = true;
3043
+ options->paginate_symbols = false;
3006
3044
  } else if (is_false_value(value)) {
3007
3045
  options->paginate = false;
3046
+ options->paginate_symbols = false;
3008
3047
  }
3009
3048
  }
3010
3049
  /* Syntax highlighting options */