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
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
#include "ial.h"
|
|
6
|
+
#include "bear_image_attrs.h"
|
|
6
7
|
#include "table.h" /* For CMARK_NODE_TABLE */
|
|
7
8
|
#include "apex/apex.h" /* For apex_mode_t */
|
|
8
9
|
#include <string.h>
|
|
@@ -348,9 +349,13 @@ ald_entry *apex_extract_alds(char **text_ptr) {
|
|
|
348
349
|
while ((line_end = strchr(line_start, '\n')) != NULL || *line_start) {
|
|
349
350
|
if (!line_end) line_end = line_start + strlen(line_start);
|
|
350
351
|
|
|
351
|
-
size_t line_len = line_end - line_start;
|
|
352
|
-
char line
|
|
353
|
-
if (
|
|
352
|
+
size_t line_len = (size_t)(line_end - line_start);
|
|
353
|
+
char *line = malloc(line_len + 1);
|
|
354
|
+
if (!line) {
|
|
355
|
+
apex_free_alds(alds);
|
|
356
|
+
free(output);
|
|
357
|
+
return NULL;
|
|
358
|
+
}
|
|
354
359
|
memcpy(line, line_start, line_len);
|
|
355
360
|
line[line_len] = '\0';
|
|
356
361
|
|
|
@@ -371,6 +376,7 @@ ald_entry *apex_extract_alds(char **text_ptr) {
|
|
|
371
376
|
}
|
|
372
377
|
|
|
373
378
|
/* Skip this line in output */
|
|
379
|
+
free(line);
|
|
374
380
|
line_start = *line_end ? line_end + 1 : line_end;
|
|
375
381
|
continue;
|
|
376
382
|
}
|
|
@@ -378,6 +384,7 @@ ald_entry *apex_extract_alds(char **text_ptr) {
|
|
|
378
384
|
/* Not an ALD, copy line to output */
|
|
379
385
|
memcpy(output_write, line_start, line_len);
|
|
380
386
|
output_write += line_len;
|
|
387
|
+
free(line);
|
|
381
388
|
if (*line_end) {
|
|
382
389
|
*output_write++ = '\n';
|
|
383
390
|
line_start = line_end + 1;
|
|
@@ -477,6 +484,128 @@ static apex_attributes *merge_attributes(apex_attributes *base, apex_attributes
|
|
|
477
484
|
return merged;
|
|
478
485
|
}
|
|
479
486
|
|
|
487
|
+
static apex_attributes *copy_attributes(const apex_attributes *source) {
|
|
488
|
+
apex_attributes *copy = create_attributes();
|
|
489
|
+
if (!copy) return NULL;
|
|
490
|
+
|
|
491
|
+
if (source) {
|
|
492
|
+
if (source->id) copy->id = strdup(source->id);
|
|
493
|
+
for (int i = 0; i < source->class_count; i++) {
|
|
494
|
+
add_class(copy, source->classes[i]);
|
|
495
|
+
}
|
|
496
|
+
for (int i = 0; i < source->attr_count; i++) {
|
|
497
|
+
add_attribute(copy, source->keys[i], source->values[i]);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return copy;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
static char *escape_bear_attribute_value(const char *value) {
|
|
505
|
+
size_t length = 0;
|
|
506
|
+
for (const char *p = value; *p; p++) {
|
|
507
|
+
switch (*p) {
|
|
508
|
+
case '&':
|
|
509
|
+
length += strlen("&");
|
|
510
|
+
break;
|
|
511
|
+
case '"':
|
|
512
|
+
length += strlen(""");
|
|
513
|
+
break;
|
|
514
|
+
case '<':
|
|
515
|
+
length += strlen("<");
|
|
516
|
+
break;
|
|
517
|
+
case '>':
|
|
518
|
+
length += strlen(">");
|
|
519
|
+
break;
|
|
520
|
+
default:
|
|
521
|
+
length++;
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
char *escaped = malloc(length + 1);
|
|
527
|
+
if (!escaped) return NULL;
|
|
528
|
+
|
|
529
|
+
char *write = escaped;
|
|
530
|
+
for (const char *p = value; *p; p++) {
|
|
531
|
+
const char *replacement = NULL;
|
|
532
|
+
switch (*p) {
|
|
533
|
+
case '&':
|
|
534
|
+
replacement = "&";
|
|
535
|
+
break;
|
|
536
|
+
case '"':
|
|
537
|
+
replacement = """;
|
|
538
|
+
break;
|
|
539
|
+
case '<':
|
|
540
|
+
replacement = "<";
|
|
541
|
+
break;
|
|
542
|
+
case '>':
|
|
543
|
+
replacement = ">";
|
|
544
|
+
break;
|
|
545
|
+
default:
|
|
546
|
+
*write++ = *p;
|
|
547
|
+
break;
|
|
548
|
+
}
|
|
549
|
+
if (replacement) {
|
|
550
|
+
size_t replacement_length = strlen(replacement);
|
|
551
|
+
memcpy(write, replacement, replacement_length);
|
|
552
|
+
write += replacement_length;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
*write = '\0';
|
|
556
|
+
return escaped;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
static apex_attributes *attributes_from_bear(
|
|
560
|
+
const apex_bear_image_attrs *bear) {
|
|
561
|
+
apex_attributes *attrs = create_attributes();
|
|
562
|
+
if (!attrs) return NULL;
|
|
563
|
+
|
|
564
|
+
for (size_t i = 0; i < bear->count; i++) {
|
|
565
|
+
/*
|
|
566
|
+
* Width/height classification is unchanged by escaping: all encoded
|
|
567
|
+
* characters are non-numeric in the decoded value as well.
|
|
568
|
+
*/
|
|
569
|
+
char *escaped = escape_bear_attribute_value(bear->items[i].value);
|
|
570
|
+
if (escaped) {
|
|
571
|
+
add_attribute(attrs, bear->items[i].key, escaped);
|
|
572
|
+
free(escaped);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return attrs;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
static apex_attributes *parse_adjacent_bear_attrs(
|
|
579
|
+
const char *after_construct,
|
|
580
|
+
const char *line_end,
|
|
581
|
+
const char **comment_start,
|
|
582
|
+
const char **comment_end) {
|
|
583
|
+
*comment_start = NULL;
|
|
584
|
+
*comment_end = NULL;
|
|
585
|
+
|
|
586
|
+
const char *candidate = after_construct;
|
|
587
|
+
while (candidate < line_end &&
|
|
588
|
+
(*candidate == ' ' || *candidate == '\t')) {
|
|
589
|
+
candidate++;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
apex_bear_image_attrs bear = {0};
|
|
593
|
+
if (!apex_parse_bear_image_comment(
|
|
594
|
+
candidate, line_end, comment_end, &bear)) {
|
|
595
|
+
return NULL;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
apex_attributes *attrs = attributes_from_bear(&bear);
|
|
599
|
+
apex_free_bear_image_attrs(&bear);
|
|
600
|
+
if (!attrs) {
|
|
601
|
+
*comment_end = NULL;
|
|
602
|
+
return NULL;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
*comment_start = candidate;
|
|
606
|
+
return attrs;
|
|
607
|
+
}
|
|
608
|
+
|
|
480
609
|
/**
|
|
481
610
|
* Check if text ends with IAL pattern
|
|
482
611
|
* Pattern: {: attributes} or {:.class} or {: ref-name} or {: ref-name .class #id}
|
|
@@ -1571,6 +1700,45 @@ static bool is_ial_line(const char *line, size_t len) {
|
|
|
1571
1700
|
return (after >= end);
|
|
1572
1701
|
}
|
|
1573
1702
|
|
|
1703
|
+
/** True if content at p looks like a list marker (- , * , + , or digit+. ) */
|
|
1704
|
+
static int ial_looks_like_list_marker(const char *p) {
|
|
1705
|
+
if (!*p) return 0;
|
|
1706
|
+
if (*p == '-' || *p == '*' || *p == '+')
|
|
1707
|
+
return (p[1] == ' ' || p[1] == '\t');
|
|
1708
|
+
if (isdigit((unsigned char)*p)) {
|
|
1709
|
+
while (isdigit((unsigned char)*p)) p++;
|
|
1710
|
+
return (*p == '.' && (p[1] == ' ' || p[1] == '\t'));
|
|
1711
|
+
}
|
|
1712
|
+
return 0;
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
/** True if line is an indented code block (4+ spaces or tab at start). */
|
|
1716
|
+
static bool ial_line_is_indented_code_block(const char *line, size_t len) {
|
|
1717
|
+
if (len == 0) return false;
|
|
1718
|
+
if (line[0] == '\t')
|
|
1719
|
+
return !ial_looks_like_list_marker(line + 1);
|
|
1720
|
+
if (len < 4 || line[0] != ' ' || line[1] != ' ' || line[2] != ' ' || line[3] != ' ')
|
|
1721
|
+
return false;
|
|
1722
|
+
const char *content = line + 4;
|
|
1723
|
+
while (content < line + len && *content == ' ') content++;
|
|
1724
|
+
return content < line + len && !ial_looks_like_list_marker(content);
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
/** True if line is a fenced code fence (``` or ~~~) with up to 3 leading spaces. */
|
|
1728
|
+
static bool ial_line_is_fence(const char *line, size_t len) {
|
|
1729
|
+
const char *p = line;
|
|
1730
|
+
const char *end = line + len;
|
|
1731
|
+
int spaces = 0;
|
|
1732
|
+
while (p < end && *p == ' ' && spaces < 3) {
|
|
1733
|
+
p++;
|
|
1734
|
+
spaces++;
|
|
1735
|
+
}
|
|
1736
|
+
if (p + 2 >= end) return false;
|
|
1737
|
+
if (p[0] == '`' && p[1] == '`' && p[2] == '`') return true;
|
|
1738
|
+
if (p[0] == '~' && p[1] == '~' && p[2] == '~') return true;
|
|
1739
|
+
return false;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1574
1742
|
/**
|
|
1575
1743
|
* Preprocess text to separate IAL markers from preceding content.
|
|
1576
1744
|
* Kramdown allows IAL on the line immediately following content,
|
|
@@ -1590,6 +1758,8 @@ char *apex_preprocess_ial(const char *text) {
|
|
|
1590
1758
|
const char *p = text;
|
|
1591
1759
|
bool prev_line_was_content = false;
|
|
1592
1760
|
bool prev_line_was_blank = true; /* Start as if there was a blank line before */
|
|
1761
|
+
bool in_fenced_code = false;
|
|
1762
|
+
bool in_indented_code = false;
|
|
1593
1763
|
|
|
1594
1764
|
while (*p) {
|
|
1595
1765
|
/* Find end of current line */
|
|
@@ -1613,6 +1783,18 @@ char *apex_preprocess_ial(const char *text) {
|
|
|
1613
1783
|
/* Check if this line is an IAL */
|
|
1614
1784
|
bool is_ial = is_ial_line(line_start, line_len);
|
|
1615
1785
|
|
|
1786
|
+
if (ial_line_is_fence(line_start, line_len)) {
|
|
1787
|
+
in_fenced_code = !in_fenced_code;
|
|
1788
|
+
}
|
|
1789
|
+
if (!in_fenced_code) {
|
|
1790
|
+
if (ial_line_is_indented_code_block(line_start, line_len)) {
|
|
1791
|
+
in_indented_code = true;
|
|
1792
|
+
} else if (!is_blank) {
|
|
1793
|
+
in_indented_code = false;
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
bool in_code = in_fenced_code || in_indented_code;
|
|
1797
|
+
|
|
1616
1798
|
/* Special case: Kramdown-style TOC marker "{:toc ...}".
|
|
1617
1799
|
*
|
|
1618
1800
|
* In Kramdown/Jekyll, a pure IAL paragraph containing only "{:toc}"
|
|
@@ -1622,7 +1804,7 @@ char *apex_preprocess_ial(const char *text) {
|
|
|
1622
1804
|
* TOC extension.
|
|
1623
1805
|
*/
|
|
1624
1806
|
bool handled_toc_marker = false;
|
|
1625
|
-
if (is_ial) {
|
|
1807
|
+
if (is_ial && !in_code) {
|
|
1626
1808
|
const char *q = line_start;
|
|
1627
1809
|
const char *end = line_start + line_len;
|
|
1628
1810
|
|
|
@@ -2495,12 +2677,17 @@ static char *attributes_to_markdown(apex_attributes *attrs) {
|
|
|
2495
2677
|
return attributes_to_inline_format(attrs);
|
|
2496
2678
|
}
|
|
2497
2679
|
|
|
2680
|
+
static bool reference_id_matches(
|
|
2681
|
+
const char *ref_id, const char *text, size_t text_len);
|
|
2682
|
+
|
|
2498
2683
|
/**
|
|
2499
2684
|
* Find image attribute entry by reference name
|
|
2500
2685
|
*/
|
|
2501
2686
|
static image_attr_entry *find_image_attr_by_ref(image_attr_entry *list, const char *ref_name) {
|
|
2502
2687
|
for (image_attr_entry *entry = list; entry; entry = entry->next) {
|
|
2503
|
-
if (entry->ref_name && ref_name &&
|
|
2688
|
+
if (entry->ref_name && ref_name &&
|
|
2689
|
+
reference_id_matches(
|
|
2690
|
+
entry->ref_name, ref_name, strlen(ref_name))) {
|
|
2504
2691
|
return entry;
|
|
2505
2692
|
}
|
|
2506
2693
|
}
|
|
@@ -2607,17 +2794,15 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
2607
2794
|
}
|
|
2608
2795
|
|
|
2609
2796
|
/* Check if we should do URL encoding */
|
|
2610
|
-
bool do_url_encoding = (mode
|
|
2797
|
+
bool do_url_encoding = apex_mode_is_unified_family(mode) ||
|
|
2611
2798
|
mode == APEX_MODE_MULTIMARKDOWN ||
|
|
2612
|
-
mode == APEX_MODE_KRAMDOWN
|
|
2799
|
+
mode == APEX_MODE_KRAMDOWN;
|
|
2613
2800
|
|
|
2614
|
-
/* Check if we should process image attributes.
|
|
2615
|
-
|
|
2616
|
-
* and @2x markers on images and reference definitions are honored consistently.
|
|
2617
|
-
*/
|
|
2618
|
-
bool do_image_attrs = (mode == APEX_MODE_UNIFIED ||
|
|
2801
|
+
/* Check if we should process image attributes. */
|
|
2802
|
+
bool do_image_attrs = apex_mode_is_unified_family(mode) ||
|
|
2619
2803
|
mode == APEX_MODE_MULTIMARKDOWN ||
|
|
2620
|
-
mode == APEX_MODE_GFM
|
|
2804
|
+
mode == APEX_MODE_GFM ||
|
|
2805
|
+
mode == APEX_MODE_COMMONMARK;
|
|
2621
2806
|
|
|
2622
2807
|
if (!do_url_encoding && !do_image_attrs) {
|
|
2623
2808
|
/* Nothing to do */
|
|
@@ -2862,6 +3047,43 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
2862
3047
|
}
|
|
2863
3048
|
}
|
|
2864
3049
|
|
|
3050
|
+
/*
|
|
3051
|
+
* Bear stores image metadata in an adjacent HTML
|
|
3052
|
+
* comment. Parse and merge it, but leave the source
|
|
3053
|
+
* bytes untouched so cmark preserves the comment.
|
|
3054
|
+
* Gated on do_image_attrs so modes that only enter
|
|
3055
|
+
* the preprocessor for URL encoding (Kramdown) do
|
|
3056
|
+
* not pick up Bear attributes.
|
|
3057
|
+
*/
|
|
3058
|
+
if (do_image_attrs) {
|
|
3059
|
+
const char *after_attributes =
|
|
3060
|
+
ial_end_pos ? ial_end_pos + 1 : after_paren;
|
|
3061
|
+
const char *line_end = after_attributes;
|
|
3062
|
+
while (*line_end &&
|
|
3063
|
+
*line_end != '\n' && *line_end != '\r') {
|
|
3064
|
+
line_end++;
|
|
3065
|
+
}
|
|
3066
|
+
const char *bear_comment_start = NULL;
|
|
3067
|
+
const char *bear_comment_end = NULL;
|
|
3068
|
+
apex_attributes *bear_attrs =
|
|
3069
|
+
parse_adjacent_bear_attrs(
|
|
3070
|
+
after_attributes,
|
|
3071
|
+
line_end,
|
|
3072
|
+
&bear_comment_start,
|
|
3073
|
+
&bear_comment_end);
|
|
3074
|
+
if (bear_attrs) {
|
|
3075
|
+
if (attrs) {
|
|
3076
|
+
apex_attributes *merged =
|
|
3077
|
+
merge_attributes(attrs, bear_attrs);
|
|
3078
|
+
apex_free_attributes(attrs);
|
|
3079
|
+
apex_free_attributes(bear_attrs);
|
|
3080
|
+
attrs = merged;
|
|
3081
|
+
} else {
|
|
3082
|
+
attrs = bear_attrs;
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
|
|
2865
3087
|
/* URL ending in .* means auto-discover formats (same as auto attribute) */
|
|
2866
3088
|
bool url_is_wildcard = (url_len >= 2 && url[url_len - 2] == '.' && url[url_len - 1] == '*');
|
|
2867
3089
|
if (url_is_wildcard && do_image_attrs) {
|
|
@@ -3038,6 +3260,38 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3038
3260
|
/* Find the end of the line first */
|
|
3039
3261
|
const char *line_end = p;
|
|
3040
3262
|
while (*line_end && *line_end != '\n' && *line_end != '\r') line_end++;
|
|
3263
|
+
const char *physical_line_end = line_end;
|
|
3264
|
+
const char *bear_comment_start = NULL;
|
|
3265
|
+
const char *bear_comment_end = NULL;
|
|
3266
|
+
const char *bear_output_start = NULL;
|
|
3267
|
+
apex_attributes *bear_attrs = NULL;
|
|
3268
|
+
|
|
3269
|
+
/* Pre-scan for a candidate Bear comment so title/attribute
|
|
3270
|
+
* parsing below does not consume it. Adjacency to the true
|
|
3271
|
+
* end of the definition is verified after that parsing.
|
|
3272
|
+
*/
|
|
3273
|
+
if (do_image_attrs) {
|
|
3274
|
+
const char *bear_candidate = strstr(url_start, "<!--");
|
|
3275
|
+
while (bear_candidate &&
|
|
3276
|
+
bear_candidate < physical_line_end) {
|
|
3277
|
+
bear_attrs = parse_adjacent_bear_attrs(
|
|
3278
|
+
bear_candidate,
|
|
3279
|
+
physical_line_end,
|
|
3280
|
+
&bear_comment_start,
|
|
3281
|
+
&bear_comment_end);
|
|
3282
|
+
if (bear_attrs) break;
|
|
3283
|
+
bear_candidate = strstr(bear_candidate + 1, "<!--");
|
|
3284
|
+
}
|
|
3285
|
+
if (bear_attrs) {
|
|
3286
|
+
bear_output_start = bear_comment_start;
|
|
3287
|
+
while (bear_output_start > url_start &&
|
|
3288
|
+
(bear_output_start[-1] == ' ' ||
|
|
3289
|
+
bear_output_start[-1] == '\t')) {
|
|
3290
|
+
bear_output_start--;
|
|
3291
|
+
}
|
|
3292
|
+
line_end = bear_output_start;
|
|
3293
|
+
}
|
|
3294
|
+
}
|
|
3041
3295
|
|
|
3042
3296
|
/* For reference definitions, we need to check for:
|
|
3043
3297
|
* 1. Image attributes (if do_image_attrs): key=value pattern
|
|
@@ -3309,6 +3563,63 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3309
3563
|
}
|
|
3310
3564
|
}
|
|
3311
3565
|
|
|
3566
|
+
if (bear_attrs) {
|
|
3567
|
+
/* Enforce adjacency: re-scan from the true end of
|
|
3568
|
+
* the URL, title, IAL, or MMD attributes so only
|
|
3569
|
+
* spaces or tabs may precede the Bear comment.
|
|
3570
|
+
* The URL itself ends at its first whitespace,
|
|
3571
|
+
* matching cmark link destinations.
|
|
3572
|
+
*/
|
|
3573
|
+
const char *after_construct;
|
|
3574
|
+
if (title_end) {
|
|
3575
|
+
after_construct = title_end;
|
|
3576
|
+
} else {
|
|
3577
|
+
after_construct = url_start;
|
|
3578
|
+
while (after_construct < url_end &&
|
|
3579
|
+
*after_construct != ' ' &&
|
|
3580
|
+
*after_construct != '\t') {
|
|
3581
|
+
after_construct++;
|
|
3582
|
+
}
|
|
3583
|
+
}
|
|
3584
|
+
const char *adjacent_start = NULL;
|
|
3585
|
+
const char *adjacent_end = NULL;
|
|
3586
|
+
apex_attributes *adjacent_attrs =
|
|
3587
|
+
parse_adjacent_bear_attrs(
|
|
3588
|
+
after_construct,
|
|
3589
|
+
physical_line_end,
|
|
3590
|
+
&adjacent_start,
|
|
3591
|
+
&adjacent_end);
|
|
3592
|
+
apex_free_attributes(bear_attrs);
|
|
3593
|
+
bear_attrs = adjacent_attrs;
|
|
3594
|
+
if (bear_attrs) {
|
|
3595
|
+
bear_comment_start = adjacent_start;
|
|
3596
|
+
bear_comment_end = adjacent_end;
|
|
3597
|
+
bear_output_start = adjacent_start;
|
|
3598
|
+
while (bear_output_start > after_construct &&
|
|
3599
|
+
(bear_output_start[-1] == ' ' ||
|
|
3600
|
+
bear_output_start[-1] == '\t')) {
|
|
3601
|
+
bear_output_start--;
|
|
3602
|
+
}
|
|
3603
|
+
} else {
|
|
3604
|
+
bear_comment_start = NULL;
|
|
3605
|
+
bear_comment_end = NULL;
|
|
3606
|
+
bear_output_start = NULL;
|
|
3607
|
+
}
|
|
3608
|
+
}
|
|
3609
|
+
|
|
3610
|
+
if (bear_attrs) {
|
|
3611
|
+
if (attrs) {
|
|
3612
|
+
apex_attributes *merged =
|
|
3613
|
+
merge_attributes(attrs, bear_attrs);
|
|
3614
|
+
apex_free_attributes(attrs);
|
|
3615
|
+
apex_free_attributes(bear_attrs);
|
|
3616
|
+
attrs = merged;
|
|
3617
|
+
} else {
|
|
3618
|
+
attrs = bear_attrs;
|
|
3619
|
+
}
|
|
3620
|
+
bear_attrs = NULL;
|
|
3621
|
+
}
|
|
3622
|
+
|
|
3312
3623
|
/* Extract reference name */
|
|
3313
3624
|
size_t ref_name_len = ref_end - ref_start - 1; /* Exclude [ and ] */
|
|
3314
3625
|
char *ref_name = malloc(ref_name_len + 1);
|
|
@@ -3343,8 +3654,8 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3343
3654
|
*/
|
|
3344
3655
|
if (is_footnote_ref) {
|
|
3345
3656
|
/* Write the entire definition line unchanged */
|
|
3346
|
-
size_t line_len =
|
|
3347
|
-
if (*
|
|
3657
|
+
size_t line_len = physical_line_end - ref_start;
|
|
3658
|
+
if (*physical_line_end == '\n') {
|
|
3348
3659
|
line_len++; /* Include newline */
|
|
3349
3660
|
}
|
|
3350
3661
|
|
|
@@ -3370,7 +3681,7 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3370
3681
|
remaining -= line_len;
|
|
3371
3682
|
|
|
3372
3683
|
/* Advance read past this line (including newline if present) */
|
|
3373
|
-
const char *next =
|
|
3684
|
+
const char *next = physical_line_end;
|
|
3374
3685
|
if (*next == '\n') {
|
|
3375
3686
|
next++;
|
|
3376
3687
|
} else if (*next == '\r') {
|
|
@@ -3393,11 +3704,13 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3393
3704
|
bool skip_encode_ref = has_protocol(url);
|
|
3394
3705
|
char *encoded_url = (do_url_encoding && !skip_encode_ref) ? url_encode(url) : strdup(url);
|
|
3395
3706
|
if (encoded_url) {
|
|
3707
|
+
bool has_bear_attrs = (bear_comment_start != NULL);
|
|
3396
3708
|
bool has_image_attrs = (attrs != NULL && attrs_are_image_specific(attrs));
|
|
3397
3709
|
/* If has image-specific attributes (width, height, etc.), store with reference name.
|
|
3398
3710
|
* Don't create entry for link refs with only a title (e.g. [ref]: url "title"). */
|
|
3399
3711
|
if (ref_name) {
|
|
3400
|
-
if (
|
|
3712
|
+
if (has_bear_attrs || has_image_attrs ||
|
|
3713
|
+
(do_image_attrs && found_ial)) {
|
|
3401
3714
|
image_attr_entry *entry = create_image_attr_entry_with_ref(&local_img_attrs, encoded_url, ref_name);
|
|
3402
3715
|
if (entry) {
|
|
3403
3716
|
if (attrs) {
|
|
@@ -3412,8 +3725,11 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3412
3725
|
add_class(entry->attrs, attrs->classes[i]);
|
|
3413
3726
|
}
|
|
3414
3727
|
}
|
|
3415
|
-
/* Add title
|
|
3416
|
-
|
|
3728
|
+
/* Add the markdown title unless Bear
|
|
3729
|
+
* metadata already supplied one. */
|
|
3730
|
+
if (title_text &&
|
|
3731
|
+
find_attribute_index(
|
|
3732
|
+
entry->attrs, "title") < 0) {
|
|
3417
3733
|
add_attribute(entry->attrs, "title", title_text);
|
|
3418
3734
|
}
|
|
3419
3735
|
/* Entry created - will be used for expansion */
|
|
@@ -3421,22 +3737,72 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3421
3737
|
}
|
|
3422
3738
|
}
|
|
3423
3739
|
/* If this reference definition has image-specific attributes, remove it so we expand and apply attrs */
|
|
3424
|
-
bool created_entry =
|
|
3740
|
+
bool created_entry =
|
|
3741
|
+
(ref_name &&
|
|
3742
|
+
(has_bear_attrs || has_image_attrs ||
|
|
3743
|
+
(do_image_attrs && found_ial)));
|
|
3425
3744
|
bool should_remove = created_entry;
|
|
3426
3745
|
|
|
3427
3746
|
if (should_remove) {
|
|
3428
3747
|
/* Reference definitions with attributes are removed from output (like ALDs) */
|
|
3429
|
-
/*
|
|
3748
|
+
/* Preserve Bear metadata as one standalone raw HTML comment. */
|
|
3749
|
+
bool wrote_bear_comment = false;
|
|
3750
|
+
if (bear_output_start && bear_comment_end) {
|
|
3751
|
+
size_t comment_len =
|
|
3752
|
+
(size_t)(bear_comment_end - bear_output_start);
|
|
3753
|
+
if (comment_len + 2 > remaining) {
|
|
3754
|
+
size_t written = write - output;
|
|
3755
|
+
size_t new_capacity =
|
|
3756
|
+
(written + comment_len + 3) * 2;
|
|
3757
|
+
char *new_output =
|
|
3758
|
+
realloc(output, new_capacity);
|
|
3759
|
+
if (!new_output) {
|
|
3760
|
+
free(output);
|
|
3761
|
+
free(url);
|
|
3762
|
+
free(encoded_url);
|
|
3763
|
+
free(ref_name);
|
|
3764
|
+
if (title_text) free(title_text);
|
|
3765
|
+
if (attrs) apex_free_attributes(attrs);
|
|
3766
|
+
apex_free_image_attributes(local_img_attrs);
|
|
3767
|
+
return NULL;
|
|
3768
|
+
}
|
|
3769
|
+
output = new_output;
|
|
3770
|
+
write = output + written;
|
|
3771
|
+
remaining = new_capacity - written;
|
|
3772
|
+
}
|
|
3773
|
+
memcpy(write, bear_output_start, comment_len);
|
|
3774
|
+
write += comment_len;
|
|
3775
|
+
remaining -= comment_len;
|
|
3776
|
+
wrote_bear_comment = true;
|
|
3777
|
+
}
|
|
3430
3778
|
free(ref_name);
|
|
3431
3779
|
if (title_text) free(title_text);
|
|
3432
|
-
|
|
3433
|
-
|
|
3780
|
+
/* A preserved comment keeps the original line
|
|
3781
|
+
* ending so the next block stays separate.
|
|
3782
|
+
* Otherwise the whole line is removed.
|
|
3783
|
+
*/
|
|
3784
|
+
const char *p = physical_line_end;
|
|
3434
3785
|
if (*p == '\n') {
|
|
3786
|
+
if (wrote_bear_comment && remaining > 0) {
|
|
3787
|
+
*write++ = '\n';
|
|
3788
|
+
remaining--;
|
|
3789
|
+
}
|
|
3435
3790
|
p++;
|
|
3436
3791
|
} else if (*p == '\r') {
|
|
3437
3792
|
if (p[1] == '\n') {
|
|
3793
|
+
if (wrote_bear_comment &&
|
|
3794
|
+
remaining >= 2) {
|
|
3795
|
+
*write++ = '\r';
|
|
3796
|
+
*write++ = '\n';
|
|
3797
|
+
remaining -= 2;
|
|
3798
|
+
}
|
|
3438
3799
|
p += 2;
|
|
3439
3800
|
} else {
|
|
3801
|
+
if (wrote_bear_comment &&
|
|
3802
|
+
remaining > 0) {
|
|
3803
|
+
*write++ = '\r';
|
|
3804
|
+
remaining--;
|
|
3805
|
+
}
|
|
3440
3806
|
p++;
|
|
3441
3807
|
}
|
|
3442
3808
|
}
|
|
@@ -3505,7 +3871,10 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3505
3871
|
}
|
|
3506
3872
|
}
|
|
3507
3873
|
|
|
3508
|
-
/* Advance read past the
|
|
3874
|
+
/* Advance read past the processed portion so
|
|
3875
|
+
* any remaining line text (for example a
|
|
3876
|
+
* rejected comment) is copied by the main
|
|
3877
|
+
* loop. */
|
|
3509
3878
|
const char *p = title_end ? title_end : line_end;
|
|
3510
3879
|
|
|
3511
3880
|
/* Write newline */
|
|
@@ -3537,6 +3906,13 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3537
3906
|
continue;
|
|
3538
3907
|
}
|
|
3539
3908
|
}
|
|
3909
|
+
|
|
3910
|
+
/* URL extraction failed or was empty; release any pre-scanned
|
|
3911
|
+
* Bear attributes that were never merged. */
|
|
3912
|
+
if (bear_attrs) {
|
|
3913
|
+
apex_free_attributes(bear_attrs);
|
|
3914
|
+
bear_attrs = NULL;
|
|
3915
|
+
}
|
|
3540
3916
|
}
|
|
3541
3917
|
}
|
|
3542
3918
|
|
|
@@ -3735,27 +4111,40 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3735
4111
|
bool made_expansions = false;
|
|
3736
4112
|
|
|
3737
4113
|
while (*read2) {
|
|
3738
|
-
/* Look for reference
|
|
4114
|
+
/* Look for full, collapsed, and shortcut reference images. */
|
|
3739
4115
|
if (*read2 == '!' && read2[1] == '[') {
|
|
3740
4116
|
const char *img_start = read2;
|
|
3741
4117
|
read2 += 2; /* Skip ![ */
|
|
3742
4118
|
|
|
3743
4119
|
/* Find closing ] for alt text */
|
|
3744
4120
|
const char *alt_end = strchr(read2, ']');
|
|
3745
|
-
if (alt_end && alt_end[1]
|
|
3746
|
-
|
|
3747
|
-
const char *
|
|
3748
|
-
const char *
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
const char *
|
|
3752
|
-
|
|
3753
|
-
|
|
4121
|
+
if (alt_end && alt_end[1] != '(') {
|
|
4122
|
+
const char *ref_start = read2;
|
|
4123
|
+
const char *ref_end = alt_end;
|
|
4124
|
+
const char *image_end = alt_end;
|
|
4125
|
+
bool is_explicit_reference = false;
|
|
4126
|
+
if (alt_end[1] == '[') {
|
|
4127
|
+
const char *explicit_ref_start = alt_end + 2;
|
|
4128
|
+
const char *explicit_ref_end =
|
|
4129
|
+
strchr(explicit_ref_start, ']');
|
|
4130
|
+
if (!explicit_ref_end) {
|
|
4131
|
+
ref_end = NULL;
|
|
4132
|
+
} else if (explicit_ref_end > explicit_ref_start) {
|
|
4133
|
+
ref_start = explicit_ref_start;
|
|
4134
|
+
ref_end = explicit_ref_end;
|
|
4135
|
+
image_end = explicit_ref_end;
|
|
4136
|
+
is_explicit_reference = true;
|
|
4137
|
+
} else {
|
|
4138
|
+
image_end = explicit_ref_end;
|
|
3754
4139
|
}
|
|
3755
|
-
|
|
4140
|
+
}
|
|
4141
|
+
|
|
4142
|
+
if (ref_end) {
|
|
4143
|
+
size_t ref_name_len =
|
|
4144
|
+
(size_t)(ref_end - ref_start);
|
|
3756
4145
|
char *ref_name = malloc(ref_name_len + 1);
|
|
3757
4146
|
if (ref_name) {
|
|
3758
|
-
memcpy(ref_name,
|
|
4147
|
+
memcpy(ref_name, ref_start, ref_name_len);
|
|
3759
4148
|
ref_name[ref_name_len] = '\0';
|
|
3760
4149
|
/* Trim whitespace from reference name */
|
|
3761
4150
|
char *p = ref_name;
|
|
@@ -3769,9 +4158,53 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3769
4158
|
p--;
|
|
3770
4159
|
}
|
|
3771
4160
|
|
|
4161
|
+
apex_attributes *local_attrs = NULL;
|
|
4162
|
+
if (is_explicit_reference) {
|
|
4163
|
+
const char *after_use = image_end + 1;
|
|
4164
|
+
const char *line_end = after_use;
|
|
4165
|
+
while (*line_end && *line_end != '\n' &&
|
|
4166
|
+
*line_end != '\r') {
|
|
4167
|
+
line_end++;
|
|
4168
|
+
}
|
|
4169
|
+
const char *comment_start = NULL;
|
|
4170
|
+
const char *comment_end = NULL;
|
|
4171
|
+
local_attrs = parse_adjacent_bear_attrs(
|
|
4172
|
+
after_use,
|
|
4173
|
+
line_end,
|
|
4174
|
+
&comment_start,
|
|
4175
|
+
&comment_end);
|
|
4176
|
+
}
|
|
4177
|
+
|
|
3772
4178
|
/* Look up if this reference has attributes */
|
|
3773
|
-
image_attr_entry *def_entry =
|
|
4179
|
+
image_attr_entry *def_entry =
|
|
4180
|
+
find_image_attr_by_ref(
|
|
4181
|
+
local_img_attrs, ref_name);
|
|
3774
4182
|
if (def_entry && def_entry->url) {
|
|
4183
|
+
apex_attributes *effective_attrs =
|
|
4184
|
+
copy_attributes(def_entry->attrs);
|
|
4185
|
+
if (effective_attrs && local_attrs) {
|
|
4186
|
+
for (int i = 0;
|
|
4187
|
+
i < local_attrs->attr_count;
|
|
4188
|
+
i++) {
|
|
4189
|
+
int existing_idx =
|
|
4190
|
+
find_attribute_index(
|
|
4191
|
+
effective_attrs,
|
|
4192
|
+
local_attrs->keys[i]);
|
|
4193
|
+
if (existing_idx >= 0) {
|
|
4194
|
+
free(effective_attrs
|
|
4195
|
+
->values[existing_idx]);
|
|
4196
|
+
effective_attrs
|
|
4197
|
+
->values[existing_idx] =
|
|
4198
|
+
strdup(
|
|
4199
|
+
local_attrs->values[i]);
|
|
4200
|
+
} else {
|
|
4201
|
+
add_attribute(
|
|
4202
|
+
effective_attrs,
|
|
4203
|
+
local_attrs->keys[i],
|
|
4204
|
+
local_attrs->values[i]);
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
3775
4208
|
if (getenv("APEX_DEBUG_PIPELINE")) {
|
|
3776
4209
|
fprintf(stderr, "[APEX_DEBUG] expand ref [%s] -> inline image\n", ref_name);
|
|
3777
4210
|
}
|
|
@@ -3780,7 +4213,11 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3780
4213
|
size_t alt_len = alt_end - read2;
|
|
3781
4214
|
|
|
3782
4215
|
/* Convert attributes to markdown format */
|
|
3783
|
-
char *attr_str =
|
|
4216
|
+
char *attr_str =
|
|
4217
|
+
effective_attrs
|
|
4218
|
+
? attributes_to_markdown(
|
|
4219
|
+
effective_attrs)
|
|
4220
|
+
: NULL;
|
|
3784
4221
|
|
|
3785
4222
|
/* Build expanded image:  */
|
|
3786
4223
|
/* Need space for:  */
|
|
@@ -3831,13 +4268,17 @@ char *apex_preprocess_image_attributes(const char *text, image_attr_entry **img_
|
|
|
3831
4268
|
*write2++ = ')';
|
|
3832
4269
|
remaining2--;
|
|
3833
4270
|
|
|
3834
|
-
read2 =
|
|
4271
|
+
read2 = image_end + 1;
|
|
3835
4272
|
free(ref_name);
|
|
3836
4273
|
free(attr_str);
|
|
4274
|
+
apex_free_attributes(local_attrs);
|
|
4275
|
+
apex_free_attributes(effective_attrs);
|
|
3837
4276
|
continue;
|
|
3838
4277
|
}
|
|
3839
4278
|
free(attr_str);
|
|
4279
|
+
apex_free_attributes(effective_attrs);
|
|
3840
4280
|
}
|
|
4281
|
+
apex_free_attributes(local_attrs);
|
|
3841
4282
|
free(ref_name);
|
|
3842
4283
|
}
|
|
3843
4284
|
}
|
|
@@ -4185,19 +4626,20 @@ static bool reference_id_matches(const char *ref_id, const char *text, size_t te
|
|
|
4185
4626
|
remaining--;
|
|
4186
4627
|
}
|
|
4187
4628
|
|
|
4188
|
-
/* Compare
|
|
4629
|
+
/* Compare case-insensitively, collapsing each whitespace run. */
|
|
4189
4630
|
while (*p && remaining > 0) {
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
}
|
|
4199
|
-
continue;
|
|
4631
|
+
bool p_space = isspace((unsigned char)*p);
|
|
4632
|
+
bool t_space = isspace((unsigned char)*t);
|
|
4633
|
+
if (p_space || t_space) {
|
|
4634
|
+
if (!p_space || !t_space) return false;
|
|
4635
|
+
while (*p && isspace((unsigned char)*p)) p++;
|
|
4636
|
+
while (remaining > 0 && isspace((unsigned char)*t)) {
|
|
4637
|
+
t++;
|
|
4638
|
+
remaining--;
|
|
4200
4639
|
}
|
|
4640
|
+
continue;
|
|
4641
|
+
}
|
|
4642
|
+
if (tolower((unsigned char)*p) != tolower((unsigned char)*t)) {
|
|
4201
4643
|
return false;
|
|
4202
4644
|
}
|
|
4203
4645
|
p++;
|
|
@@ -4378,12 +4820,20 @@ char *apex_preprocess_bracketed_spans(const char *text) {
|
|
|
4378
4820
|
if (needs_markdown_span) {
|
|
4379
4821
|
/* Write <span markdown="span" ...> for spans that
|
|
4380
4822
|
* genuinely need inline markdown processing. */
|
|
4381
|
-
|
|
4823
|
+
if (attr_str && attr_str[0]) {
|
|
4824
|
+
written = snprintf(write, remaining, "<span markdown=\"span\" %s>", attr_str);
|
|
4825
|
+
} else {
|
|
4826
|
+
written = snprintf(write, remaining, "<span markdown=\"span\">");
|
|
4827
|
+
}
|
|
4382
4828
|
} else {
|
|
4383
4829
|
/* For simple text-only spans, omit markdown=\"span\"
|
|
4384
4830
|
* so that content like a lone '-' is not reparsed
|
|
4385
4831
|
* as a list item by the markdown-in-HTML pipeline. */
|
|
4386
|
-
|
|
4832
|
+
if (attr_str && attr_str[0]) {
|
|
4833
|
+
written = snprintf(write, remaining, "<span %s>", attr_str);
|
|
4834
|
+
} else {
|
|
4835
|
+
written = snprintf(write, remaining, "<span>");
|
|
4836
|
+
}
|
|
4387
4837
|
}
|
|
4388
4838
|
|
|
4389
4839
|
if (written > 0 && (size_t)written < remaining) {
|