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.
- 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
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
#include "includes.h"
|
|
7
7
|
#include "metadata.h"
|
|
8
|
+
#include "../plugins.h"
|
|
8
9
|
#include <stdio.h>
|
|
9
10
|
#include <stdlib.h>
|
|
10
11
|
#include <string.h>
|
|
@@ -1236,6 +1237,242 @@ static bool parse_embedded_delimiter_override(char *filepath, char *delimiter_ou
|
|
|
1236
1237
|
return true;
|
|
1237
1238
|
}
|
|
1238
1239
|
|
|
1240
|
+
static char *trim_copy(const char *s, size_t len) {
|
|
1241
|
+
if (!s) return NULL;
|
|
1242
|
+
while (len > 0 && isspace((unsigned char)*s)) {
|
|
1243
|
+
s++;
|
|
1244
|
+
len--;
|
|
1245
|
+
}
|
|
1246
|
+
while (len > 0 && isspace((unsigned char)s[len - 1])) {
|
|
1247
|
+
len--;
|
|
1248
|
+
}
|
|
1249
|
+
char *out = malloc(len + 1);
|
|
1250
|
+
if (!out) return NULL;
|
|
1251
|
+
memcpy(out, s, len);
|
|
1252
|
+
out[len] = '\0';
|
|
1253
|
+
return out;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
static void split_section_fragment(char *filepath, char **section_out) {
|
|
1257
|
+
if (section_out) *section_out = NULL;
|
|
1258
|
+
if (!filepath) return;
|
|
1259
|
+
|
|
1260
|
+
char *hash = strchr(filepath, '#');
|
|
1261
|
+
if (!hash) return;
|
|
1262
|
+
|
|
1263
|
+
*hash = '\0';
|
|
1264
|
+
hash++;
|
|
1265
|
+
while (*hash && isspace((unsigned char)*hash)) hash++;
|
|
1266
|
+
if (!*hash) return;
|
|
1267
|
+
|
|
1268
|
+
if (section_out) {
|
|
1269
|
+
*section_out = strdup(hash);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
static bool has_extension(const char *path) {
|
|
1274
|
+
if (!path || !*path) return false;
|
|
1275
|
+
const char *slash = strrchr(path, '/');
|
|
1276
|
+
const char *base = slash ? slash + 1 : path;
|
|
1277
|
+
const char *dot = strrchr(base, '.');
|
|
1278
|
+
return dot && dot[1] != '\0';
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
static char *with_default_extension(const char *path, const char *ext_without_dot) {
|
|
1282
|
+
if (!path || !*path) return NULL;
|
|
1283
|
+
if (has_extension(path)) return strdup(path);
|
|
1284
|
+
if (!ext_without_dot || !*ext_without_dot) return strdup(path);
|
|
1285
|
+
|
|
1286
|
+
size_t len = strlen(path) + strlen(ext_without_dot) + 2;
|
|
1287
|
+
char *out = malloc(len);
|
|
1288
|
+
if (!out) return NULL;
|
|
1289
|
+
snprintf(out, len, "%s.%s", path, ext_without_dot);
|
|
1290
|
+
return out;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
static const char *next_line_start(const char *line_end) {
|
|
1294
|
+
if (!line_end) return NULL;
|
|
1295
|
+
if (*line_end == '\n') return line_end + 1;
|
|
1296
|
+
if (*line_end == '\0') return line_end;
|
|
1297
|
+
return line_end + 1;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
static bool parse_setext_underline(const char *line, size_t len, int *level_out) {
|
|
1301
|
+
if (!line || len == 0) return false;
|
|
1302
|
+
size_t i = 0;
|
|
1303
|
+
while (i < len && line[i] == ' ') i++;
|
|
1304
|
+
if (i > 3 || i >= len) return false;
|
|
1305
|
+
|
|
1306
|
+
char marker = 0;
|
|
1307
|
+
int marker_count = 0;
|
|
1308
|
+
for (; i < len; i++) {
|
|
1309
|
+
char c = line[i];
|
|
1310
|
+
if (c == '\r') continue;
|
|
1311
|
+
if (c == '=' || c == '-') {
|
|
1312
|
+
if (marker == 0) marker = c;
|
|
1313
|
+
if (c != marker) return false;
|
|
1314
|
+
marker_count++;
|
|
1315
|
+
continue;
|
|
1316
|
+
}
|
|
1317
|
+
if (!isspace((unsigned char)c)) return false;
|
|
1318
|
+
}
|
|
1319
|
+
if (marker_count == 0 || marker == 0) return false;
|
|
1320
|
+
if (level_out) *level_out = (marker == '=') ? 1 : 2;
|
|
1321
|
+
return true;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
static char *normalize_heading_text(const char *start, size_t len, bool is_atx) {
|
|
1325
|
+
if (!start) return NULL;
|
|
1326
|
+
|
|
1327
|
+
while (len > 0 && isspace((unsigned char)*start)) {
|
|
1328
|
+
start++;
|
|
1329
|
+
len--;
|
|
1330
|
+
}
|
|
1331
|
+
while (len > 0 && isspace((unsigned char)start[len - 1])) {
|
|
1332
|
+
len--;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
if (is_atx && len > 0) {
|
|
1336
|
+
size_t t = len;
|
|
1337
|
+
while (t > 0 && start[t - 1] == '#') t--;
|
|
1338
|
+
if (t < len) {
|
|
1339
|
+
size_t u = t;
|
|
1340
|
+
while (u > 0 && isspace((unsigned char)start[u - 1])) u--;
|
|
1341
|
+
if (u < t) len = u;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
/* Collapse spaces and lowercase for matching. */
|
|
1346
|
+
char *out = malloc(len + 1);
|
|
1347
|
+
if (!out) return NULL;
|
|
1348
|
+
|
|
1349
|
+
size_t w = 0;
|
|
1350
|
+
bool in_space = false;
|
|
1351
|
+
for (size_t i = 0; i < len; i++) {
|
|
1352
|
+
unsigned char c = (unsigned char)start[i];
|
|
1353
|
+
if (isspace(c)) {
|
|
1354
|
+
if (!in_space) {
|
|
1355
|
+
out[w++] = ' ';
|
|
1356
|
+
in_space = true;
|
|
1357
|
+
}
|
|
1358
|
+
continue;
|
|
1359
|
+
}
|
|
1360
|
+
out[w++] = (char)tolower(c);
|
|
1361
|
+
in_space = false;
|
|
1362
|
+
}
|
|
1363
|
+
while (w > 0 && out[w - 1] == ' ') w--;
|
|
1364
|
+
out[w] = '\0';
|
|
1365
|
+
return out;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
static bool parse_atx_heading(const char *line_start, const char *line_end,
|
|
1369
|
+
int *level_out, char **normalized_out) {
|
|
1370
|
+
if (normalized_out) *normalized_out = NULL;
|
|
1371
|
+
if (!line_start || !line_end || line_end < line_start) return false;
|
|
1372
|
+
|
|
1373
|
+
const char *p = line_start;
|
|
1374
|
+
int leading_spaces = 0;
|
|
1375
|
+
while (p < line_end && *p == ' ' && leading_spaces < 4) {
|
|
1376
|
+
p++;
|
|
1377
|
+
leading_spaces++;
|
|
1378
|
+
}
|
|
1379
|
+
if (leading_spaces > 3 || p >= line_end || *p != '#') return false;
|
|
1380
|
+
|
|
1381
|
+
int level = 0;
|
|
1382
|
+
while (p < line_end && *p == '#' && level < 6) {
|
|
1383
|
+
p++;
|
|
1384
|
+
level++;
|
|
1385
|
+
}
|
|
1386
|
+
if (level == 0) return false;
|
|
1387
|
+
if (p < line_end && !isspace((unsigned char)*p)) return false;
|
|
1388
|
+
|
|
1389
|
+
while (p < line_end && isspace((unsigned char)*p)) p++;
|
|
1390
|
+
size_t text_len = (size_t)(line_end - p);
|
|
1391
|
+
|
|
1392
|
+
if (level_out) *level_out = level;
|
|
1393
|
+
if (normalized_out) {
|
|
1394
|
+
*normalized_out = normalize_heading_text(p, text_len, true);
|
|
1395
|
+
}
|
|
1396
|
+
return true;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
static char *extract_markdown_section(const char *content, const char *section_name) {
|
|
1400
|
+
if (!content || !section_name || !*section_name) {
|
|
1401
|
+
return content ? strdup(content) : NULL;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
char *target = normalize_heading_text(section_name, strlen(section_name), false);
|
|
1405
|
+
if (!target || !*target) {
|
|
1406
|
+
if (target) free(target);
|
|
1407
|
+
return NULL;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
const char *cursor = content;
|
|
1411
|
+
const char *section_start = NULL;
|
|
1412
|
+
const char *section_end = NULL;
|
|
1413
|
+
int target_level = 0;
|
|
1414
|
+
bool found = false;
|
|
1415
|
+
|
|
1416
|
+
while (*cursor) {
|
|
1417
|
+
const char *line_end = strchr(cursor, '\n');
|
|
1418
|
+
if (!line_end) line_end = cursor + strlen(cursor);
|
|
1419
|
+
const char *next = next_line_start(line_end);
|
|
1420
|
+
const char *next_end = (*next) ? (strchr(next, '\n') ? strchr(next, '\n') : next + strlen(next)) : next;
|
|
1421
|
+
|
|
1422
|
+
int level = 0;
|
|
1423
|
+
char *heading_norm = NULL;
|
|
1424
|
+
bool heading_found = parse_atx_heading(cursor, line_end, &level, &heading_norm);
|
|
1425
|
+
bool is_setext = false;
|
|
1426
|
+
|
|
1427
|
+
if (!heading_found && *next && next > cursor) {
|
|
1428
|
+
int setext_level = 0;
|
|
1429
|
+
size_t cur_len = (size_t)(line_end - cursor);
|
|
1430
|
+
if (cur_len > 0 && parse_setext_underline(next, (size_t)(next_end - next), &setext_level)) {
|
|
1431
|
+
heading_found = true;
|
|
1432
|
+
is_setext = true;
|
|
1433
|
+
level = setext_level;
|
|
1434
|
+
heading_norm = normalize_heading_text(cursor, cur_len, false);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
if (heading_found) {
|
|
1439
|
+
if (!found) {
|
|
1440
|
+
if (heading_norm && strcmp(heading_norm, target) == 0) {
|
|
1441
|
+
found = true;
|
|
1442
|
+
target_level = level;
|
|
1443
|
+
section_start = cursor;
|
|
1444
|
+
if (is_setext) {
|
|
1445
|
+
cursor = (*next_end == '\n') ? (next_end + 1) : next_end;
|
|
1446
|
+
free(heading_norm);
|
|
1447
|
+
continue;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
} else {
|
|
1451
|
+
if (level <= target_level) {
|
|
1452
|
+
section_end = cursor;
|
|
1453
|
+
free(heading_norm);
|
|
1454
|
+
break;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
if (heading_norm) free(heading_norm);
|
|
1460
|
+
cursor = (*line_end == '\n') ? (line_end + 1) : line_end;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
free(target);
|
|
1464
|
+
|
|
1465
|
+
if (!found || !section_start) return NULL;
|
|
1466
|
+
if (!section_end) section_end = content + strlen(content);
|
|
1467
|
+
|
|
1468
|
+
size_t out_len = (size_t)(section_end - section_start);
|
|
1469
|
+
char *out = malloc(out_len + 1);
|
|
1470
|
+
if (!out) return NULL;
|
|
1471
|
+
memcpy(out, section_start, out_len);
|
|
1472
|
+
out[out_len] = '\0';
|
|
1473
|
+
return out;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1239
1476
|
/* Find closing "}}" for MMD transclusion, allowing embedded single-brace
|
|
1240
1477
|
* segments inside filepath (e.g. {{data.csv{;}}}). */
|
|
1241
1478
|
static const char *find_mmd_transclusion_end(const char *filepath_start) {
|
|
@@ -1263,10 +1500,34 @@ static const char *find_mmd_transclusion_end(const char *filepath_start) {
|
|
|
1263
1500
|
return NULL;
|
|
1264
1501
|
}
|
|
1265
1502
|
|
|
1503
|
+
static char *run_preparse_plugins_on_text(const char *text,
|
|
1504
|
+
apex_plugin_manager *plugin_manager,
|
|
1505
|
+
const apex_options *options) {
|
|
1506
|
+
if (!text) {
|
|
1507
|
+
return NULL;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
if (!plugin_manager || !options) {
|
|
1511
|
+
return NULL;
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
char *plugin_text = apex_plugins_run_text_phase(plugin_manager,
|
|
1515
|
+
APEX_PLUGIN_PHASE_PRE_PARSE,
|
|
1516
|
+
text,
|
|
1517
|
+
options);
|
|
1518
|
+
return plugin_text;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1266
1521
|
/**
|
|
1267
1522
|
* Process file includes in text
|
|
1268
1523
|
*/
|
|
1269
|
-
char *apex_process_includes(const char *text,
|
|
1524
|
+
char *apex_process_includes(const char *text,
|
|
1525
|
+
const char *base_dir,
|
|
1526
|
+
apex_metadata_item *metadata,
|
|
1527
|
+
int depth,
|
|
1528
|
+
const char *default_extension,
|
|
1529
|
+
apex_plugin_manager *plugin_manager,
|
|
1530
|
+
const apex_options *options) {
|
|
1270
1531
|
if (!text) return NULL;
|
|
1271
1532
|
if (depth > MAX_INCLUDE_DEPTH) {
|
|
1272
1533
|
return strdup(text); /* Silently return original text */
|
|
@@ -1312,26 +1573,197 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1312
1573
|
in_code_span = !in_code_span;
|
|
1313
1574
|
}
|
|
1314
1575
|
|
|
1576
|
+
/* Obsidian embed syntax: ![[file]] or ![[file#Section]] */
|
|
1577
|
+
if (!in_code_span && read_pos[0] == '!' && read_pos[1] == '[' && read_pos[2] == '[') {
|
|
1578
|
+
const char *content_start = read_pos + 3;
|
|
1579
|
+
const char *close = strstr(content_start, "]]");
|
|
1580
|
+
if (close && (close - content_start) > 0 && (close - content_start) < 1024) {
|
|
1581
|
+
char target[1024];
|
|
1582
|
+
size_t target_len = (size_t)(close - content_start);
|
|
1583
|
+
memcpy(target, content_start, target_len);
|
|
1584
|
+
target[target_len] = '\0';
|
|
1585
|
+
|
|
1586
|
+
char *pipe = strchr(target, '|');
|
|
1587
|
+
if (pipe) *pipe = '\0'; /* Ignore alias text for includes */
|
|
1588
|
+
|
|
1589
|
+
percent_decode_inplace(target);
|
|
1590
|
+
|
|
1591
|
+
char *section_name = NULL;
|
|
1592
|
+
split_section_fragment(target, §ion_name);
|
|
1593
|
+
|
|
1594
|
+
const char *effective_default_ext = default_extension;
|
|
1595
|
+
while (effective_default_ext && *effective_default_ext == '.') {
|
|
1596
|
+
effective_default_ext++;
|
|
1597
|
+
}
|
|
1598
|
+
if (effective_default_ext && *effective_default_ext == '\0') {
|
|
1599
|
+
effective_default_ext = NULL;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
bool had_explicit_ext = has_extension(target);
|
|
1603
|
+
char *target_with_ext = with_default_extension(target, effective_default_ext ? effective_default_ext : "md");
|
|
1604
|
+
char *resolved_path = apex_resolve_wildcard(target_with_ext ? target_with_ext : target, effective_base_dir);
|
|
1605
|
+
if (!resolved_path) {
|
|
1606
|
+
resolved_path = resolve_path(target_with_ext ? target_with_ext : target, effective_base_dir);
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
/* If a non-md default extension was configured but didn't resolve,
|
|
1610
|
+
* fall back to .md to keep Obsidian-style embeds practical. */
|
|
1611
|
+
if (!had_explicit_ext &&
|
|
1612
|
+
(!resolved_path || !apex_file_exists(resolved_path)) &&
|
|
1613
|
+
effective_default_ext &&
|
|
1614
|
+
strcasecmp(effective_default_ext, "md") != 0) {
|
|
1615
|
+
char *md_target = with_default_extension(target, "md");
|
|
1616
|
+
char *md_resolved = apex_resolve_wildcard(md_target ? md_target : target, effective_base_dir);
|
|
1617
|
+
if (!md_resolved) {
|
|
1618
|
+
md_resolved = resolve_path(md_target ? md_target : target, effective_base_dir);
|
|
1619
|
+
}
|
|
1620
|
+
if (md_target) free(md_target);
|
|
1621
|
+
if (md_resolved && apex_file_exists(md_resolved)) {
|
|
1622
|
+
if (resolved_path) free(resolved_path);
|
|
1623
|
+
resolved_path = md_resolved;
|
|
1624
|
+
} else if (md_resolved) {
|
|
1625
|
+
free(md_resolved);
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
if (resolved_path && apex_file_exists(resolved_path)) {
|
|
1630
|
+
apex_file_type_t file_type = apex_detect_file_type(resolved_path);
|
|
1631
|
+
char *content = read_file_contents(resolved_path);
|
|
1632
|
+
if (content) {
|
|
1633
|
+
char *to_insert = NULL;
|
|
1634
|
+
bool free_to_insert = false;
|
|
1635
|
+
|
|
1636
|
+
if (file_type == FILE_TYPE_IMAGE) {
|
|
1637
|
+
size_t buf_size = strlen(target_with_ext ? target_with_ext : target) + 10;
|
|
1638
|
+
to_insert = malloc(buf_size);
|
|
1639
|
+
if (to_insert) snprintf(to_insert, buf_size, "\n", target_with_ext ? target_with_ext : target);
|
|
1640
|
+
free_to_insert = true;
|
|
1641
|
+
} else if (file_type == FILE_TYPE_CSV || file_type == FILE_TYPE_TSV) {
|
|
1642
|
+
char *plugin_csv_content = run_preparse_plugins_on_text(content, plugin_manager, options);
|
|
1643
|
+
const char *csv_content = plugin_csv_content ? plugin_csv_content : content;
|
|
1644
|
+
to_insert = apex_csv_to_table_with_delimiter(csv_content, file_type == FILE_TYPE_TSV, '\0');
|
|
1645
|
+
if (plugin_csv_content) free(plugin_csv_content);
|
|
1646
|
+
free_to_insert = true;
|
|
1647
|
+
} else if (file_type == FILE_TYPE_CODE) {
|
|
1648
|
+
char *plugin_code_content = run_preparse_plugins_on_text(content, plugin_manager, options);
|
|
1649
|
+
const char *code_content = plugin_code_content ? plugin_code_content : content;
|
|
1650
|
+
const char *ext = strrchr(target_with_ext ? target_with_ext : target, '.');
|
|
1651
|
+
const char *lang = ext ? ext + 1 : "";
|
|
1652
|
+
size_t buf_size = strlen(code_content) + strlen(lang) + 20;
|
|
1653
|
+
to_insert = malloc(buf_size);
|
|
1654
|
+
if (to_insert) snprintf(to_insert, buf_size, "\n```%s\n%s\n```\n", lang, code_content);
|
|
1655
|
+
if (plugin_code_content) free(plugin_code_content);
|
|
1656
|
+
free_to_insert = true;
|
|
1657
|
+
} else {
|
|
1658
|
+
char *section_content = section_name ? extract_markdown_section(content, section_name) : NULL;
|
|
1659
|
+
char *base_content = section_content ? section_content : strdup(content);
|
|
1660
|
+
char *plugin_base_content = run_preparse_plugins_on_text(base_content ? base_content : content,
|
|
1661
|
+
plugin_manager,
|
|
1662
|
+
options);
|
|
1663
|
+
const char *content_for_processing = plugin_base_content ? plugin_base_content : (base_content ? base_content : content);
|
|
1664
|
+
|
|
1665
|
+
char *file_content_for_metadata = strdup(content_for_processing);
|
|
1666
|
+
apex_metadata_item *file_metadata = NULL;
|
|
1667
|
+
char *file_text_after_metadata = file_content_for_metadata;
|
|
1668
|
+
if (file_content_for_metadata) {
|
|
1669
|
+
file_metadata = apex_extract_metadata(&file_text_after_metadata);
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
char *transclude_base = NULL;
|
|
1673
|
+
if (file_metadata) {
|
|
1674
|
+
transclude_base = get_transclude_base(get_directory(resolved_path), file_metadata);
|
|
1675
|
+
}
|
|
1676
|
+
if (!transclude_base) {
|
|
1677
|
+
transclude_base = get_directory(resolved_path);
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
to_insert = apex_process_includes(content_for_processing,
|
|
1681
|
+
transclude_base,
|
|
1682
|
+
file_metadata,
|
|
1683
|
+
depth + 1,
|
|
1684
|
+
default_extension,
|
|
1685
|
+
plugin_manager,
|
|
1686
|
+
options);
|
|
1687
|
+
free_to_insert = true;
|
|
1688
|
+
|
|
1689
|
+
if (transclude_base) free(transclude_base);
|
|
1690
|
+
if (file_metadata) apex_free_metadata(file_metadata);
|
|
1691
|
+
if (file_content_for_metadata) free(file_content_for_metadata);
|
|
1692
|
+
if (plugin_base_content) free(plugin_base_content);
|
|
1693
|
+
if (base_content) free(base_content);
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
if (to_insert) {
|
|
1697
|
+
size_t insert_len = strlen(to_insert);
|
|
1698
|
+
if (insert_len < remaining) {
|
|
1699
|
+
memcpy(write_pos, to_insert, insert_len);
|
|
1700
|
+
write_pos += insert_len;
|
|
1701
|
+
remaining -= insert_len;
|
|
1702
|
+
}
|
|
1703
|
+
if (free_to_insert) free(to_insert);
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
free(content);
|
|
1707
|
+
read_pos = close + 2;
|
|
1708
|
+
processed_include = true;
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
if (target_with_ext) free(target_with_ext);
|
|
1713
|
+
if (resolved_path) free(resolved_path);
|
|
1714
|
+
if (section_name) free(section_name);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1315
1718
|
/* Look for iA Writer transclusion /filename (at start of line only) */
|
|
1316
1719
|
if (!in_code_span && read_pos[0] == '/' && (read_pos == text_to_process || read_pos[-1] == '\n')) {
|
|
1317
1720
|
const char *filepath_start = read_pos + 1;
|
|
1318
|
-
const char *
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
while (*filepath_end && *filepath_end != ' ' && *filepath_end != '\t' &&
|
|
1322
|
-
*filepath_end != '\n' && *filepath_end != '\r') {
|
|
1323
|
-
filepath_end++;
|
|
1721
|
+
const char *line_end = read_pos;
|
|
1722
|
+
while (*line_end && *line_end != '\n' && *line_end != '\r') {
|
|
1723
|
+
line_end++;
|
|
1324
1724
|
}
|
|
1325
1725
|
|
|
1326
|
-
if (
|
|
1726
|
+
if (line_end > filepath_start && (line_end - filepath_start) < 1024) {
|
|
1327
1727
|
char filepath[1024];
|
|
1328
|
-
size_t filepath_len =
|
|
1728
|
+
size_t filepath_len = (size_t)(line_end - filepath_start);
|
|
1329
1729
|
char ia_delimiter_override = '\0';
|
|
1330
1730
|
memcpy(filepath, filepath_start, filepath_len);
|
|
1331
1731
|
filepath[filepath_len] = '\0';
|
|
1732
|
+
|
|
1733
|
+
/* Trim leading/trailing whitespace for line-based iA include. */
|
|
1734
|
+
char *trimmed = trim_copy(filepath, strlen(filepath));
|
|
1735
|
+
if (!trimmed) {
|
|
1736
|
+
read_pos = line_end;
|
|
1737
|
+
processed_include = true;
|
|
1738
|
+
continue;
|
|
1739
|
+
}
|
|
1740
|
+
strncpy(filepath, trimmed, sizeof(filepath) - 1);
|
|
1741
|
+
filepath[sizeof(filepath) - 1] = '\0';
|
|
1742
|
+
free(trimmed);
|
|
1743
|
+
|
|
1744
|
+
/* Allow trailing delimiter override on iA syntax, e.g. /data.csv {delimiter=;} */
|
|
1745
|
+
char *last_brace = strrchr(filepath, '{');
|
|
1746
|
+
if (last_brace) {
|
|
1747
|
+
const char *after_override = NULL;
|
|
1748
|
+
char parsed = '\0';
|
|
1749
|
+
if (parse_include_delimiter_override(last_brace, &after_override, &parsed) &&
|
|
1750
|
+
after_override && *after_override == '\0') {
|
|
1751
|
+
ia_delimiter_override = parsed;
|
|
1752
|
+
*last_brace = '\0';
|
|
1753
|
+
size_t trim_len = strlen(filepath);
|
|
1754
|
+
while (trim_len > 0 && isspace((unsigned char)filepath[trim_len - 1])) {
|
|
1755
|
+
filepath[trim_len - 1] = '\0';
|
|
1756
|
+
trim_len--;
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1332
1761
|
percent_decode_inplace(filepath);
|
|
1333
1762
|
parse_embedded_delimiter_override(filepath, &ia_delimiter_override);
|
|
1334
1763
|
|
|
1764
|
+
char *section_name = NULL;
|
|
1765
|
+
split_section_fragment(filepath, §ion_name);
|
|
1766
|
+
|
|
1335
1767
|
/* Resolve and check file exists */
|
|
1336
1768
|
char *resolved_path = resolve_path(filepath, effective_base_dir);
|
|
1337
1769
|
if (resolved_path && apex_file_exists(resolved_path)) {
|
|
@@ -1349,23 +1781,31 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1349
1781
|
} else if (file_type == FILE_TYPE_CSV || file_type == FILE_TYPE_TSV) {
|
|
1350
1782
|
/* CSV/TSV: convert to table */
|
|
1351
1783
|
char delimiter_override = ia_delimiter_override;
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
}
|
|
1357
|
-
to_insert = apex_csv_to_table_with_delimiter(content, file_type == FILE_TYPE_TSV, delimiter_override);
|
|
1784
|
+
char *plugin_csv_content = run_preparse_plugins_on_text(content, plugin_manager, options);
|
|
1785
|
+
const char *csv_content = plugin_csv_content ? plugin_csv_content : content;
|
|
1786
|
+
to_insert = apex_csv_to_table_with_delimiter(csv_content, file_type == FILE_TYPE_TSV, delimiter_override);
|
|
1787
|
+
if (plugin_csv_content) free(plugin_csv_content);
|
|
1358
1788
|
} else if (file_type == FILE_TYPE_CODE) {
|
|
1359
1789
|
/* Code: wrap in fenced code block */
|
|
1790
|
+
char *plugin_code_content = run_preparse_plugins_on_text(content, plugin_manager, options);
|
|
1791
|
+
const char *code_content = plugin_code_content ? plugin_code_content : content;
|
|
1360
1792
|
const char *ext = strrchr(filepath, '.');
|
|
1361
1793
|
const char *lang = ext ? ext + 1 : "";
|
|
1362
|
-
size_t buf_size = strlen(
|
|
1794
|
+
size_t buf_size = strlen(code_content) + strlen(lang) + 20;
|
|
1363
1795
|
to_insert = malloc(buf_size);
|
|
1364
|
-
if (to_insert) snprintf(to_insert, buf_size, "\n```%s\n%s\n```\n", lang,
|
|
1796
|
+
if (to_insert) snprintf(to_insert, buf_size, "\n```%s\n%s\n```\n", lang, code_content);
|
|
1797
|
+
if (plugin_code_content) free(plugin_code_content);
|
|
1365
1798
|
} else {
|
|
1366
1799
|
/* Text/Markdown: process and include */
|
|
1800
|
+
char *section_content = section_name ? extract_markdown_section(content, section_name) : NULL;
|
|
1801
|
+
char *base_text = section_content ? section_content : strdup(content);
|
|
1802
|
+
char *plugin_base_text = run_preparse_plugins_on_text(base_text ? base_text : content,
|
|
1803
|
+
plugin_manager,
|
|
1804
|
+
options);
|
|
1805
|
+
const char *content_for_processing = plugin_base_text ? plugin_base_text : (base_text ? base_text : content);
|
|
1806
|
+
|
|
1367
1807
|
/* Extract metadata from transcluded file */
|
|
1368
|
-
char *file_content_for_metadata = strdup(
|
|
1808
|
+
char *file_content_for_metadata = strdup(content_for_processing);
|
|
1369
1809
|
apex_metadata_item *file_metadata = NULL;
|
|
1370
1810
|
char *file_text_after_metadata = file_content_for_metadata;
|
|
1371
1811
|
if (file_content_for_metadata) {
|
|
@@ -1381,12 +1821,20 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1381
1821
|
transclude_base = get_directory(resolved_path);
|
|
1382
1822
|
}
|
|
1383
1823
|
|
|
1384
|
-
to_insert = apex_process_includes(
|
|
1824
|
+
to_insert = apex_process_includes(content_for_processing,
|
|
1825
|
+
transclude_base,
|
|
1826
|
+
file_metadata,
|
|
1827
|
+
depth + 1,
|
|
1828
|
+
default_extension,
|
|
1829
|
+
plugin_manager,
|
|
1830
|
+
options);
|
|
1385
1831
|
|
|
1386
1832
|
/* Cleanup */
|
|
1387
1833
|
if (transclude_base) free(transclude_base);
|
|
1388
1834
|
if (file_metadata) apex_free_metadata(file_metadata);
|
|
1389
1835
|
if (file_content_for_metadata) free(file_content_for_metadata);
|
|
1836
|
+
if (plugin_base_text) free(plugin_base_text);
|
|
1837
|
+
if (base_text) free(base_text);
|
|
1390
1838
|
}
|
|
1391
1839
|
|
|
1392
1840
|
if (to_insert) {
|
|
@@ -1401,13 +1849,16 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1401
1849
|
|
|
1402
1850
|
free(content);
|
|
1403
1851
|
free(resolved_path);
|
|
1404
|
-
read_pos =
|
|
1852
|
+
read_pos = line_end;
|
|
1405
1853
|
processed_include = true;
|
|
1854
|
+
if (section_name) free(section_name);
|
|
1406
1855
|
} else {
|
|
1407
1856
|
free(resolved_path);
|
|
1857
|
+
if (section_name) free(section_name);
|
|
1408
1858
|
}
|
|
1409
1859
|
} else if (resolved_path) {
|
|
1410
1860
|
free(resolved_path);
|
|
1861
|
+
if (section_name) free(section_name);
|
|
1411
1862
|
}
|
|
1412
1863
|
}
|
|
1413
1864
|
}
|
|
@@ -1427,6 +1878,9 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1427
1878
|
percent_decode_inplace(filepath);
|
|
1428
1879
|
parse_embedded_delimiter_override(filepath, &mmd_delimiter_override);
|
|
1429
1880
|
|
|
1881
|
+
char *section_name = NULL;
|
|
1882
|
+
split_section_fragment(filepath, §ion_name);
|
|
1883
|
+
|
|
1430
1884
|
/* Check for address specification [address] */
|
|
1431
1885
|
const char *address_start = filepath_end + 2;
|
|
1432
1886
|
const char *address_end = NULL;
|
|
@@ -1457,8 +1911,11 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1457
1911
|
apex_file_type_t file_type = apex_detect_file_type(resolved_path);
|
|
1458
1912
|
char *content = read_file_contents(resolved_path);
|
|
1459
1913
|
if (content) {
|
|
1914
|
+
char *section_content = section_name ? extract_markdown_section(content, section_name) : NULL;
|
|
1915
|
+
char *section_base = section_content ? section_content : strdup(content);
|
|
1916
|
+
|
|
1460
1917
|
/* Extract metadata from original file content FIRST (before any processing) */
|
|
1461
|
-
char *file_content_for_metadata = strdup(
|
|
1918
|
+
char *file_content_for_metadata = section_base ? strdup(section_base) : NULL;
|
|
1462
1919
|
apex_metadata_item *file_metadata = NULL;
|
|
1463
1920
|
char *file_text_after_metadata = file_content_for_metadata;
|
|
1464
1921
|
if (file_content_for_metadata) {
|
|
@@ -1466,12 +1923,12 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1466
1923
|
}
|
|
1467
1924
|
|
|
1468
1925
|
/* Apply address specification if present */
|
|
1469
|
-
char *extracted_content = content;
|
|
1926
|
+
char *extracted_content = section_base ? section_base : content;
|
|
1470
1927
|
bool free_extracted = false;
|
|
1471
1928
|
|
|
1472
1929
|
if (address_spec) {
|
|
1473
|
-
extracted_content = extract_lines(content, address_spec);
|
|
1474
|
-
if (extracted_content && extracted_content != content) {
|
|
1930
|
+
extracted_content = extract_lines(section_base ? section_base : content, address_spec);
|
|
1931
|
+
if (extracted_content && extracted_content != (section_base ? section_base : content)) {
|
|
1475
1932
|
free_extracted = true;
|
|
1476
1933
|
}
|
|
1477
1934
|
}
|
|
@@ -1492,6 +1949,15 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1492
1949
|
}
|
|
1493
1950
|
}
|
|
1494
1951
|
|
|
1952
|
+
if (file_type == FILE_TYPE_MARKDOWN || file_type == FILE_TYPE_TEXT) {
|
|
1953
|
+
char *plugin_text = run_preparse_plugins_on_text(to_process, plugin_manager, options);
|
|
1954
|
+
if (plugin_text) {
|
|
1955
|
+
if (free_to_process) free(to_process);
|
|
1956
|
+
to_process = plugin_text;
|
|
1957
|
+
free_to_process = true;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1495
1961
|
/* Get transclude base from file's metadata, or use file's directory */
|
|
1496
1962
|
char *transclude_base = NULL;
|
|
1497
1963
|
if (file_metadata) {
|
|
@@ -1502,7 +1968,13 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1502
1968
|
}
|
|
1503
1969
|
|
|
1504
1970
|
/* Recursively process with file's metadata and transclude base */
|
|
1505
|
-
char *processed = apex_process_includes(to_process,
|
|
1971
|
+
char *processed = apex_process_includes(to_process,
|
|
1972
|
+
transclude_base,
|
|
1973
|
+
file_metadata,
|
|
1974
|
+
depth + 1,
|
|
1975
|
+
default_extension,
|
|
1976
|
+
plugin_manager,
|
|
1977
|
+
options);
|
|
1506
1978
|
|
|
1507
1979
|
/* Cleanup */
|
|
1508
1980
|
if (transclude_base) free(transclude_base);
|
|
@@ -1522,6 +1994,7 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1522
1994
|
if (free_to_process) free(to_process);
|
|
1523
1995
|
if (free_extracted) free(extracted_content);
|
|
1524
1996
|
free(content);
|
|
1997
|
+
if (section_base) free(section_base);
|
|
1525
1998
|
|
|
1526
1999
|
if (address_end) {
|
|
1527
2000
|
read_pos = address_end + 1;
|
|
@@ -1531,12 +2004,15 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1531
2004
|
free(resolved_path);
|
|
1532
2005
|
if (address_spec) free_address_spec(address_spec);
|
|
1533
2006
|
processed_include = true;
|
|
2007
|
+
if (section_name) free(section_name);
|
|
1534
2008
|
} else {
|
|
1535
2009
|
free(resolved_path);
|
|
1536
2010
|
if (address_spec) free_address_spec(address_spec);
|
|
2011
|
+
if (section_name) free(section_name);
|
|
1537
2012
|
}
|
|
1538
2013
|
} else {
|
|
1539
2014
|
if (address_spec) free_address_spec(address_spec);
|
|
2015
|
+
if (section_name) free(section_name);
|
|
1540
2016
|
}
|
|
1541
2017
|
}
|
|
1542
2018
|
}
|
|
@@ -1580,10 +2056,14 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1580
2056
|
parse_embedded_delimiter_override(filepath, &marked_delimiter_override);
|
|
1581
2057
|
}
|
|
1582
2058
|
|
|
1583
|
-
|
|
2059
|
+
char *section_name = NULL;
|
|
2060
|
+
split_section_fragment(filepath, §ion_name);
|
|
2061
|
+
|
|
2062
|
+
/* Check for address specification [address] on the SAME line only.
|
|
2063
|
+
* Do not skip across newlines, otherwise following reference
|
|
2064
|
+
* definitions like "[^1]: ..." are misparsed as include addresses. */
|
|
1584
2065
|
const char *address_start = filepath_end + 1;
|
|
1585
|
-
|
|
1586
|
-
while (*address_start && isspace(*address_start)) address_start++;
|
|
2066
|
+
while (*address_start == ' ' || *address_start == '\t') address_start++;
|
|
1587
2067
|
const char *address_end = NULL;
|
|
1588
2068
|
address_spec_t *address_spec = NULL;
|
|
1589
2069
|
|
|
@@ -1607,8 +2087,11 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1607
2087
|
apex_file_type_t file_type = apex_detect_file_type(resolved_path);
|
|
1608
2088
|
char *content = read_file_contents(resolved_path);
|
|
1609
2089
|
if (content) {
|
|
2090
|
+
char *section_content = section_name ? extract_markdown_section(content, section_name) : NULL;
|
|
2091
|
+
char *section_base = section_content ? section_content : strdup(content);
|
|
2092
|
+
|
|
1610
2093
|
/* Extract metadata from original file content FIRST (before any processing) */
|
|
1611
|
-
char *file_content_for_metadata = strdup(
|
|
2094
|
+
char *file_content_for_metadata = section_base ? strdup(section_base) : NULL;
|
|
1612
2095
|
apex_metadata_item *file_metadata = NULL;
|
|
1613
2096
|
char *file_text_after_metadata = file_content_for_metadata;
|
|
1614
2097
|
if (file_content_for_metadata) {
|
|
@@ -1616,12 +2099,12 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1616
2099
|
}
|
|
1617
2100
|
|
|
1618
2101
|
/* Apply address specification if present */
|
|
1619
|
-
char *extracted_content = content;
|
|
2102
|
+
char *extracted_content = section_base ? section_base : content;
|
|
1620
2103
|
bool free_extracted = false;
|
|
1621
2104
|
|
|
1622
2105
|
if (address_spec) {
|
|
1623
|
-
extracted_content = extract_lines(content, address_spec);
|
|
1624
|
-
if (extracted_content && extracted_content != content) {
|
|
2106
|
+
extracted_content = extract_lines(section_base ? section_base : content, address_spec);
|
|
2107
|
+
if (extracted_content && extracted_content != (section_base ? section_base : content)) {
|
|
1625
2108
|
free_extracted = true;
|
|
1626
2109
|
}
|
|
1627
2110
|
}
|
|
@@ -1643,6 +2126,14 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1643
2126
|
free_to_process = true;
|
|
1644
2127
|
}
|
|
1645
2128
|
}
|
|
2129
|
+
if (file_type == FILE_TYPE_MARKDOWN || file_type == FILE_TYPE_TEXT) {
|
|
2130
|
+
char *plugin_text = run_preparse_plugins_on_text(to_process, plugin_manager, options);
|
|
2131
|
+
if (plugin_text) {
|
|
2132
|
+
if (free_to_process) free(to_process);
|
|
2133
|
+
to_process = plugin_text;
|
|
2134
|
+
free_to_process = true;
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
1646
2137
|
|
|
1647
2138
|
/* Markdown include - recursively process */
|
|
1648
2139
|
|
|
@@ -1655,7 +2146,13 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1655
2146
|
transclude_base = get_directory(resolved_path);
|
|
1656
2147
|
}
|
|
1657
2148
|
|
|
1658
|
-
char *processed = apex_process_includes(to_process,
|
|
2149
|
+
char *processed = apex_process_includes(to_process,
|
|
2150
|
+
transclude_base,
|
|
2151
|
+
file_metadata,
|
|
2152
|
+
depth + 1,
|
|
2153
|
+
default_extension,
|
|
2154
|
+
plugin_manager,
|
|
2155
|
+
options);
|
|
1659
2156
|
|
|
1660
2157
|
/* Cleanup */
|
|
1661
2158
|
if (transclude_base) free(transclude_base);
|
|
@@ -1718,6 +2215,7 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1718
2215
|
|
|
1719
2216
|
if (free_extracted) free(extracted_content);
|
|
1720
2217
|
free(content);
|
|
2218
|
+
if (section_base) free(section_base);
|
|
1721
2219
|
}
|
|
1722
2220
|
free(resolved_path);
|
|
1723
2221
|
}
|
|
@@ -1741,6 +2239,7 @@ char *apex_process_includes(const char *text, const char *base_dir, apex_metadat
|
|
|
1741
2239
|
}
|
|
1742
2240
|
}
|
|
1743
2241
|
if (address_spec) free_address_spec(address_spec);
|
|
2242
|
+
if (section_name) free(section_name);
|
|
1744
2243
|
processed_include = true;
|
|
1745
2244
|
}
|
|
1746
2245
|
}
|