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.
- checksums.yaml +4 -4
- data/README.md +17 -3
- data/ext/apex_ext/apex_ext.c +260 -91
- data/ext/apex_ext/apex_src/CHANGELOG.md +440 -0
- data/ext/apex_ext/apex_src/CMakeLists.txt +15 -1
- data/ext/apex_ext/apex_src/Formula/apex.rb +7 -2
- data/ext/apex_ext/apex_src/Package.swift +15 -4
- data/ext/apex_ext/apex_src/README.md +94 -35
- data/ext/apex_ext/apex_src/VERSION +1 -1
- data/ext/apex_ext/apex_src/apex-debug.log +4 -0
- data/ext/apex_ext/apex_src/apex.code-workspace +38 -0
- data/ext/apex_ext/apex_src/apex.taskpaper +12 -0
- data/ext/apex_ext/apex_src/apex_deflist_debug.log +25 -0
- data/ext/apex_ext/apex_src/buildnotes.md +1435 -0
- data/ext/apex_ext/apex_src/cli/main.c +262 -33
- data/ext/apex_ext/apex_src/debug.log +7 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_EXAMPLES.md +274 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_IMPLEMENTATION_PLAN.md +749 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_PLAN.md +744 -0
- data/ext/apex_ext/apex_src/docs/INDEX_IMPLEMENTATION_ANALYSIS.md +382 -0
- data/ext/apex_ext/apex_src/docs/plans/2025-02-27-man-page-output-implementation.md +351 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-12-toc-output-format.md +745 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-18-bear-image-attributes.md +829 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-19-apex-node-npm.md +1148 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-12-toc-output-format-design.md +161 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-18-bear-image-attributes-design.md +184 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-19-apex-node-npm-design.md +211 -0
- data/ext/apex_ext/apex_src/documentation/app-settings-table.md +67 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Citations.md +340 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Credits.md +11 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Header-IDs.md +234 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Inline-Attribute-Lists.md +516 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Metadata-Transforms.md +461 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Modes.md +193 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Multi-File-Documents.md +201 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Plugins.md +678 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Syntax.md +1367 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex Command Line Options.cheatsheet.txt +6 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/C-API.html +774 -300
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Callouts.html +1194 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Citations.html +416 -216
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Command-Line-Options.html +3544 -1094
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Configuration.html +371 -97
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Credits.html +153 -23
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Examples.html +358 -124
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Filters.html +1656 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Generating-Man-Pages.html +1226 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Getting-Started.html +201 -56
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Header-IDs.html +279 -109
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Home.html +200 -53
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Indices.html +2327 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Inline-Attribute-Lists.html +690 -271
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Installation.html +201 -55
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Limitations-and-Roadmap.html +238 -68
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Metadata-Transforms.html +421 -221
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Modes.html +340 -78
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-File-Documents.html +251 -86
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-Format-Images.html +1362 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Pandoc-Integration.html +277 -90
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Plugins.html +673 -346
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Quarto-Mode.html +1405 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Rendering-Markdown-In-Terminal.html +1902 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Syntax.html +1939 -1698
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Tables.html +1781 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Troubleshooting.html +315 -140
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Usage.html +307 -113
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Using-Apex-with-Jekyll.html +1132 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Writing-Tests.html +1754 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Xcode-Integration.html +872 -376
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/docSet.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/optimizedIndex.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/html/apex-app-docs.html +8746 -0
- data/ext/apex_ext/apex_src/documentation/shared_styles.css +20 -15
- data/ext/apex_ext/apex_src/documentation/transform_for_app.md +55 -0
- data/ext/apex_ext/apex_src/escaping-repro.md +103 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/Info.plist +8 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/QuickLook/Preview.png +0 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/document.wflow +547 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown-to-RTF.workflow.zip +0 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/README.md +33 -0
- data/ext/apex_ext/apex_src/include/apex/apex.h +92 -6
- data/ext/apex_ext/apex_src/include/apex/ast_rtf.h +23 -0
- data/ext/apex_ext/apex_src/include/apex/ast_terminal.h +6 -0
- data/ext/apex_ext/apex_src/include/apex/module.modulemap +5 -0
- data/ext/apex_ext/apex_src/include/apex/plugins.h +105 -0
- data/ext/apex_ext/apex_src/include/apexc.h +1 -0
- data/ext/apex_ext/apex_src/man/apex.1 +82 -78
- data/ext/apex_ext/apex_src/man/apex.1.md +81 -4
- data/ext/apex_ext/apex_src/objc/Apex.swift +73 -0
- data/ext/apex_ext/apex_src/objc/ApexPlugins.swift +79 -0
- data/ext/apex_ext/apex_src/objc/NSString+Apex.h +83 -5
- data/ext/apex_ext/apex_src/objc/NSString+Apex.m +244 -1
- data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.h +76 -0
- data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.m +169 -0
- data/ext/apex_ext/apex_src/output.html +87 -0
- data/ext/apex_ext/apex_src/plans/quarto-mode.md +442 -0
- data/ext/apex_ext/apex_src/src/_README.md +85 -32
- data/ext/apex_ext/apex_src/src/apex.c +770 -200
- data/ext/apex_ext/apex_src/src/ast_rtf.c +848 -0
- data/ext/apex_ext/apex_src/src/ast_terminal.c +184 -7
- data/ext/apex_ext/apex_src/src/extensions/abbreviations.c +10 -3
- data/ext/apex_ext/apex_src/src/extensions/advanced_tables.c +7 -11
- data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.c +467 -0
- data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.h +27 -0
- data/ext/apex_ext/apex_src/src/extensions/callouts.c +400 -4
- data/ext/apex_ext/apex_src/src/extensions/callouts.h +15 -5
- data/ext/apex_ext/apex_src/src/extensions/citations.c +26 -5
- data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.c +632 -0
- data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.h +22 -0
- data/ext/apex_ext/apex_src/src/extensions/concordance.c +632 -0
- data/ext/apex_ext/apex_src/src/extensions/definition_list.c +129 -15
- data/ext/apex_ext/apex_src/src/extensions/grid_tables.c +1050 -121
- data/ext/apex_ext/apex_src/src/extensions/html_markdown.c +569 -16
- data/ext/apex_ext/apex_src/src/extensions/ial.c +502 -52
- data/ext/apex_ext/apex_src/src/extensions/ial.h +2 -1
- data/ext/apex_ext/apex_src/src/extensions/includes.c +532 -33
- data/ext/apex_ext/apex_src/src/extensions/includes.h +7 -1
- data/ext/apex_ext/apex_src/src/extensions/index.c +1427 -140
- data/ext/apex_ext/apex_src/src/extensions/index.h +28 -0
- data/ext/apex_ext/apex_src/src/extensions/metadata.c +200 -161
- data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.c +251 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.h +22 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_lists.c +624 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_lists.h +35 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_polish.c +264 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_polish.h +23 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.c +307 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.h +21 -0
- data/ext/apex_ext/apex_src/src/extensions/raw_content.c +351 -0
- data/ext/apex_ext/apex_src/src/extensions/raw_content.h +20 -0
- data/ext/apex_ext/apex_src/src/extensions/relaxed_tables.c +117 -3
- data/ext/apex_ext/apex_src/src/extensions/special_markers.c +53 -0
- data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.c +23 -1
- data/ext/apex_ext/apex_src/src/extensions/table_html_postprocess.c +83 -92
- data/ext/apex_ext/apex_src/src/extensions/toc.c +446 -25
- data/ext/apex_ext/apex_src/src/extensions/toc.h +26 -1
- data/ext/apex_ext/apex_src/src/extensions/wiki_links.c +28 -0
- data/ext/apex_ext/apex_src/src/html_renderer.c +387 -17
- data/ext/apex_ext/apex_src/src/plugin_catalog.c +517 -0
- data/ext/apex_ext/apex_src/src/plugins_remote.c +88 -14
- data/ext/apex_ext/apex_src/src/plugins_remote.h +34 -0
- data/ext/apex_ext/apex_src/src/pretty_html.c +6 -1
- data/ext/apex_ext/apex_src/tests/fixtures/comprehensive_test.md +21 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/bear_image_attributes.md +10 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.md +19 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.txt +11 -0
- data/ext/apex_ext/apex_src/tests/fixtures/minimal_pb.md +2 -0
- data/ext/apex_ext/apex_src/tests/fixtures/obsidian-callouts.md +46 -0
- data/ext/apex_ext/apex_src/tests/fixtures/pagebreak_html_repro.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/python-callouts.md +47 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/callouts.md +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/code-attrs.md +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/diagrams.md +8 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/lists.md +19 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/raw-content.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/shortcodes.md +7 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/smoke.md +81 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/spans.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto-callouts.md +47 -0
- data/ext/apex_ext/apex_src/tests/fixtures/speed.md +192 -0
- data/ext/apex_ext/apex_src/tests/fixtures/tables/grid-tables.md +37 -0
- data/ext/apex_ext/apex_src/tests/paginate_cli_test.sh +16 -0
- data/ext/apex_ext/apex_src/tests/test_bear_image_attrs.c +301 -0
- data/ext/apex_ext/apex_src/tests/test_concordance.tsv +4 -0
- data/ext/apex_ext/apex_src/tests/test_escaping_repro.c +82 -0
- data/ext/apex_ext/apex_src/tests/test_extensions.c +821 -1
- data/ext/apex_ext/apex_src/tests/test_ial.c +7 -0
- data/ext/apex_ext/apex_src/tests/test_marked_integration.c +25 -0
- data/ext/apex_ext/apex_src/tests/test_metadata.c +129 -0
- data/ext/apex_ext/apex_src/tests/test_output.c +568 -2
- data/ext/apex_ext/apex_src/tests/test_runner.c +11 -0
- data/ext/apex_ext/apex_src/tests/test_tables.c +420 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/CMakeLists.txt +1 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/autolink.c +77 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/table.c +135 -5
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/blocks.c +56 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/config.h +38 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/main.c +1 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/cmark.cpython-314.pyc +0 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/normalize.cpython-314.pyc +0 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/extensions.txt +69 -0
- data/ext/apex_ext/apex_src/xcode_build/CMakeScripts/ReRunCMake.make +74 -0
- data/ext/apex_ext/apex_src/xcode_build/CTestTestfile.cmake +22 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Apex +0 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Resources/Info.plist +44 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/_CodeSignature/CodeResources +128 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.pbxproj +5118 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/xcuserdata/ttscoff.xcuserdatad/xcschemes/xcschememanagement.plist +99 -0
- data/ext/apex_ext/apex_src/xcode_build/cmake_install.cmake +452 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/CMakeScripts/ReRunCMake.make +52 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmake_install.cmake +55 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.pbxproj +2455 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/extensions/cmake_install.cmake +171 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/man/cmake_install.cmake +55 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmake_install.cmake +220 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_export.h +43 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_version.h +7 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/config.h +76 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/libcmark-gfm.pc +10 -0
- data/ext/apex_ext/extconf.rb +35 -0
- data/lib/apex/version.rb +2 -2
- metadata +117 -2
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/tempOptimizedIndex.dsidx +0 -0
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#include <stdlib.h>
|
|
9
9
|
#include <ctype.h>
|
|
10
10
|
#include <strings.h>
|
|
11
|
+
#include <stdio.h>
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Detect callout type from string (case-insensitive)
|
|
@@ -66,7 +67,7 @@ static const char *callout_type_name(callout_type_t type) {
|
|
|
66
67
|
* Check if a blockquote is a Bear/Obsidian style callout
|
|
67
68
|
* Pattern: > [!TYPE] Title or > [!TYPE]+ Title or > [!TYPE]- Title
|
|
68
69
|
*/
|
|
69
|
-
static bool is_bear_callout(cmark_node *blockquote, callout_type_t *type,
|
|
70
|
+
static bool is_bear_callout(cmark_node *blockquote, bool enable_py_callouts, callout_type_t *type,
|
|
70
71
|
char **title, bool *collapsible, bool *default_open) {
|
|
71
72
|
if (cmark_node_get_type(blockquote) != CMARK_NODE_BLOCK_QUOTE) return false;
|
|
72
73
|
|
|
@@ -81,6 +82,34 @@ static bool is_bear_callout(cmark_node *blockquote, callout_type_t *type,
|
|
|
81
82
|
const char *text = cmark_node_get_literal(text_node);
|
|
82
83
|
if (!text) return false;
|
|
83
84
|
|
|
85
|
+
/* markdown-callouts collapsed syntax in blockquote: ? TYPE: Title */
|
|
86
|
+
if (enable_py_callouts && text[0] == '?' && text[1] == ' ') {
|
|
87
|
+
const char *type_start = text + 2;
|
|
88
|
+
const char *p = type_start;
|
|
89
|
+
while (*p && (isalnum((unsigned char)*p) || *p == '-' || *p == '_')) p++;
|
|
90
|
+
if (*p == ':') {
|
|
91
|
+
int type_len = (int)(p - type_start);
|
|
92
|
+
if (type_len > 0) {
|
|
93
|
+
*type = detect_callout_type(type_start, type_len);
|
|
94
|
+
if (*type != CALLOUT_NONE) {
|
|
95
|
+
*collapsible = true;
|
|
96
|
+
*default_open = false;
|
|
97
|
+
const char *title_start = p + 1;
|
|
98
|
+
while (*title_start == ' ' || *title_start == '\t') title_start++;
|
|
99
|
+
if (*title_start) {
|
|
100
|
+
const char *title_end = strchr(title_start, '\n');
|
|
101
|
+
if (title_end) {
|
|
102
|
+
*title = strndup(title_start, title_end - title_start);
|
|
103
|
+
} else {
|
|
104
|
+
*title = strdup(title_start);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
84
113
|
/* Check for [!TYPE] pattern */
|
|
85
114
|
if (text[0] != '[' || text[1] != '!') return false;
|
|
86
115
|
|
|
@@ -188,7 +217,7 @@ static void convert_blockquote_to_callout(cmark_node *blockquote, callout_type_t
|
|
|
188
217
|
/**
|
|
189
218
|
* Process callouts in AST
|
|
190
219
|
*/
|
|
191
|
-
void apex_process_callouts_in_tree(cmark_node *node) {
|
|
220
|
+
void apex_process_callouts_in_tree(cmark_node *node, bool enable_py_callouts) {
|
|
192
221
|
if (!node) return;
|
|
193
222
|
|
|
194
223
|
/* Check if current node is a blockquote callout */
|
|
@@ -197,7 +226,7 @@ void apex_process_callouts_in_tree(cmark_node *node) {
|
|
|
197
226
|
char *title = NULL;
|
|
198
227
|
bool collapsible, default_open;
|
|
199
228
|
|
|
200
|
-
if (is_bear_callout(node, &type, &title, &collapsible, &default_open)) {
|
|
229
|
+
if (is_bear_callout(node, enable_py_callouts, &type, &title, &collapsible, &default_open)) {
|
|
201
230
|
convert_blockquote_to_callout(node, type, title, collapsible, default_open);
|
|
202
231
|
free(title);
|
|
203
232
|
return; /* Don't recurse into modified node */
|
|
@@ -208,8 +237,375 @@ void apex_process_callouts_in_tree(cmark_node *node) {
|
|
|
208
237
|
cmark_node *child = cmark_node_first_child(node);
|
|
209
238
|
while (child) {
|
|
210
239
|
cmark_node *next = cmark_node_next(child);
|
|
211
|
-
apex_process_callouts_in_tree(child);
|
|
240
|
+
apex_process_callouts_in_tree(child, enable_py_callouts);
|
|
212
241
|
child = next;
|
|
213
242
|
}
|
|
214
243
|
}
|
|
215
244
|
|
|
245
|
+
static bool append_chunk(char **out, size_t *len, size_t *cap, const char *chunk, size_t chunk_len) {
|
|
246
|
+
if (!out || !len || !cap || !chunk) return false;
|
|
247
|
+
if (*len + chunk_len + 1 > *cap) {
|
|
248
|
+
size_t new_cap = *cap ? *cap : 256;
|
|
249
|
+
while (*len + chunk_len + 1 > new_cap) {
|
|
250
|
+
new_cap *= 2;
|
|
251
|
+
}
|
|
252
|
+
char *new_out = realloc(*out, new_cap);
|
|
253
|
+
if (!new_out) return false;
|
|
254
|
+
*out = new_out;
|
|
255
|
+
*cap = new_cap;
|
|
256
|
+
}
|
|
257
|
+
memcpy(*out + *len, chunk, chunk_len);
|
|
258
|
+
*len += chunk_len;
|
|
259
|
+
(*out)[*len] = '\0';
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
static bool append_str(char **out, size_t *len, size_t *cap, const char *str) {
|
|
264
|
+
if (!str) return true;
|
|
265
|
+
return append_chunk(out, len, cap, str, strlen(str));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
static char *trim_ascii_whitespace(char *s) {
|
|
269
|
+
if (!s) return s;
|
|
270
|
+
while (*s && (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')) s++;
|
|
271
|
+
char *end = s + strlen(s);
|
|
272
|
+
while (end > s && (end[-1] == ' ' || end[-1] == '\t' || end[-1] == '\r' || end[-1] == '\n')) {
|
|
273
|
+
end--;
|
|
274
|
+
}
|
|
275
|
+
*end = '\0';
|
|
276
|
+
return s;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
char *apex_preprocess_py_callouts(const char *text) {
|
|
280
|
+
if (!text) return NULL;
|
|
281
|
+
|
|
282
|
+
size_t cap = strlen(text) * 2 + 256;
|
|
283
|
+
char *out = malloc(cap);
|
|
284
|
+
if (!out) return NULL;
|
|
285
|
+
size_t len = 0;
|
|
286
|
+
out[0] = '\0';
|
|
287
|
+
|
|
288
|
+
bool in_fenced_code = false;
|
|
289
|
+
const char *p = text;
|
|
290
|
+
while (*p) {
|
|
291
|
+
const char *line_start = p;
|
|
292
|
+
const char *line_end = strchr(p, '\n');
|
|
293
|
+
bool has_nl = line_end != NULL;
|
|
294
|
+
size_t line_len = has_nl ? (size_t)(line_end - line_start) : strlen(line_start);
|
|
295
|
+
|
|
296
|
+
const char *content = line_start;
|
|
297
|
+
while ((size_t)(content - line_start) < line_len && (*content == ' ' || *content == '\t')) content++;
|
|
298
|
+
size_t content_len = line_len - (size_t)(content - line_start);
|
|
299
|
+
|
|
300
|
+
if (content_len >= 3 && strncmp(content, "```", 3) == 0) {
|
|
301
|
+
in_fenced_code = !in_fenced_code;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (!in_fenced_code) {
|
|
305
|
+
if (content_len > 4 && strncmp(content, ">? ", 3) == 0) {
|
|
306
|
+
const char *spec = content + 3;
|
|
307
|
+
const char *spec_end = content + content_len;
|
|
308
|
+
const char *type_start = spec;
|
|
309
|
+
while (spec < spec_end && (isalnum((unsigned char)*spec) || *spec == '-' || *spec == '_')) spec++;
|
|
310
|
+
if (spec > type_start && spec < spec_end && *spec == ':') {
|
|
311
|
+
int type_len = (int)(spec - type_start);
|
|
312
|
+
callout_type_t ct = detect_callout_type(type_start, type_len);
|
|
313
|
+
if (ct != CALLOUT_NONE) {
|
|
314
|
+
spec++; /* skip : */
|
|
315
|
+
while (spec < spec_end && *spec == ' ') spec++;
|
|
316
|
+
|
|
317
|
+
char header[640];
|
|
318
|
+
if (spec < spec_end) {
|
|
319
|
+
snprintf(header, sizeof(header), "> [!%.*s]- %.*s",
|
|
320
|
+
type_len, type_start, (int)(spec_end - spec), spec);
|
|
321
|
+
} else {
|
|
322
|
+
snprintf(header, sizeof(header), "> [!%.*s]-", type_len, type_start);
|
|
323
|
+
}
|
|
324
|
+
if (!append_str(&out, &len, &cap, header)) goto fail;
|
|
325
|
+
if (has_nl && !append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
326
|
+
p = has_nl ? line_end + 1 : line_start + line_len;
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const char *spec = content;
|
|
333
|
+
const char *spec_end = content + content_len;
|
|
334
|
+
const char *type_start = spec;
|
|
335
|
+
while (spec < spec_end && (isalnum((unsigned char)*spec) || *spec == '-' || *spec == '_')) spec++;
|
|
336
|
+
if (spec > type_start && spec < spec_end && *spec == ':') {
|
|
337
|
+
int type_len = (int)(spec - type_start);
|
|
338
|
+
callout_type_t ct = detect_callout_type(type_start, type_len);
|
|
339
|
+
if (ct != CALLOUT_NONE) {
|
|
340
|
+
spec++; /* skip : */
|
|
341
|
+
while (spec < spec_end && *spec == ' ') spec++;
|
|
342
|
+
|
|
343
|
+
char header[128];
|
|
344
|
+
snprintf(header, sizeof(header), "> [!%.*s]", type_len, type_start);
|
|
345
|
+
if (!append_str(&out, &len, &cap, header)) goto fail;
|
|
346
|
+
if (!append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
347
|
+
|
|
348
|
+
if (!append_str(&out, &len, &cap, "> ")) goto fail;
|
|
349
|
+
if (spec < spec_end && !append_chunk(&out, &len, &cap, spec, (size_t)(spec_end - spec))) goto fail;
|
|
350
|
+
if (has_nl && !append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
351
|
+
|
|
352
|
+
p = has_nl ? line_end + 1 : line_start + line_len;
|
|
353
|
+
if (!append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
354
|
+
while (*p) {
|
|
355
|
+
const char *body_start = p;
|
|
356
|
+
const char *body_end = strchr(p, '\n');
|
|
357
|
+
bool body_nl = body_end != NULL;
|
|
358
|
+
size_t body_len = body_nl ? (size_t)(body_end - body_start) : strlen(body_start);
|
|
359
|
+
bool blank = true;
|
|
360
|
+
for (size_t i = 0; i < body_len; i++) {
|
|
361
|
+
if (body_start[i] != ' ' && body_start[i] != '\t' && body_start[i] != '\r') {
|
|
362
|
+
blank = false;
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (blank) break;
|
|
367
|
+
if (!append_str(&out, &len, &cap, "> ")) goto fail;
|
|
368
|
+
if (!append_chunk(&out, &len, &cap, body_start, body_len)) goto fail;
|
|
369
|
+
if (body_nl && !append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
370
|
+
p = body_nl ? body_end + 1 : body_start + body_len;
|
|
371
|
+
}
|
|
372
|
+
if (!append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (!in_fenced_code && content_len >= 4 && strncmp(content, "!!! ", 4) == 0) {
|
|
379
|
+
const char *spec = content + 4;
|
|
380
|
+
const char *spec_end = content + content_len;
|
|
381
|
+
while (spec < spec_end && *spec == ' ') spec++;
|
|
382
|
+
const char *type_start = spec;
|
|
383
|
+
while (spec < spec_end && (isalnum((unsigned char)*spec) || *spec == '-' || *spec == '_')) spec++;
|
|
384
|
+
if (spec > type_start) {
|
|
385
|
+
int type_len = (int)(spec - type_start);
|
|
386
|
+
callout_type_t ct = detect_callout_type(type_start, type_len);
|
|
387
|
+
if (ct != CALLOUT_NONE) {
|
|
388
|
+
char title_buf[512];
|
|
389
|
+
title_buf[0] = '\0';
|
|
390
|
+
while (spec < spec_end && *spec == ' ') spec++;
|
|
391
|
+
if (spec < spec_end) {
|
|
392
|
+
if (*spec == '"' || *spec == '\'') {
|
|
393
|
+
char quote = *spec++;
|
|
394
|
+
const char *title_start = spec;
|
|
395
|
+
while (spec < spec_end && *spec != quote) spec++;
|
|
396
|
+
size_t tlen = (size_t)(spec - title_start);
|
|
397
|
+
if (tlen >= sizeof(title_buf)) tlen = sizeof(title_buf) - 1;
|
|
398
|
+
memcpy(title_buf, title_start, tlen);
|
|
399
|
+
title_buf[tlen] = '\0';
|
|
400
|
+
} else {
|
|
401
|
+
size_t tlen = (size_t)(spec_end - spec);
|
|
402
|
+
if (tlen >= sizeof(title_buf)) tlen = sizeof(title_buf) - 1;
|
|
403
|
+
memcpy(title_buf, spec, tlen);
|
|
404
|
+
title_buf[tlen] = '\0';
|
|
405
|
+
trim_ascii_whitespace(title_buf);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
char header[640];
|
|
410
|
+
if (title_buf[0]) {
|
|
411
|
+
snprintf(header, sizeof(header), "> [!%.*s] %s", type_len, type_start, title_buf);
|
|
412
|
+
} else {
|
|
413
|
+
snprintf(header, sizeof(header), "> [!%.*s]", type_len, type_start);
|
|
414
|
+
}
|
|
415
|
+
if (!append_str(&out, &len, &cap, header)) goto fail;
|
|
416
|
+
if (has_nl && !append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
417
|
+
|
|
418
|
+
p = has_nl ? line_end + 1 : line_start + line_len;
|
|
419
|
+
while (*p) {
|
|
420
|
+
const char *body_start = p;
|
|
421
|
+
const char *body_end = strchr(p, '\n');
|
|
422
|
+
bool body_nl = body_end != NULL;
|
|
423
|
+
size_t body_len = body_nl ? (size_t)(body_end - body_start) : strlen(body_start);
|
|
424
|
+
|
|
425
|
+
size_t indent = 0;
|
|
426
|
+
while (indent < body_len && body_start[indent] == ' ') indent++;
|
|
427
|
+
bool blank = true;
|
|
428
|
+
for (size_t i = 0; i < body_len; i++) {
|
|
429
|
+
if (body_start[i] != ' ' && body_start[i] != '\t' && body_start[i] != '\r') {
|
|
430
|
+
blank = false;
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (!blank && indent < 4) break;
|
|
436
|
+
|
|
437
|
+
if (!append_str(&out, &len, &cap, ">")) goto fail;
|
|
438
|
+
if (!blank) {
|
|
439
|
+
if (!append_str(&out, &len, &cap, " ")) goto fail;
|
|
440
|
+
size_t strip = indent >= 4 ? 4 : indent;
|
|
441
|
+
if (!append_chunk(&out, &len, &cap, body_start + strip, body_len - strip)) goto fail;
|
|
442
|
+
}
|
|
443
|
+
if (body_nl && !append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
444
|
+
|
|
445
|
+
p = body_nl ? body_end + 1 : body_start + body_len;
|
|
446
|
+
}
|
|
447
|
+
if (!append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (!append_chunk(&out, &len, &cap, line_start, line_len)) goto fail;
|
|
454
|
+
if (has_nl && !append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
455
|
+
p = has_nl ? line_end + 1 : line_start + line_len;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return out;
|
|
459
|
+
|
|
460
|
+
fail:
|
|
461
|
+
free(out);
|
|
462
|
+
return NULL;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
char *apex_preprocess_quarto_callouts(const char *text) {
|
|
466
|
+
if (!text) return NULL;
|
|
467
|
+
|
|
468
|
+
size_t cap = strlen(text) * 2 + 256;
|
|
469
|
+
char *out = malloc(cap);
|
|
470
|
+
if (!out) return NULL;
|
|
471
|
+
size_t len = 0;
|
|
472
|
+
out[0] = '\0';
|
|
473
|
+
|
|
474
|
+
bool in_fenced_code = false;
|
|
475
|
+
const char *p = text;
|
|
476
|
+
while (*p) {
|
|
477
|
+
const char *line_start = p;
|
|
478
|
+
const char *line_end = strchr(p, '\n');
|
|
479
|
+
bool has_nl = line_end != NULL;
|
|
480
|
+
size_t line_len = has_nl ? (size_t)(line_end - line_start) : strlen(line_start);
|
|
481
|
+
|
|
482
|
+
const char *content = line_start;
|
|
483
|
+
while ((size_t)(content - line_start) < line_len && (*content == ' ' || *content == '\t')) content++;
|
|
484
|
+
size_t content_len = line_len - (size_t)(content - line_start);
|
|
485
|
+
|
|
486
|
+
if (content_len >= 3 && strncmp(content, "```", 3) == 0) {
|
|
487
|
+
in_fenced_code = !in_fenced_code;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (!in_fenced_code && content_len >= 3 && strncmp(content, ":::", 3) == 0) {
|
|
491
|
+
const char *after = content + 3;
|
|
492
|
+
while (after < content + content_len && *after == ' ') after++;
|
|
493
|
+
if (after < content + content_len && *after == '{') {
|
|
494
|
+
const char *close = content + content_len - 1;
|
|
495
|
+
while (close > after && *close != '}') close--;
|
|
496
|
+
if (*close == '}') {
|
|
497
|
+
size_t attrs_len = (size_t)(close - (after + 1));
|
|
498
|
+
char attrs[768];
|
|
499
|
+
if (attrs_len >= sizeof(attrs)) attrs_len = sizeof(attrs) - 1;
|
|
500
|
+
memcpy(attrs, after + 1, attrs_len);
|
|
501
|
+
attrs[attrs_len] = '\0';
|
|
502
|
+
|
|
503
|
+
char *attrs_work = strdup(attrs);
|
|
504
|
+
if (!attrs_work) goto fail;
|
|
505
|
+
char *token = strtok(attrs_work, " \t");
|
|
506
|
+
char type_buf[64] = {0};
|
|
507
|
+
char title_buf[256] = {0};
|
|
508
|
+
bool collapsible = false;
|
|
509
|
+
bool default_open = true;
|
|
510
|
+
while (token) {
|
|
511
|
+
if (strncmp(token, ".callout-", 9) == 0) {
|
|
512
|
+
strncpy(type_buf, token + 9, sizeof(type_buf) - 1);
|
|
513
|
+
} else if (strncmp(token, "title=", 6) == 0) {
|
|
514
|
+
const char *v = token + 6;
|
|
515
|
+
size_t vlen = strlen(v);
|
|
516
|
+
if (vlen >= 2 && ((v[0] == '"' && v[vlen - 1] == '"') || (v[0] == '\'' && v[vlen - 1] == '\''))) {
|
|
517
|
+
v++;
|
|
518
|
+
vlen -= 2;
|
|
519
|
+
}
|
|
520
|
+
if (vlen >= sizeof(title_buf)) vlen = sizeof(title_buf) - 1;
|
|
521
|
+
memcpy(title_buf, v, vlen);
|
|
522
|
+
title_buf[vlen] = '\0';
|
|
523
|
+
} else if (strncmp(token, "collapse=", 9) == 0) {
|
|
524
|
+
const char *v = token + 9;
|
|
525
|
+
if (strcasecmp(v, "\"true\"") == 0 || strcasecmp(v, "true") == 0) {
|
|
526
|
+
collapsible = true;
|
|
527
|
+
default_open = false;
|
|
528
|
+
} else if (strcasecmp(v, "\"false\"") == 0 || strcasecmp(v, "false") == 0) {
|
|
529
|
+
collapsible = true;
|
|
530
|
+
default_open = true;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
token = strtok(NULL, " \t");
|
|
534
|
+
}
|
|
535
|
+
free(attrs_work);
|
|
536
|
+
|
|
537
|
+
if (type_buf[0]) {
|
|
538
|
+
callout_type_t ct = detect_callout_type(type_buf, (int)strlen(type_buf));
|
|
539
|
+
if (ct != CALLOUT_NONE) {
|
|
540
|
+
char header[512];
|
|
541
|
+
char marker = collapsible ? (default_open ? '+' : '-') : ']';
|
|
542
|
+
if (marker == ']') {
|
|
543
|
+
if (title_buf[0]) snprintf(header, sizeof(header), "> [!%s] %s", type_buf, title_buf);
|
|
544
|
+
else snprintf(header, sizeof(header), "> [!%s]", type_buf);
|
|
545
|
+
} else {
|
|
546
|
+
if (title_buf[0]) snprintf(header, sizeof(header), "> [!%s]%c %s", type_buf, marker, title_buf);
|
|
547
|
+
else snprintf(header, sizeof(header), "> [!%s]%c", type_buf, marker);
|
|
548
|
+
}
|
|
549
|
+
if (!append_str(&out, &len, &cap, header)) goto fail;
|
|
550
|
+
if (has_nl && !append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
551
|
+
|
|
552
|
+
p = has_nl ? line_end + 1 : line_start + line_len;
|
|
553
|
+
bool had_title_heading = false;
|
|
554
|
+
bool emitted_body_content = false;
|
|
555
|
+
while (*p) {
|
|
556
|
+
const char *body_start = p;
|
|
557
|
+
const char *body_end = strchr(p, '\n');
|
|
558
|
+
bool body_nl = body_end != NULL;
|
|
559
|
+
size_t body_len = body_nl ? (size_t)(body_end - body_start) : strlen(body_start);
|
|
560
|
+
|
|
561
|
+
const char *body_content = body_start;
|
|
562
|
+
while ((size_t)(body_content - body_start) < body_len && (*body_content == ' ' || *body_content == '\t')) body_content++;
|
|
563
|
+
size_t body_content_len = body_len - (size_t)(body_content - body_start);
|
|
564
|
+
|
|
565
|
+
if (body_content_len >= 3 && strncmp(body_content, ":::", 3) == 0) {
|
|
566
|
+
p = body_nl ? body_end + 1 : body_start + body_len;
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (!title_buf[0] && !had_title_heading && body_content_len > 2 &&
|
|
571
|
+
body_content[0] == '#' && body_content[1] == '#') {
|
|
572
|
+
had_title_heading = true;
|
|
573
|
+
if (body_nl) p = body_end + 1;
|
|
574
|
+
else p = body_start + body_len;
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/* Avoid emitting an empty leading paragraph after heading/title removal. */
|
|
579
|
+
if (body_len == 0 && !emitted_body_content) {
|
|
580
|
+
p = body_nl ? body_end + 1 : body_start + body_len;
|
|
581
|
+
continue;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if (!append_str(&out, &len, &cap, ">")) goto fail;
|
|
585
|
+
if (body_len > 0) {
|
|
586
|
+
if (!append_str(&out, &len, &cap, " ")) goto fail;
|
|
587
|
+
if (!append_chunk(&out, &len, &cap, body_start, body_len)) goto fail;
|
|
588
|
+
emitted_body_content = true;
|
|
589
|
+
}
|
|
590
|
+
if (body_nl && !append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
591
|
+
p = body_nl ? body_end + 1 : body_start + body_len;
|
|
592
|
+
}
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
if (!append_chunk(&out, &len, &cap, line_start, line_len)) goto fail;
|
|
601
|
+
if (has_nl && !append_chunk(&out, &len, &cap, "\n", 1)) goto fail;
|
|
602
|
+
p = has_nl ? line_end + 1 : line_start + line_len;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
return out;
|
|
606
|
+
|
|
607
|
+
fail:
|
|
608
|
+
free(out);
|
|
609
|
+
return NULL;
|
|
610
|
+
}
|
|
611
|
+
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Callouts Extension for Apex
|
|
3
3
|
*
|
|
4
|
-
* Supports Bear/Obsidian
|
|
4
|
+
* Supports Bear/Obsidian callout syntax:
|
|
5
5
|
* > [!NOTE] Title
|
|
6
6
|
* > Content
|
|
7
|
-
*
|
|
8
|
-
* - Attention: Title
|
|
9
|
-
* Content
|
|
10
7
|
*/
|
|
11
8
|
|
|
12
9
|
#ifndef APEX_CALLOUTS_H
|
|
@@ -43,7 +40,20 @@ typedef enum {
|
|
|
43
40
|
/**
|
|
44
41
|
* Process callouts in AST (postprocessing)
|
|
45
42
|
*/
|
|
46
|
-
void apex_process_callouts_in_tree(cmark_node *document);
|
|
43
|
+
void apex_process_callouts_in_tree(cmark_node *document, bool enable_py_callouts);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Preprocess Python-Markdown callouts into Obsidian-style blockquotes.
|
|
47
|
+
* Pattern: !!! type "Optional title" followed by indented content.
|
|
48
|
+
* Returns newly allocated string or NULL on allocation failure.
|
|
49
|
+
*/
|
|
50
|
+
char *apex_preprocess_py_callouts(const char *text);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Preprocess Quarto ::: {.callout-*} callouts into Obsidian-style blockquotes.
|
|
54
|
+
* Returns newly allocated string or NULL on allocation failure.
|
|
55
|
+
*/
|
|
56
|
+
char *apex_preprocess_quarto_callouts(const char *text);
|
|
47
57
|
|
|
48
58
|
#ifdef __cplusplus
|
|
49
59
|
}
|
|
@@ -107,12 +107,29 @@ static bool is_mmark_pattern(const char *text, int pos, int len) {
|
|
|
107
107
|
return false;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Quarto cross-ref keys (fig-/sec-/tbl-/eq-) use bare @ syntax and must not be
|
|
112
|
+
* parsed as author-in-text citations when quarto-xrefs is enabled.
|
|
113
|
+
*/
|
|
114
|
+
static bool apex_citation_key_is_quarto_xref(const char *key) {
|
|
115
|
+
if (!key) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
static const char *prefixes[] = { "fig-", "sec-", "tbl-", "eq-", NULL };
|
|
119
|
+
for (int i = 0; prefixes[i]; i++) {
|
|
120
|
+
size_t n = strlen(prefixes[i]);
|
|
121
|
+
if (strncmp(key, prefixes[i], n) == 0) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
|
|
110
128
|
/**
|
|
111
129
|
* Parse Pandoc citation: [@key] or @key or [see @key, pp. 33-35]
|
|
112
130
|
*/
|
|
113
131
|
static int parse_pandoc_citation(const char *text, int pos, int len,
|
|
114
132
|
apex_citation **citation_out, const apex_options *options) {
|
|
115
|
-
(void)options; /* Unused for now */
|
|
116
133
|
if (pos >= len) return 0;
|
|
117
134
|
|
|
118
135
|
const char *p = text + pos;
|
|
@@ -128,6 +145,10 @@ static int parse_pandoc_citation(const char *text, int pos, int len,
|
|
|
128
145
|
p++;
|
|
129
146
|
int key_len = extract_citation_key(text, apex_ptrdiff_to_int(p - text), len, &key);
|
|
130
147
|
if (key_len > 0 && key) {
|
|
148
|
+
if (options && options->enable_quarto_xrefs && apex_citation_key_is_quarto_xref(key)) {
|
|
149
|
+
free(key);
|
|
150
|
+
return 0;
|
|
151
|
+
}
|
|
131
152
|
/* Check if there's a locator after: @key [p. 33] */
|
|
132
153
|
const char *after_key = p + key_len;
|
|
133
154
|
while (after_key < text + len && isspace(*after_key)) after_key++;
|
|
@@ -418,7 +439,7 @@ char *apex_process_citations(const char *text, apex_citation_registry *registry,
|
|
|
418
439
|
|
|
419
440
|
/* Citations only enabled in certain modes */
|
|
420
441
|
if (options->mode != APEX_MODE_MULTIMARKDOWN &&
|
|
421
|
-
options->mode
|
|
442
|
+
!apex_mode_is_unified_family(options->mode)) {
|
|
422
443
|
return NULL; /* Citations not enabled in this mode */
|
|
423
444
|
}
|
|
424
445
|
|
|
@@ -487,17 +508,17 @@ char *apex_process_citations(const char *text, apex_citation_registry *registry,
|
|
|
487
508
|
int consumed = 0;
|
|
488
509
|
|
|
489
510
|
/* Try mmark first (most specific pattern) */
|
|
490
|
-
if (options->mode
|
|
511
|
+
if (apex_mode_is_unified_family(options->mode)) {
|
|
491
512
|
consumed = parse_mmark_citation(text, pos, apex_size_to_int(len), &citation, options);
|
|
492
513
|
}
|
|
493
514
|
|
|
494
515
|
/* Try MultiMarkdown */
|
|
495
|
-
if (!citation && (options->mode == APEX_MODE_MULTIMARKDOWN || options->mode
|
|
516
|
+
if (!citation && (options->mode == APEX_MODE_MULTIMARKDOWN || apex_mode_is_unified_family(options->mode))) {
|
|
496
517
|
consumed = parse_mmd_citation(text, pos, apex_size_to_int(len), &citation, options);
|
|
497
518
|
}
|
|
498
519
|
|
|
499
520
|
/* Try Pandoc (most common) */
|
|
500
|
-
if (!citation && (options->mode
|
|
521
|
+
if (!citation && apex_mode_is_unified_family(options->mode)) {
|
|
501
522
|
consumed = parse_pandoc_citation(text, pos, apex_size_to_int(len), &citation, options);
|
|
502
523
|
}
|
|
503
524
|
|