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