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
|
@@ -43,9 +43,11 @@ void test_cmark_init_callback(void);
|
|
|
43
43
|
void test_cmark_callback(void);
|
|
44
44
|
void test_custom_plugins(void);
|
|
45
45
|
void test_processor_modes(void);
|
|
46
|
+
void test_quarto_mode(void);
|
|
46
47
|
void test_multimarkdown_image_attributes(void);
|
|
47
48
|
void test_file_includes(void);
|
|
48
49
|
void test_ial(void);
|
|
50
|
+
void test_bear_image_attributes(void);
|
|
49
51
|
void test_bracketed_spans(void);
|
|
50
52
|
void test_definition_lists(void);
|
|
51
53
|
void test_advanced_tables(void);
|
|
@@ -58,6 +60,7 @@ void test_callouts(void);
|
|
|
58
60
|
void test_blockquote_lists(void);
|
|
59
61
|
void test_toc(void);
|
|
60
62
|
void test_terminal_output(void);
|
|
63
|
+
void test_rtf_output(void);
|
|
61
64
|
void test_html_markdown_attributes(void);
|
|
62
65
|
void test_fenced_divs(void);
|
|
63
66
|
void test_sup_sub(void);
|
|
@@ -68,6 +71,7 @@ void test_mmd6_features(void);
|
|
|
68
71
|
void test_emoji(void);
|
|
69
72
|
void test_special_markers(void);
|
|
70
73
|
void test_inline_tables(void);
|
|
74
|
+
void test_grid_tables(void);
|
|
71
75
|
void test_insert_syntax(void);
|
|
72
76
|
void test_advanced_footnotes(void);
|
|
73
77
|
void test_standalone_output(void);
|
|
@@ -81,6 +85,7 @@ void test_aria_labels(void);
|
|
|
81
85
|
void test_marked_integration_features(void);
|
|
82
86
|
void test_plugins_integration(void);
|
|
83
87
|
void test_ast_json_parser(void);
|
|
88
|
+
void test_escaping_repro(void);
|
|
84
89
|
|
|
85
90
|
/**
|
|
86
91
|
* Test suite registry
|
|
@@ -113,8 +118,10 @@ static test_suite suites[] = {
|
|
|
113
118
|
{ "cmark_callback", test_cmark_callback },
|
|
114
119
|
{ "multimarkdown_image_attributes",test_multimarkdown_image_attributes },
|
|
115
120
|
{ "processor_modes", test_processor_modes },
|
|
121
|
+
{ "quarto_mode", test_quarto_mode },
|
|
116
122
|
{ "file_includes", test_file_includes },
|
|
117
123
|
{ "ial", test_ial },
|
|
124
|
+
{ "bear_image_attributes", test_bear_image_attributes },
|
|
118
125
|
{ "bracketed_spans", test_bracketed_spans },
|
|
119
126
|
{ "definition_lists", test_definition_lists },
|
|
120
127
|
{ "advanced_tables", test_advanced_tables },
|
|
@@ -127,6 +134,7 @@ static test_suite suites[] = {
|
|
|
127
134
|
{ "blockquote_lists", test_blockquote_lists },
|
|
128
135
|
{ "toc", test_toc },
|
|
129
136
|
{ "terminal_output", test_terminal_output },
|
|
137
|
+
{ "rtf_output", test_rtf_output },
|
|
130
138
|
{ "html_markdown_attributes", test_html_markdown_attributes },
|
|
131
139
|
{ "fenced_divs", test_fenced_divs },
|
|
132
140
|
{ "sup_sub", test_sup_sub },
|
|
@@ -137,6 +145,7 @@ static test_suite suites[] = {
|
|
|
137
145
|
{ "emoji", test_emoji },
|
|
138
146
|
{ "special_markers", test_special_markers },
|
|
139
147
|
{ "inline_tables", test_inline_tables },
|
|
148
|
+
{ "grid_tables", test_grid_tables },
|
|
140
149
|
{ "insert_syntax", test_insert_syntax },
|
|
141
150
|
{ "advanced_footnotes", test_advanced_footnotes },
|
|
142
151
|
{ "standalone_output", test_standalone_output },
|
|
@@ -153,6 +162,8 @@ static test_suite suites[] = {
|
|
|
153
162
|
{ "plugins_integration", test_plugins_integration },
|
|
154
163
|
{ "plugins_custom", test_custom_plugins },
|
|
155
164
|
{ "ast_json", test_ast_json_parser },
|
|
165
|
+
{ "escaping_repro", test_escaping_repro },
|
|
166
|
+
{ "escaping", test_escaping_repro },
|
|
156
167
|
};
|
|
157
168
|
|
|
158
169
|
static const size_t suite_count = sizeof(suites) / sizeof(suites[0]);
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#include <string.h>
|
|
8
8
|
#include <stdlib.h>
|
|
9
9
|
#include <stdbool.h>
|
|
10
|
+
#include <stdio.h>
|
|
10
11
|
|
|
11
12
|
void test_advanced_tables(void) {
|
|
12
13
|
int suite_failures = suite_start();
|
|
@@ -37,6 +38,120 @@ void test_advanced_tables(void) {
|
|
|
37
38
|
assert_contains(html, "Table Caption After", "Caption text after is present");
|
|
38
39
|
apex_free_string(html);
|
|
39
40
|
|
|
41
|
+
/* Regression: footnote definitions must not be interpreted as table captions.
|
|
42
|
+
* Repro from issue #20: inline table followed by [^1]: ...
|
|
43
|
+
*/
|
|
44
|
+
apex_options inline_table_opts = apex_options_default();
|
|
45
|
+
inline_table_opts.enable_marked_extensions = true;
|
|
46
|
+
const char *inline_table_footnote_caption_regression =
|
|
47
|
+
"Lorem ipsum dolor sit amet[^1], fabulas propriae signiferumque in ius.\n\n"
|
|
48
|
+
"<<[Table.csv{;}]\n\n"
|
|
49
|
+
"[^1]: Lorem is a good guy\n";
|
|
50
|
+
html = apex_markdown_to_html(inline_table_footnote_caption_regression,
|
|
51
|
+
strlen(inline_table_footnote_caption_regression),
|
|
52
|
+
&inline_table_opts);
|
|
53
|
+
assert_not_contains(html, "<figcaption>^1</figcaption>",
|
|
54
|
+
"Footnote definition is not treated as table caption");
|
|
55
|
+
apex_free_string(html);
|
|
56
|
+
|
|
57
|
+
const char *inline_table_linkdef_caption_regression =
|
|
58
|
+
"Lorem ipsum dolor sit amet [link-ref].\n\n"
|
|
59
|
+
"<<[Table.csv{;}]\n\n"
|
|
60
|
+
"[link-ref]: https://example.com\n";
|
|
61
|
+
html = apex_markdown_to_html(inline_table_linkdef_caption_regression,
|
|
62
|
+
strlen(inline_table_linkdef_caption_regression),
|
|
63
|
+
&inline_table_opts);
|
|
64
|
+
assert_not_contains(html, "<figcaption>link-ref</figcaption>",
|
|
65
|
+
"Link definition is not treated as table caption");
|
|
66
|
+
apex_free_string(html);
|
|
67
|
+
|
|
68
|
+
const char *gfm_table_footnote_caption_regression =
|
|
69
|
+
"Lorem ipsum dolor sit amet[^1], fabulas propriae signiferumque in ius.\n\n"
|
|
70
|
+
"| Lorem | Dolor | Sit |\n"
|
|
71
|
+
"| ------------- | ------- | ------- |\n"
|
|
72
|
+
"| Amet | Fabulas | Propiae |\n"
|
|
73
|
+
"| Signiferumque | In | Ius |\n\n"
|
|
74
|
+
"[^1]: Lorem is a good guy\n";
|
|
75
|
+
html = apex_markdown_to_html(gfm_table_footnote_caption_regression,
|
|
76
|
+
strlen(gfm_table_footnote_caption_regression),
|
|
77
|
+
&opts);
|
|
78
|
+
assert_contains(html, "<table", "GFM table renders in footnote-caption regression");
|
|
79
|
+
assert_not_contains(html, "<figcaption>^1</figcaption>",
|
|
80
|
+
"Footnote definition after GFM table is not treated as caption");
|
|
81
|
+
apex_free_string(html);
|
|
82
|
+
|
|
83
|
+
/* Regression (#22): caption from inclusion-table section must not leak to nearby tables
|
|
84
|
+
* that do not define their own caption.
|
|
85
|
+
*/
|
|
86
|
+
const char *inclusion_caption_leak_regression =
|
|
87
|
+
"**First table**\n\n"
|
|
88
|
+
"| Lorem | Dolor | Sit |\n"
|
|
89
|
+
"| ------------- | ------- | ------- |\n"
|
|
90
|
+
"| Amet | Fabulas | Propiae |\n"
|
|
91
|
+
"| Signiferumque | In | Ius |\n"
|
|
92
|
+
": My little table caption\n\n"
|
|
93
|
+
"**Second table**\n\n"
|
|
94
|
+
"| Lorem | Dolor | Sit |\n"
|
|
95
|
+
"| ------------- | ------- | ------- |\n"
|
|
96
|
+
"| Amet | Fabulas | Propiae |\n"
|
|
97
|
+
"| Signiferumque | In | Ius |\n\n"
|
|
98
|
+
"**Inclusion Table**\n\n"
|
|
99
|
+
"<<[Table.csv]\n"
|
|
100
|
+
": Caption for inclusion table\n\n"
|
|
101
|
+
"**Third table**\n\n"
|
|
102
|
+
"| Lorem | Dolor | Sit |\n"
|
|
103
|
+
"| ------------- | ------- | ------- |\n"
|
|
104
|
+
"| Amet | Fabulas | Propiae |\n"
|
|
105
|
+
"| Signiferumque | In | Ius |\n";
|
|
106
|
+
html = apex_markdown_to_html(inclusion_caption_leak_regression,
|
|
107
|
+
strlen(inclusion_caption_leak_regression),
|
|
108
|
+
&inline_table_opts);
|
|
109
|
+
assert_contains(html, "My little table caption",
|
|
110
|
+
"Own caption remains attached to first table");
|
|
111
|
+
assert_not_contains(html, "data-caption=\"Caption for inclusion table\"",
|
|
112
|
+
"Inclusion-table caption does not leak into other table attributes");
|
|
113
|
+
assert_not_contains(html, "<figcaption>Caption for inclusion table</figcaption>",
|
|
114
|
+
"Inclusion-table caption does not leak into other table figure captions");
|
|
115
|
+
apex_free_string(html);
|
|
116
|
+
|
|
117
|
+
/* Regression (#20 comment): <<[file] include must not treat following
|
|
118
|
+
* definition lines as include addresses or table captions.
|
|
119
|
+
*/
|
|
120
|
+
const char *include_csv_path = "/tmp/apex_issue20_include_table.csv";
|
|
121
|
+
FILE *include_csv = fopen(include_csv_path, "w");
|
|
122
|
+
if (include_csv) {
|
|
123
|
+
fputs("H1,H2\nA,B\n", include_csv);
|
|
124
|
+
fclose(include_csv);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
char include_table_footnote_def_regression[512];
|
|
128
|
+
snprintf(include_table_footnote_def_regression,
|
|
129
|
+
sizeof(include_table_footnote_def_regression),
|
|
130
|
+
"<<[%s]\n\n[^1]: Some Footnote Text\n",
|
|
131
|
+
include_csv_path);
|
|
132
|
+
html = apex_markdown_to_html(include_table_footnote_def_regression,
|
|
133
|
+
strlen(include_table_footnote_def_regression),
|
|
134
|
+
&inline_table_opts);
|
|
135
|
+
assert_contains(html, "<table", "Include-table with real CSV renders");
|
|
136
|
+
assert_not_contains(html, "<figcaption>Some Footnote Text</figcaption>",
|
|
137
|
+
"Footnote definition after <<[file] is not treated as caption");
|
|
138
|
+
apex_free_string(html);
|
|
139
|
+
|
|
140
|
+
char include_table_link_def_regression[512];
|
|
141
|
+
snprintf(include_table_link_def_regression,
|
|
142
|
+
sizeof(include_table_link_def_regression),
|
|
143
|
+
"<<[%s]\n\n[link-ref]: https://example.com\n",
|
|
144
|
+
include_csv_path);
|
|
145
|
+
html = apex_markdown_to_html(include_table_link_def_regression,
|
|
146
|
+
strlen(include_table_link_def_regression),
|
|
147
|
+
&inline_table_opts);
|
|
148
|
+
assert_contains(html, "<table", "Include-table with link definition renders");
|
|
149
|
+
assert_not_contains(html, "<figcaption>https://example.com</figcaption>",
|
|
150
|
+
"Link definition after <<[file] is not treated as caption");
|
|
151
|
+
apex_free_string(html);
|
|
152
|
+
|
|
153
|
+
remove(include_csv_path);
|
|
154
|
+
|
|
40
155
|
/* Test rowspan with ^^ */
|
|
41
156
|
const char *rowspan_table = "| H1 | H2 |\n|----|----|"
|
|
42
157
|
"\n| A | B |"
|
|
@@ -98,6 +213,35 @@ void test_advanced_tables(void) {
|
|
|
98
213
|
assert_not_contains(html, "colspan", "Empty cells table: no colspan attribute (empty cells don't create colspan)");
|
|
99
214
|
apex_free_string(html);
|
|
100
215
|
|
|
216
|
+
/* Blank cells use spaced pipes (| |); colspan only for consecutive pipes (||).
|
|
217
|
+
* A later full-width colspan row must not steal blanks from earlier indent rows. */
|
|
218
|
+
const char *blank_then_colspan =
|
|
219
|
+
"|:-|:-|:-|:-|:-|\n"
|
|
220
|
+
"|a|b|c|d|e|\n"
|
|
221
|
+
"| | |x|y|z|\n"
|
|
222
|
+
"| | |p|q|r|\n"
|
|
223
|
+
"|full|||||\n";
|
|
224
|
+
html = apex_markdown_to_html(blank_then_colspan, strlen(blank_then_colspan), &opts);
|
|
225
|
+
assert_contains(html, "<td colspan=\"5\">full</td>", "Blank then colspan: full-width colspan on last row");
|
|
226
|
+
assert_contains(html, ">x</td>", "Blank then colspan: indent cell x present");
|
|
227
|
+
assert_contains(html, ">p</td>", "Blank then colspan: indent cell p present");
|
|
228
|
+
/* First indent row should keep two leading blank cells, not a colspan on an empty cell */
|
|
229
|
+
assert_not_contains(html, "<td colspan=\"5\"></td>", "Blank then colspan: no empty-cell colspan on indent rows");
|
|
230
|
+
assert_not_contains(html, "<th colspan=\"5\"></th>", "Blank then colspan: no empty th colspan on indent rows");
|
|
231
|
+
apex_free_string(html);
|
|
232
|
+
|
|
233
|
+
/* Spaced empty cell between content stays a blank column, not a span */
|
|
234
|
+
const char *spaced_blank_between =
|
|
235
|
+
"| H1 | H2 | H3 |\n"
|
|
236
|
+
"|----|----|----|\n"
|
|
237
|
+
"| A | | B |\n";
|
|
238
|
+
html = apex_markdown_to_html(spaced_blank_between, strlen(spaced_blank_between), &opts);
|
|
239
|
+
assert_contains(html, "<td>A</td>", "Spaced blank between: A present");
|
|
240
|
+
assert_contains(html, "<td></td>", "Spaced blank between: blank cell present");
|
|
241
|
+
assert_contains(html, "<td>B</td>", "Spaced blank between: B present");
|
|
242
|
+
assert_not_contains(html, "colspan", "Spaced blank between: no colspan from | |");
|
|
243
|
+
apex_free_string(html);
|
|
244
|
+
|
|
101
245
|
/* Test dash-only separator row removal (rows containing only — should be removed). */
|
|
102
246
|
const char *dash_row =
|
|
103
247
|
"| H1 | H2 |\n"
|
|
@@ -389,6 +533,43 @@ void test_relaxed_tables(void) {
|
|
|
389
533
|
}
|
|
390
534
|
apex_free_string(html);
|
|
391
535
|
|
|
536
|
+
/* Pipes inside fenced code blocks must not trigger relaxed table separators */
|
|
537
|
+
const char *fenced_code_with_pipes =
|
|
538
|
+
"```bash\n"
|
|
539
|
+
"update_widgets() {\n"
|
|
540
|
+
" echo foo | sed 's/x/y/' | awk '{print $1}'\n"
|
|
541
|
+
"}\n"
|
|
542
|
+
"```";
|
|
543
|
+
html = apex_markdown_to_html(fenced_code_with_pipes, strlen(fenced_code_with_pipes), &opts);
|
|
544
|
+
assert_contains(html, "<code", "Fenced code block with pipes renders as code");
|
|
545
|
+
assert_contains(html, "echo foo | sed", "Code block content with pipes preserved");
|
|
546
|
+
if (strstr(html, "---|---|---|") == NULL) {
|
|
547
|
+
test_result(true, "No relaxed-table separator injected inside fenced code");
|
|
548
|
+
} else {
|
|
549
|
+
test_result(false, "Relaxed-table separator was injected inside fenced code");
|
|
550
|
+
}
|
|
551
|
+
apex_free_string(html);
|
|
552
|
+
|
|
553
|
+
/* Mermaid edge labels |Yes| / |No| must not get a GFM separator injected */
|
|
554
|
+
{
|
|
555
|
+
apex_options unified = apex_options_default();
|
|
556
|
+
unified.mode = APEX_MODE_UNIFIED;
|
|
557
|
+
unified.relaxed_tables = true;
|
|
558
|
+
unified.enable_tables = true;
|
|
559
|
+
const char *mermaid_pipes =
|
|
560
|
+
"```mermaid\n"
|
|
561
|
+
"graph TD\n"
|
|
562
|
+
" A -->|Yes| B\n"
|
|
563
|
+
" A -->|No| C\n"
|
|
564
|
+
"```\n";
|
|
565
|
+
html = apex_markdown_to_html(mermaid_pipes, strlen(mermaid_pipes), &unified);
|
|
566
|
+
assert_contains(html, "lang=\"mermaid\"", "Mermaid fence keeps language");
|
|
567
|
+
assert_contains(html, "|Yes|", "Mermaid Yes edge label preserved");
|
|
568
|
+
assert_contains(html, "|No|", "Mermaid No edge label preserved");
|
|
569
|
+
assert_not_contains(html, "---|---|---", "No relaxed-table separator inside Mermaid fence");
|
|
570
|
+
apex_free_string(html);
|
|
571
|
+
}
|
|
572
|
+
|
|
392
573
|
bool had_failures = suite_end(suite_failures);
|
|
393
574
|
print_suite_title("Relaxed Tables Tests", had_failures, false);
|
|
394
575
|
}
|
|
@@ -873,6 +1054,245 @@ void test_inline_tables(void) {
|
|
|
873
1054
|
print_suite_title("Inline Tables Tests", had_failures, false);
|
|
874
1055
|
}
|
|
875
1056
|
|
|
1057
|
+
void test_grid_tables(void) {
|
|
1058
|
+
int suite_failures = suite_start();
|
|
1059
|
+
print_suite_title("Grid Tables Tests", false, true);
|
|
1060
|
+
|
|
1061
|
+
apex_options opts = apex_options_default();
|
|
1062
|
+
opts.enable_tables = true;
|
|
1063
|
+
opts.enable_grid_tables = true;
|
|
1064
|
+
opts.relaxed_tables = false;
|
|
1065
|
+
char *html;
|
|
1066
|
+
|
|
1067
|
+
/* Test basic grid table */
|
|
1068
|
+
const char *basic_grid = "+---+---+\n"
|
|
1069
|
+
"| H1 | H2 |\n"
|
|
1070
|
+
"+===+===+\n"
|
|
1071
|
+
"| C1 | C2 |\n"
|
|
1072
|
+
"+---+---+";
|
|
1073
|
+
html = apex_markdown_to_html(basic_grid, strlen(basic_grid), &opts);
|
|
1074
|
+
assert_contains(html, "<table", "Basic grid table renders");
|
|
1075
|
+
assert_contains(html, "<th>H1</th>", "Grid table header");
|
|
1076
|
+
assert_contains(html, "<td>C1</td>", "Grid table cell");
|
|
1077
|
+
apex_free_string(html);
|
|
1078
|
+
|
|
1079
|
+
/* Test grid table with header separator */
|
|
1080
|
+
const char *header_sep_grid = "+---+---+\n"
|
|
1081
|
+
"| H1 | H2 |\n"
|
|
1082
|
+
"+===+===+\n"
|
|
1083
|
+
"| C1 | C2 |\n"
|
|
1084
|
+
"+---+---+";
|
|
1085
|
+
html = apex_markdown_to_html(header_sep_grid, strlen(header_sep_grid), &opts);
|
|
1086
|
+
assert_contains(html, "<table", "Grid table with header separator renders");
|
|
1087
|
+
assert_contains(html, "<th>H1</th>", "Header separator table has header");
|
|
1088
|
+
apex_free_string(html);
|
|
1089
|
+
|
|
1090
|
+
/* Test grid table with alignment */
|
|
1091
|
+
const char *aligned_grid = "+:---+---+---:+\n"
|
|
1092
|
+
"| C | L | R |\n"
|
|
1093
|
+
"+===+===+===+\n"
|
|
1094
|
+
"| A | B | C |\n"
|
|
1095
|
+
"+---+---+---+";
|
|
1096
|
+
html = apex_markdown_to_html(aligned_grid, strlen(aligned_grid), &opts);
|
|
1097
|
+
assert_contains(html, "<table", "Aligned grid table renders");
|
|
1098
|
+
apex_free_string(html);
|
|
1099
|
+
|
|
1100
|
+
/* Test grid table with footer separator */
|
|
1101
|
+
const char *footer_grid = "+---+---+\n"
|
|
1102
|
+
"| H1 | H2 |\n"
|
|
1103
|
+
"+---+---+\n"
|
|
1104
|
+
"| C1 | C2 |\n"
|
|
1105
|
+
"+===+===+\n"
|
|
1106
|
+
"| F1 | F2 |\n"
|
|
1107
|
+
"+---+---+";
|
|
1108
|
+
html = apex_markdown_to_html(footer_grid, strlen(footer_grid), &opts);
|
|
1109
|
+
assert_contains(html, "<table", "Grid table with footer renders");
|
|
1110
|
+
apex_free_string(html);
|
|
1111
|
+
|
|
1112
|
+
/* Test multi-line cells in grid table */
|
|
1113
|
+
const char *multiline_grid = "+---+---+\n"
|
|
1114
|
+
"| H1 | H2 |\n"
|
|
1115
|
+
"+===+===+\n"
|
|
1116
|
+
"| Line 1 | Cell 2 |\n"
|
|
1117
|
+
"| Line 2 | |\n"
|
|
1118
|
+
"+---+---+";
|
|
1119
|
+
html = apex_markdown_to_html(multiline_grid, strlen(multiline_grid), &opts);
|
|
1120
|
+
assert_contains(html, "<table", "Multi-line grid table renders");
|
|
1121
|
+
assert_contains(html, "Line 1", "Multi-line cell content preserved");
|
|
1122
|
+
assert_contains(html, "Line 2", "Multi-line cell second line preserved");
|
|
1123
|
+
apex_free_string(html);
|
|
1124
|
+
|
|
1125
|
+
/* Test grid table with caption (before) */
|
|
1126
|
+
const char *caption_before = "[Grid Table Caption]\n\n"
|
|
1127
|
+
"+---+---+\n"
|
|
1128
|
+
"| H1 | H2 |\n"
|
|
1129
|
+
"+===+===+\n"
|
|
1130
|
+
"| C1 | C2 |\n"
|
|
1131
|
+
"+---+---+";
|
|
1132
|
+
html = apex_markdown_to_html(caption_before, strlen(caption_before), &opts);
|
|
1133
|
+
assert_contains(html, "<table", "Grid table with caption before renders");
|
|
1134
|
+
assert_contains(html, "<figure", "Grid table with caption wrapped in figure");
|
|
1135
|
+
assert_contains(html, "Grid Table Caption", "Caption text present");
|
|
1136
|
+
apex_free_string(html);
|
|
1137
|
+
|
|
1138
|
+
/* Test grid table with caption (after) */
|
|
1139
|
+
const char *caption_after = "+---+---+\n"
|
|
1140
|
+
"| H1 | H2 |\n"
|
|
1141
|
+
"+===+===+\n"
|
|
1142
|
+
"| C1 | C2 |\n"
|
|
1143
|
+
"+---+---+\n\n"
|
|
1144
|
+
"[Grid Table Caption After]";
|
|
1145
|
+
html = apex_markdown_to_html(caption_after, strlen(caption_after), &opts);
|
|
1146
|
+
assert_contains(html, "<table", "Grid table with caption after renders");
|
|
1147
|
+
assert_contains(html, "Grid Table Caption After", "Caption text after present");
|
|
1148
|
+
apex_free_string(html);
|
|
1149
|
+
|
|
1150
|
+
/* Test grid table in code block (should not be parsed) */
|
|
1151
|
+
const char *code_block_grid = "```\n"
|
|
1152
|
+
"+---+---+\n"
|
|
1153
|
+
"| H1 | H2 |\n"
|
|
1154
|
+
"+===+===+\n"
|
|
1155
|
+
"| C1 | C2 |\n"
|
|
1156
|
+
"+---+---+\n"
|
|
1157
|
+
"```";
|
|
1158
|
+
html = apex_markdown_to_html(code_block_grid, strlen(code_block_grid), &opts);
|
|
1159
|
+
assert_not_contains(html, "<table", "Grid table in code block not parsed");
|
|
1160
|
+
assert_contains(html, "<code", "Code block preserved");
|
|
1161
|
+
apex_free_string(html);
|
|
1162
|
+
|
|
1163
|
+
/* Test mixed grid and pipe tables */
|
|
1164
|
+
const char *mixed_tables = "+---+---+\n"
|
|
1165
|
+
"| G1 | G2 |\n"
|
|
1166
|
+
"+===+===+\n"
|
|
1167
|
+
"| GC1 | GC2 |\n"
|
|
1168
|
+
"+---+---+\n\n"
|
|
1169
|
+
"| P1 | P2 |\n"
|
|
1170
|
+
"|----|----|\n"
|
|
1171
|
+
"| PC1 | PC2 |";
|
|
1172
|
+
html = apex_markdown_to_html(mixed_tables, strlen(mixed_tables), &opts);
|
|
1173
|
+
assert_contains(html, "<table", "Mixed tables render");
|
|
1174
|
+
assert_contains(html, "G1", "Grid table content present");
|
|
1175
|
+
assert_contains(html, "P1", "Pipe table content present");
|
|
1176
|
+
apex_free_string(html);
|
|
1177
|
+
|
|
1178
|
+
/* Test grid table disabled */
|
|
1179
|
+
opts.enable_grid_tables = false;
|
|
1180
|
+
html = apex_markdown_to_html(basic_grid, strlen(basic_grid), &opts);
|
|
1181
|
+
apex_free_string(html);
|
|
1182
|
+
|
|
1183
|
+
/* Complex colspan row spanning full table width (no closing table separator) */
|
|
1184
|
+
opts.enable_grid_tables = true;
|
|
1185
|
+
opts.enable_tables = true;
|
|
1186
|
+
const char *colspan_grid = "+---+---+\n"
|
|
1187
|
+
"| H1 | H2 |\n"
|
|
1188
|
+
"+===+===+\n"
|
|
1189
|
+
"| C1 | C2 |\n"
|
|
1190
|
+
"+---+---+\n"
|
|
1191
|
+
"| Spans both columns here |\n";
|
|
1192
|
+
html = apex_markdown_to_html(colspan_grid, strlen(colspan_grid), &opts);
|
|
1193
|
+
assert_contains(html, "colspan=\"2\"", "Colspan row spans both columns");
|
|
1194
|
+
assert_contains(html, "Spans both columns", "Colspan cell content preserved");
|
|
1195
|
+
apex_free_string(html);
|
|
1196
|
+
|
|
1197
|
+
/* Nested grid inside colspan cell stays in one cell */
|
|
1198
|
+
const char *nested_in_colspan = "+---+---+\n"
|
|
1199
|
+
"| A | B |\n"
|
|
1200
|
+
"+===+===+\n"
|
|
1201
|
+
"| Wide cell |\n"
|
|
1202
|
+
"+---+---+---+\n"
|
|
1203
|
+
"| n1 | n2 | n3 |\n"
|
|
1204
|
+
"+---+---+---+";
|
|
1205
|
+
html = apex_markdown_to_html(nested_in_colspan, strlen(nested_in_colspan), &opts);
|
|
1206
|
+
assert_contains(html, "colspan=\"2\"", "Nested grid parent has colspan");
|
|
1207
|
+
assert_contains(html, "Wide cell", "Wide cell text preserved");
|
|
1208
|
+
assert_not_contains(html, "<tr>\n<td>n1</td>\n<td>n2</td>", "Nested grid not separate top-level row");
|
|
1209
|
+
apex_free_string(html);
|
|
1210
|
+
|
|
1211
|
+
/* Fixture table 1: colspan + nested grid stays inside the table, not a stray paragraph */
|
|
1212
|
+
const char *fixture_colspan_nested = "+-------------------+-------------------+\n"
|
|
1213
|
+
"| Grid Tables | Are Beautiful |\n"
|
|
1214
|
+
"+===================+===================+\n"
|
|
1215
|
+
"| Easy to read | In code and docs |\n"
|
|
1216
|
+
"+-------------------+-------------------+\n"
|
|
1217
|
+
"| Exceptionally flexible and powerful |\n"
|
|
1218
|
+
"+-------+-------+-------+-------+-------+\n"
|
|
1219
|
+
"| Col 1 | Col 2 | Col 3 | Col 4 | Col 5 |\n"
|
|
1220
|
+
"+-------+-------+-------+-------+-------+\n";
|
|
1221
|
+
html = apex_markdown_to_html(fixture_colspan_nested, strlen(fixture_colspan_nested), &opts);
|
|
1222
|
+
assert_contains(html, "colspan=\"2\"", "Fixture colspan row in table");
|
|
1223
|
+
assert_contains(html, "Exceptionally flexible and powerful", "Fixture colspan text in output");
|
|
1224
|
+
assert_not_contains(html, "</table>\n<p>|", "Colspan row not leaked as paragraph after table");
|
|
1225
|
+
assert_contains(html, "Col 1", "Nested grid Col 1 inside colspan cell");
|
|
1226
|
+
assert_contains(html, "Col 5", "Nested grid Col 5 inside colspan cell");
|
|
1227
|
+
apex_free_string(html);
|
|
1228
|
+
|
|
1229
|
+
/* Partial separator table (fixture table 2 pattern) */
|
|
1230
|
+
const char *partial_grid = "+---------------------+----------+\n"
|
|
1231
|
+
"| Property | Earth |\n"
|
|
1232
|
+
"+=============+=======+==========+\n"
|
|
1233
|
+
"| | min | -89.2 °C |\n"
|
|
1234
|
+
"| Temperature +-------+----------+\n"
|
|
1235
|
+
"| 1961-1990 | mean | 14 °C |\n"
|
|
1236
|
+
"| +-------+----------+\n"
|
|
1237
|
+
"| | min | 56.7 °C |\n"
|
|
1238
|
+
"+-------------+-------+----------+\n";
|
|
1239
|
+
html = apex_markdown_to_html(partial_grid, strlen(partial_grid), &opts);
|
|
1240
|
+
assert_contains(html, "colspan=\"2\"", "Partial table Property spans two columns");
|
|
1241
|
+
assert_contains(html, "rowspan=\"3\"", "Partial table Temperature rowspan");
|
|
1242
|
+
assert_contains(html, "14 °C", "Partial table mean temperature");
|
|
1243
|
+
apex_free_string(html);
|
|
1244
|
+
|
|
1245
|
+
/* Multiline list cells */
|
|
1246
|
+
const char *list_cells = "+---+---+---+\n"
|
|
1247
|
+
"| F | P | Notes |\n"
|
|
1248
|
+
"+===+===+===+\n"
|
|
1249
|
+
"| Ban | $1 | - one |\n"
|
|
1250
|
+
"| | | - two |\n"
|
|
1251
|
+
"+---+---+---+";
|
|
1252
|
+
html = apex_markdown_to_html(list_cells, strlen(list_cells), &opts);
|
|
1253
|
+
assert_contains(html, "<ul>", "List cell renders as ul");
|
|
1254
|
+
assert_contains(html, "<li>one</li>", "List item one in cell");
|
|
1255
|
+
assert_contains(html, "<li>two</li>", "List item two in cell");
|
|
1256
|
+
assert_contains(html, "<table", "List cells table renders");
|
|
1257
|
+
apex_free_string(html);
|
|
1258
|
+
|
|
1259
|
+
/* Plus-prefixed prose lines are not mistaken for grid tables */
|
|
1260
|
+
const char *plus_prose = "+ Item one\n+ Item two\n\nParagraph after.";
|
|
1261
|
+
html = apex_markdown_to_html(plus_prose, strlen(plus_prose), &opts);
|
|
1262
|
+
assert_contains(html, "Item one", "Plus prose lines preserved as list items");
|
|
1263
|
+
assert_contains(html, "Paragraph after", "Text after plus lines preserved");
|
|
1264
|
+
assert_not_contains(html, "<table", "Plus prose is not converted to a table");
|
|
1265
|
+
apex_free_string(html);
|
|
1266
|
+
|
|
1267
|
+
/* Block with +---+ lines but no valid grid content is preserved on failure */
|
|
1268
|
+
const char *invalid_grid = "+---+\nThis line has no pipes\n+---+";
|
|
1269
|
+
html = apex_markdown_to_html(invalid_grid, strlen(invalid_grid), &opts);
|
|
1270
|
+
assert_contains(html, "This line has no pipes", "Invalid grid block content preserved");
|
|
1271
|
+
apex_free_string(html);
|
|
1272
|
+
|
|
1273
|
+
/* Grid tables disabled by default in unified mode */
|
|
1274
|
+
apex_options unified_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
1275
|
+
html = apex_markdown_to_html(basic_grid, strlen(basic_grid), &unified_opts);
|
|
1276
|
+
assert_not_contains(html, "<th>H1</th>", "Grid tables off by default in unified mode");
|
|
1277
|
+
apex_free_string(html);
|
|
1278
|
+
|
|
1279
|
+
/* Pandoc-style simple grid (manual example pattern) */
|
|
1280
|
+
const char *pandoc_simple = "+---------------+---------------+\n"
|
|
1281
|
+
"| Fruit | Price |\n"
|
|
1282
|
+
"+:==============+==============:+\n"
|
|
1283
|
+
"| Bananas | $1.34 |\n"
|
|
1284
|
+
"| Oranges | $2.10 |\n"
|
|
1285
|
+
"+---------------+---------------+\n";
|
|
1286
|
+
html = apex_markdown_to_html(pandoc_simple, strlen(pandoc_simple), &opts);
|
|
1287
|
+
assert_contains(html, "Bananas", "Pandoc-style aligned grid renders");
|
|
1288
|
+
assert_contains(html, "$1.34", "Pandoc-style grid cell content");
|
|
1289
|
+
assert_contains(html, "<table", "Pandoc-style grid produces table");
|
|
1290
|
+
apex_free_string(html);
|
|
1291
|
+
|
|
1292
|
+
bool had_failures = suite_end(suite_failures);
|
|
1293
|
+
print_suite_title("Grid Tables Tests", had_failures, false);
|
|
1294
|
+
}
|
|
1295
|
+
|
|
876
1296
|
/**
|
|
877
1297
|
* Test advanced footnotes
|
|
878
1298
|
*/
|
|
@@ -267,7 +267,7 @@ static cmark_node *url_match(cmark_parser *parser, cmark_node *parent,
|
|
|
267
267
|
cmark_node *text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
|
|
268
268
|
text->as.literal = url;
|
|
269
269
|
cmark_node_append_child(node, text);
|
|
270
|
-
|
|
270
|
+
|
|
271
271
|
node->start_line = text->start_line = node->end_line = text->end_line = cmark_inline_parser_get_line(inline_parser);
|
|
272
272
|
|
|
273
273
|
node->start_column = text->start_column = max_rewind - rewind;
|
|
@@ -318,6 +318,64 @@ static bool validate_protocol(const char protocol[], uint8_t *data, size_t rewin
|
|
|
318
318
|
return !cmark_isalnum(prev_char);
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
+
static bool inside_html_tag(const uint8_t *data, size_t at_pos) {
|
|
322
|
+
bool in_tag = false;
|
|
323
|
+
uint8_t quote = 0;
|
|
324
|
+
size_t i;
|
|
325
|
+
|
|
326
|
+
for (i = 0; i < at_pos; ++i) {
|
|
327
|
+
uint8_t c = data[i];
|
|
328
|
+
|
|
329
|
+
if (!in_tag) {
|
|
330
|
+
if (c == '<')
|
|
331
|
+
in_tag = true;
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (quote != 0) {
|
|
336
|
+
if (c == quote)
|
|
337
|
+
quote = 0;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (c == '"' || c == '\'') {
|
|
342
|
+
quote = c;
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (c == '>')
|
|
347
|
+
in_tag = false;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return in_tag;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
static bool is_image_density_suffix(const uint8_t *data, size_t size) {
|
|
354
|
+
size_t i = 0;
|
|
355
|
+
|
|
356
|
+
if (size < 4)
|
|
357
|
+
return false;
|
|
358
|
+
|
|
359
|
+
while (i < size && cmark_isdigit(data[i]))
|
|
360
|
+
i++;
|
|
361
|
+
|
|
362
|
+
if (i == 0 || i >= size || data[i] != 'x')
|
|
363
|
+
return false;
|
|
364
|
+
i++;
|
|
365
|
+
|
|
366
|
+
if (i >= size || data[i] != '.')
|
|
367
|
+
return false;
|
|
368
|
+
i++;
|
|
369
|
+
|
|
370
|
+
if (i >= size || !cmark_isalnum(data[i]))
|
|
371
|
+
return false;
|
|
372
|
+
|
|
373
|
+
while (i < size && cmark_isalnum(data[i]))
|
|
374
|
+
i++;
|
|
375
|
+
|
|
376
|
+
return i == size;
|
|
377
|
+
}
|
|
378
|
+
|
|
321
379
|
static void postprocess_text(cmark_parser *parser, cmark_node *text) {
|
|
322
380
|
size_t start = 0;
|
|
323
381
|
size_t offset = 0;
|
|
@@ -350,6 +408,11 @@ static void postprocess_text(cmark_parser *parser, cmark_node *text) {
|
|
|
350
408
|
|
|
351
409
|
max_rewind = at - (data + start + offset);
|
|
352
410
|
|
|
411
|
+
if (inside_html_tag(data + start + offset, max_rewind)) {
|
|
412
|
+
offset += max_rewind + 1;
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
|
|
353
416
|
found_at:
|
|
354
417
|
for (rewind = 0; rewind < max_rewind; ++rewind) {
|
|
355
418
|
uint8_t c = data[start + offset + max_rewind - rewind - 1];
|
|
@@ -381,6 +444,14 @@ found_at:
|
|
|
381
444
|
continue;
|
|
382
445
|
}
|
|
383
446
|
|
|
447
|
+
/* Require that the character immediately before @ is alphanumeric.
|
|
448
|
+
* This prevents matching @ in URLs like https://example.com/@user */
|
|
449
|
+
uint8_t char_before_at = data[start + offset + max_rewind - 1];
|
|
450
|
+
if (!cmark_isalnum(char_before_at)) {
|
|
451
|
+
offset += max_rewind + 1;
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
|
|
384
455
|
assert(data[start + offset + max_rewind] == '@');
|
|
385
456
|
for (link_end = 1; link_end < remaining - offset - max_rewind; ++link_end) {
|
|
386
457
|
uint8_t c = data[start + offset + max_rewind + link_end];
|
|
@@ -409,6 +480,11 @@ found_at:
|
|
|
409
480
|
continue;
|
|
410
481
|
}
|
|
411
482
|
|
|
483
|
+
if (is_image_density_suffix(data + start + offset + max_rewind + 1, link_end - 1)) {
|
|
484
|
+
offset += max_rewind + link_end;
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
|
|
412
488
|
link_end = autolink_delim(data + start + offset + max_rewind, link_end);
|
|
413
489
|
|
|
414
490
|
if (link_end == 0) {
|