html-to-markdown 3.4.0 → 3.6.0.pre.rc.23
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/LICENSE +21 -0
- data/README.md +347 -0
- data/Steepfile +10 -2
- data/ext/html_to_markdown_rb/Cargo.toml +3 -2
- data/ext/html_to_markdown_rb/extconf.rb +5 -5
- data/ext/html_to_markdown_rb/native/Cargo.lock +962 -0
- data/ext/html_to_markdown_rb/native/Cargo.toml +6 -11
- data/ext/html_to_markdown_rb/native/extconf.rb +14 -0
- data/ext/html_to_markdown_rb/src/lib.rs +1715 -646
- data/lib/html_to_markdown/native.rb +913 -37
- data/lib/html_to_markdown/version.rb +3 -3
- data/lib/html_to_markdown.rb +9 -4
- data/lib/html_to_markdown_rb.so +0 -0
- data/sig/types.rbs +59 -292
- metadata +32 -179
- data/ext/html_to_markdown_rb/Makefile +0 -592
- data/lib/bin/html-to-markdown +0 -0
- data/vendor/Cargo.toml +0 -33
- data/vendor/html-to-markdown-rs/Cargo.toml +0 -54
- data/vendor/html-to-markdown-rs/README.md +0 -278
- data/vendor/html-to-markdown-rs/examples/basic.rs +0 -24
- data/vendor/html-to-markdown-rs/examples/table.rs +0 -25
- data/vendor/html-to-markdown-rs/examples/test_deser.rs +0 -12
- data/vendor/html-to-markdown-rs/examples/test_escape.rs +0 -58
- data/vendor/html-to-markdown-rs/examples/test_inline_formatting.rs +0 -113
- data/vendor/html-to-markdown-rs/examples/test_lists.rs +0 -39
- data/vendor/html-to-markdown-rs/examples/test_semantic_tags.rs +0 -89
- data/vendor/html-to-markdown-rs/examples/test_tables.rs +0 -100
- data/vendor/html-to-markdown-rs/examples/test_task_lists.rs +0 -61
- data/vendor/html-to-markdown-rs/examples/test_whitespace.rs +0 -34
- data/vendor/html-to-markdown-rs/src/convert_api.rs +0 -349
- data/vendor/html-to-markdown-rs/src/converter/block/blockquote.rs +0 -178
- data/vendor/html-to-markdown-rs/src/converter/block/container.rs +0 -114
- data/vendor/html-to-markdown-rs/src/converter/block/div.rs +0 -149
- data/vendor/html-to-markdown-rs/src/converter/block/heading.rs +0 -428
- data/vendor/html-to-markdown-rs/src/converter/block/horizontal_rule.rs +0 -103
- data/vendor/html-to-markdown-rs/src/converter/block/line_break.rs +0 -89
- data/vendor/html-to-markdown-rs/src/converter/block/mod.rs +0 -10
- data/vendor/html-to-markdown-rs/src/converter/block/paragraph.rs +0 -140
- data/vendor/html-to-markdown-rs/src/converter/block/preformatted.rs +0 -298
- data/vendor/html-to-markdown-rs/src/converter/block/table/builder.rs +0 -453
- data/vendor/html-to-markdown-rs/src/converter/block/table/caption.rs +0 -44
- data/vendor/html-to-markdown-rs/src/converter/block/table/cell.rs +0 -276
- data/vendor/html-to-markdown-rs/src/converter/block/table/cells.rs +0 -336
- data/vendor/html-to-markdown-rs/src/converter/block/table/layout.rs +0 -58
- data/vendor/html-to-markdown-rs/src/converter/block/table/mod.rs +0 -266
- data/vendor/html-to-markdown-rs/src/converter/block/table/scanner.rs +0 -146
- data/vendor/html-to-markdown-rs/src/converter/block/table/utils.rs +0 -34
- data/vendor/html-to-markdown-rs/src/converter/block/unknown.rs +0 -138
- data/vendor/html-to-markdown-rs/src/converter/context.rs +0 -208
- data/vendor/html-to-markdown-rs/src/converter/dom_context.rs +0 -337
- data/vendor/html-to-markdown-rs/src/converter/form/elements.rs +0 -770
- data/vendor/html-to-markdown-rs/src/converter/form/mod.rs +0 -82
- data/vendor/html-to-markdown-rs/src/converter/format/djot.rs +0 -64
- data/vendor/html-to-markdown-rs/src/converter/format/markdown.rs +0 -59
- data/vendor/html-to-markdown-rs/src/converter/format/mod.rs +0 -43
- data/vendor/html-to-markdown-rs/src/converter/handlers/blockquote.rs +0 -173
- data/vendor/html-to-markdown-rs/src/converter/handlers/code_block.rs +0 -434
- data/vendor/html-to-markdown-rs/src/converter/handlers/graphic.rs +0 -234
- data/vendor/html-to-markdown-rs/src/converter/handlers/image.rs +0 -282
- data/vendor/html-to-markdown-rs/src/converter/handlers/link.rs +0 -316
- data/vendor/html-to-markdown-rs/src/converter/handlers/mod.rs +0 -26
- data/vendor/html-to-markdown-rs/src/converter/inline/code.rs +0 -306
- data/vendor/html-to-markdown-rs/src/converter/inline/emphasis.rs +0 -345
- data/vendor/html-to-markdown-rs/src/converter/inline/link.rs +0 -428
- data/vendor/html-to-markdown-rs/src/converter/inline/mod.rs +0 -237
- data/vendor/html-to-markdown-rs/src/converter/inline/ruby.rs +0 -337
- data/vendor/html-to-markdown-rs/src/converter/inline/semantic/marks.rs +0 -566
- data/vendor/html-to-markdown-rs/src/converter/inline/semantic/mod.rs +0 -86
- data/vendor/html-to-markdown-rs/src/converter/inline/semantic/typography.rs +0 -558
- data/vendor/html-to-markdown-rs/src/converter/list/definition.rs +0 -232
- data/vendor/html-to-markdown-rs/src/converter/list/item.rs +0 -332
- data/vendor/html-to-markdown-rs/src/converter/list/mod.rs +0 -70
- data/vendor/html-to-markdown-rs/src/converter/list/ordered.rs +0 -201
- data/vendor/html-to-markdown-rs/src/converter/list/unordered.rs +0 -195
- data/vendor/html-to-markdown-rs/src/converter/list/utils.rs +0 -314
- data/vendor/html-to-markdown-rs/src/converter/main.rs +0 -710
- data/vendor/html-to-markdown-rs/src/converter/main_helpers.rs +0 -452
- data/vendor/html-to-markdown-rs/src/converter/media/embedded.rs +0 -393
- data/vendor/html-to-markdown-rs/src/converter/media/graphic.rs +0 -4
- data/vendor/html-to-markdown-rs/src/converter/media/image.rs +0 -183
- data/vendor/html-to-markdown-rs/src/converter/media/mod.rs +0 -87
- data/vendor/html-to-markdown-rs/src/converter/media/svg.rs +0 -280
- data/vendor/html-to-markdown-rs/src/converter/metadata.rs +0 -220
- data/vendor/html-to-markdown-rs/src/converter/mod.rs +0 -156
- data/vendor/html-to-markdown-rs/src/converter/plain_text.rs +0 -516
- data/vendor/html-to-markdown-rs/src/converter/preprocessing_helpers.rs +0 -201
- data/vendor/html-to-markdown-rs/src/converter/reference_collector.rs +0 -69
- data/vendor/html-to-markdown-rs/src/converter/semantic/attributes.rs +0 -269
- data/vendor/html-to-markdown-rs/src/converter/semantic/definition_list.rs +0 -266
- data/vendor/html-to-markdown-rs/src/converter/semantic/figure.rs +0 -391
- data/vendor/html-to-markdown-rs/src/converter/semantic/mod.rs +0 -112
- data/vendor/html-to-markdown-rs/src/converter/semantic/sectioning.rs +0 -85
- data/vendor/html-to-markdown-rs/src/converter/semantic/summary.rs +0 -324
- data/vendor/html-to-markdown-rs/src/converter/text/mod.rs +0 -8
- data/vendor/html-to-markdown-rs/src/converter/text/processing.rs +0 -56
- data/vendor/html-to-markdown-rs/src/converter/text_node.rs +0 -269
- data/vendor/html-to-markdown-rs/src/converter/utility/attributes.rs +0 -151
- data/vendor/html-to-markdown-rs/src/converter/utility/caching.rs +0 -74
- data/vendor/html-to-markdown-rs/src/converter/utility/content.rs +0 -271
- data/vendor/html-to-markdown-rs/src/converter/utility/mod.rs +0 -17
- data/vendor/html-to-markdown-rs/src/converter/utility/preprocessing.rs +0 -1002
- data/vendor/html-to-markdown-rs/src/converter/utility/serialization.rs +0 -126
- data/vendor/html-to-markdown-rs/src/converter/utility/siblings.rs +0 -97
- data/vendor/html-to-markdown-rs/src/converter/visitor_hooks.rs +0 -189
- data/vendor/html-to-markdown-rs/src/error.rs +0 -43
- data/vendor/html-to-markdown-rs/src/exports.rs +0 -24
- data/vendor/html-to-markdown-rs/src/inline_images.rs +0 -336
- data/vendor/html-to-markdown-rs/src/lib.rs +0 -139
- data/vendor/html-to-markdown-rs/src/metadata/collector.rs +0 -457
- data/vendor/html-to-markdown-rs/src/metadata/config.rs +0 -394
- data/vendor/html-to-markdown-rs/src/metadata/extraction.rs +0 -398
- data/vendor/html-to-markdown-rs/src/metadata/mod.rs +0 -288
- data/vendor/html-to-markdown-rs/src/metadata/types.rs +0 -477
- data/vendor/html-to-markdown-rs/src/options/conversion.rs +0 -559
- data/vendor/html-to-markdown-rs/src/options/inline_image.rs +0 -111
- data/vendor/html-to-markdown-rs/src/options/mod.rs +0 -20
- data/vendor/html-to-markdown-rs/src/options/preprocessing.rs +0 -201
- data/vendor/html-to-markdown-rs/src/options/validation.rs +0 -416
- data/vendor/html-to-markdown-rs/src/prelude.rs +0 -1
- data/vendor/html-to-markdown-rs/src/rcdom.rs +0 -487
- data/vendor/html-to-markdown-rs/src/text.rs +0 -358
- data/vendor/html-to-markdown-rs/src/types/document.rs +0 -191
- data/vendor/html-to-markdown-rs/src/types/mod.rs +0 -17
- data/vendor/html-to-markdown-rs/src/types/result.rs +0 -54
- data/vendor/html-to-markdown-rs/src/types/structure_builder.rs +0 -791
- data/vendor/html-to-markdown-rs/src/types/structure_collector.rs +0 -483
- data/vendor/html-to-markdown-rs/src/types/tables.rs +0 -52
- data/vendor/html-to-markdown-rs/src/types/warnings.rs +0 -33
- data/vendor/html-to-markdown-rs/src/validation.rs +0 -158
- data/vendor/html-to-markdown-rs/src/visitor/default_impl.rs +0 -63
- data/vendor/html-to-markdown-rs/src/visitor/mod.rs +0 -41
- data/vendor/html-to-markdown-rs/src/visitor/traits.rs +0 -370
- data/vendor/html-to-markdown-rs/src/visitor/types.rs +0 -319
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/callbacks/mod.rs +0 -1
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/content.rs +0 -126
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/mod.rs +0 -27
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/state.rs +0 -110
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/traversal.rs +0 -250
- data/vendor/html-to-markdown-rs/src/visitor_helpers.rs +0 -597
- data/vendor/html-to-markdown-rs/src/wrapper/sync.rs +0 -413
- data/vendor/html-to-markdown-rs/src/wrapper/utils.rs +0 -290
- data/vendor/html-to-markdown-rs/src/wrapper.rs +0 -9
- data/vendor/html-to-markdown-rs/tests/br_in_inline_test.rs +0 -87
- data/vendor/html-to-markdown-rs/tests/commonmark_compliance_test.rs +0 -297
- data/vendor/html-to-markdown-rs/tests/djot_output_test.rs +0 -153
- data/vendor/html-to-markdown-rs/tests/exclude_selectors_test.rs +0 -132
- data/vendor/html-to-markdown-rs/tests/integration_test.rs +0 -631
- data/vendor/html-to-markdown-rs/tests/issue_121_regressions.rs +0 -49
- data/vendor/html-to-markdown-rs/tests/issue_127_regressions.rs +0 -58
- data/vendor/html-to-markdown-rs/tests/issue_128_regressions.rs +0 -17
- data/vendor/html-to-markdown-rs/tests/issue_131_regressions.rs +0 -41
- data/vendor/html-to-markdown-rs/tests/issue_134_regressions.rs +0 -40
- data/vendor/html-to-markdown-rs/tests/issue_139_regressions.rs +0 -26
- data/vendor/html-to-markdown-rs/tests/issue_140_regressions.rs +0 -185
- data/vendor/html-to-markdown-rs/tests/issue_143_regressions.rs +0 -100
- data/vendor/html-to-markdown-rs/tests/issue_145_regressions.rs +0 -133
- data/vendor/html-to-markdown-rs/tests/issue_146_regressions.rs +0 -144
- data/vendor/html-to-markdown-rs/tests/issue_176_regressions.rs +0 -62
- data/vendor/html-to-markdown-rs/tests/issue_190_regressions.rs +0 -128
- data/vendor/html-to-markdown-rs/tests/issue_199_regressions.rs +0 -20
- data/vendor/html-to-markdown-rs/tests/issue_200_regressions.rs +0 -62
- data/vendor/html-to-markdown-rs/tests/issue_212_regressions.rs +0 -68
- data/vendor/html-to-markdown-rs/tests/issue_216_217_regressions.rs +0 -87
- data/vendor/html-to-markdown-rs/tests/issue_336_regressions.rs +0 -74
- data/vendor/html-to-markdown-rs/tests/issue_339_regressions.rs +0 -92
- data/vendor/html-to-markdown-rs/tests/issue_347_regressions.rs +0 -154
- data/vendor/html-to-markdown-rs/tests/issue_348_visitor_plain.rs +0 -93
- data/vendor/html-to-markdown-rs/tests/json_ld_script_extraction.rs +0 -44
- data/vendor/html-to-markdown-rs/tests/lists_test.rs +0 -199
- data/vendor/html-to-markdown-rs/tests/plain_output_test.rs +0 -273
- data/vendor/html-to-markdown-rs/tests/preprocessing_tests.rs +0 -61
- data/vendor/html-to-markdown-rs/tests/reference_links_test.rs +0 -169
- data/vendor/html-to-markdown-rs/tests/sectioning_elements_test.rs +0 -137
- data/vendor/html-to-markdown-rs/tests/skip_images_test.rs +0 -522
- data/vendor/html-to-markdown-rs/tests/tables_test.rs +0 -743
- data/vendor/html-to-markdown-rs/tests/test_custom_elements.rs +0 -41
- data/vendor/html-to-markdown-rs/tests/test_issue_187.rs +0 -204
- data/vendor/html-to-markdown-rs/tests/test_issue_218.rs +0 -68
- data/vendor/html-to-markdown-rs/tests/test_issue_277.rs +0 -77
- data/vendor/html-to-markdown-rs/tests/test_max_depth.rs +0 -82
- data/vendor/html-to-markdown-rs/tests/test_nested_simple.rs +0 -45
- data/vendor/html-to-markdown-rs/tests/test_script_style_stripping.rs +0 -396
- data/vendor/html-to-markdown-rs/tests/test_spa_bisect.rs +0 -34
- data/vendor/html-to-markdown-rs/tests/visitor_code_integration_test.rs +0 -121
- data/vendor/html-to-markdown-rs/tests/visitor_integration_test.rs +0 -1190
- data/vendor/html-to-markdown-rs/tests/xml_tables_test.rs +0 -372
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
//! Handlers for HTML5 definition list and heading group elements.
|
|
2
|
-
//!
|
|
3
|
-
//! Processes list and heading semantic elements:
|
|
4
|
-
//! - `<hgroup>` - Groups related headings together
|
|
5
|
-
//! - `<dl>` - Definition list container
|
|
6
|
-
//! - `<dt>` - Definition term
|
|
7
|
-
//! - `<dd>` - Definition description
|
|
8
|
-
//! - `<menu>` - Semantic list (typically unordered)
|
|
9
|
-
//!
|
|
10
|
-
//! These elements have special formatting requirements for proper Markdown output.
|
|
11
|
-
|
|
12
|
-
// Note: Context and DomContext are defined in converter.rs
|
|
13
|
-
// walk_node is also defined there and must be called via the parent module
|
|
14
|
-
use super::walk_node;
|
|
15
|
-
|
|
16
|
-
/// Handles the `<hgroup>` element.
|
|
17
|
-
///
|
|
18
|
-
/// An hgroup element groups related headings together (e.g., a title and subtitle).
|
|
19
|
-
/// In Markdown, we simply process all children sequentially, allowing nested
|
|
20
|
-
/// headings to maintain their individual formatting.
|
|
21
|
-
///
|
|
22
|
-
/// # Behavior
|
|
23
|
-
///
|
|
24
|
-
/// - Children are processed sequentially in the current context
|
|
25
|
-
/// - No special formatting is applied at the hgroup level
|
|
26
|
-
pub fn handle_hgroup(
|
|
27
|
-
_tag_name: &str,
|
|
28
|
-
node_handle: &tl::NodeHandle,
|
|
29
|
-
parser: &tl::Parser,
|
|
30
|
-
output: &mut String,
|
|
31
|
-
options: &crate::options::ConversionOptions,
|
|
32
|
-
ctx: &super::Context,
|
|
33
|
-
depth: usize,
|
|
34
|
-
dom_ctx: &super::DomContext,
|
|
35
|
-
) {
|
|
36
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
37
|
-
let children = tag.children();
|
|
38
|
-
{
|
|
39
|
-
for child_handle in children.top().iter() {
|
|
40
|
-
walk_node(child_handle, parser, output, options, ctx, depth, dom_ctx);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/// Handles the `<dl>` element.
|
|
47
|
-
///
|
|
48
|
-
/// A definition list contains terms and their definitions. Terms and definitions
|
|
49
|
-
/// are output as plain blocks without Pandoc-style colon syntax, since standard
|
|
50
|
-
/// Markdown and GFM do not support definition lists.
|
|
51
|
-
///
|
|
52
|
-
/// # Behavior
|
|
53
|
-
///
|
|
54
|
-
/// - **Inline mode**: Children are processed inline without block spacing
|
|
55
|
-
/// - **Block mode**: Content is collected and wrapped with proper spacing
|
|
56
|
-
pub fn handle_dl(
|
|
57
|
-
_tag_name: &str,
|
|
58
|
-
node_handle: &tl::NodeHandle,
|
|
59
|
-
parser: &tl::Parser,
|
|
60
|
-
output: &mut String,
|
|
61
|
-
options: &crate::options::ConversionOptions,
|
|
62
|
-
ctx: &super::Context,
|
|
63
|
-
depth: usize,
|
|
64
|
-
dom_ctx: &super::DomContext,
|
|
65
|
-
) {
|
|
66
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
67
|
-
// In inline context, just process children inline
|
|
68
|
-
if ctx.convert_as_inline {
|
|
69
|
-
let children = tag.children();
|
|
70
|
-
{
|
|
71
|
-
for child_handle in children.top().iter() {
|
|
72
|
-
walk_node(child_handle, parser, output, options, ctx, depth, dom_ctx);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Collect content from children
|
|
79
|
-
let mut content = String::new();
|
|
80
|
-
let children = tag.children();
|
|
81
|
-
{
|
|
82
|
-
for child_handle in children.top().iter() {
|
|
83
|
-
walk_node(child_handle, parser, &mut content, options, ctx, depth, dom_ctx);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Output collected content with proper spacing
|
|
88
|
-
let trimmed = content.trim();
|
|
89
|
-
if !trimmed.is_empty() {
|
|
90
|
-
if !output.is_empty() && !output.ends_with("\n\n") {
|
|
91
|
-
output.push_str("\n\n");
|
|
92
|
-
}
|
|
93
|
-
output.push_str(trimmed);
|
|
94
|
-
output.push_str("\n\n");
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/// Handles the `<dt>` element.
|
|
100
|
-
///
|
|
101
|
-
/// A dt element contains a term being defined. Terms are output on their own line,
|
|
102
|
-
/// with definitions following on subsequent lines.
|
|
103
|
-
///
|
|
104
|
-
/// # Behavior
|
|
105
|
-
///
|
|
106
|
-
/// - **Inline mode**: Content is output as-is
|
|
107
|
-
/// - **Block mode**: Content is followed by a newline
|
|
108
|
-
pub fn handle_dt(
|
|
109
|
-
_tag_name: &str,
|
|
110
|
-
node_handle: &tl::NodeHandle,
|
|
111
|
-
parser: &tl::Parser,
|
|
112
|
-
output: &mut String,
|
|
113
|
-
options: &crate::options::ConversionOptions,
|
|
114
|
-
ctx: &super::Context,
|
|
115
|
-
depth: usize,
|
|
116
|
-
dom_ctx: &super::DomContext,
|
|
117
|
-
) {
|
|
118
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
119
|
-
let mut content = String::with_capacity(64);
|
|
120
|
-
let children = tag.children();
|
|
121
|
-
{
|
|
122
|
-
for child_handle in children.top().iter() {
|
|
123
|
-
walk_node(child_handle, parser, &mut content, options, ctx, depth + 1, dom_ctx);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
let trimmed = content.trim();
|
|
128
|
-
if !trimmed.is_empty() {
|
|
129
|
-
if ctx.convert_as_inline {
|
|
130
|
-
output.push_str(trimmed);
|
|
131
|
-
} else {
|
|
132
|
-
output.push_str(trimmed);
|
|
133
|
-
output.push('\n');
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/// Handles the `<dd>` element.
|
|
140
|
-
///
|
|
141
|
-
/// A dd element contains the definition for a term. It is output as a plain
|
|
142
|
-
/// block since standard Markdown and GFM do not support definition list syntax.
|
|
143
|
-
///
|
|
144
|
-
/// # Behavior
|
|
145
|
-
///
|
|
146
|
-
/// - **Inline mode**: Content is output as-is
|
|
147
|
-
/// - **Block mode**: Content is output as a block
|
|
148
|
-
pub fn handle_dd(
|
|
149
|
-
_tag_name: &str,
|
|
150
|
-
node_handle: &tl::NodeHandle,
|
|
151
|
-
parser: &tl::Parser,
|
|
152
|
-
output: &mut String,
|
|
153
|
-
options: &crate::options::ConversionOptions,
|
|
154
|
-
ctx: &super::Context,
|
|
155
|
-
depth: usize,
|
|
156
|
-
dom_ctx: &super::DomContext,
|
|
157
|
-
) {
|
|
158
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
159
|
-
let mut content = String::with_capacity(128);
|
|
160
|
-
let children = tag.children();
|
|
161
|
-
{
|
|
162
|
-
for child_handle in children.top().iter() {
|
|
163
|
-
walk_node(child_handle, parser, &mut content, options, ctx, depth + 1, dom_ctx);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
let trimmed = content.trim();
|
|
168
|
-
|
|
169
|
-
if ctx.convert_as_inline {
|
|
170
|
-
if !trimmed.is_empty() {
|
|
171
|
-
output.push_str(trimmed);
|
|
172
|
-
}
|
|
173
|
-
} else if !trimmed.is_empty() {
|
|
174
|
-
output.push_str(trimmed);
|
|
175
|
-
output.push_str("\n\n");
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/// Handles the `<menu>` element.
|
|
181
|
-
///
|
|
182
|
-
/// A menu element is a semantic list, typically used for command menus or
|
|
183
|
-
/// navigation. It is rendered as an unordered list with dashes.
|
|
184
|
-
///
|
|
185
|
-
/// # Behavior
|
|
186
|
-
///
|
|
187
|
-
/// - **Inline mode**: Children are processed inline without list formatting
|
|
188
|
-
/// - **Block mode**: Content is rendered as an unordered list
|
|
189
|
-
/// - Uses `-` as the list bullet (overrides configured bullets)
|
|
190
|
-
/// - Proper blank-line spacing is maintained
|
|
191
|
-
pub fn handle_menu(
|
|
192
|
-
_tag_name: &str,
|
|
193
|
-
node_handle: &tl::NodeHandle,
|
|
194
|
-
parser: &tl::Parser,
|
|
195
|
-
output: &mut String,
|
|
196
|
-
options: &crate::options::ConversionOptions,
|
|
197
|
-
ctx: &super::Context,
|
|
198
|
-
depth: usize,
|
|
199
|
-
dom_ctx: &super::DomContext,
|
|
200
|
-
) {
|
|
201
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
202
|
-
let content_start = output.len();
|
|
203
|
-
|
|
204
|
-
// Create options with menu-specific bullet style
|
|
205
|
-
let menu_options = crate::options::ConversionOptions {
|
|
206
|
-
bullets: "-".to_string(),
|
|
207
|
-
..options.clone()
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
// Create context for list rendering
|
|
211
|
-
let list_ctx = super::Context {
|
|
212
|
-
in_ordered_list: false,
|
|
213
|
-
list_counter: 0,
|
|
214
|
-
in_list: true,
|
|
215
|
-
list_depth: ctx.list_depth,
|
|
216
|
-
..ctx.clone()
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
let children = tag.children();
|
|
220
|
-
{
|
|
221
|
-
for child_handle in children.top().iter() {
|
|
222
|
-
walk_node(child_handle, parser, output, &menu_options, &list_ctx, depth, dom_ctx);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Ensure proper spacing after menu
|
|
227
|
-
if !ctx.convert_as_inline && output.len() > content_start {
|
|
228
|
-
if !output.ends_with("\n\n") {
|
|
229
|
-
if output.ends_with('\n') {
|
|
230
|
-
output.push('\n');
|
|
231
|
-
} else {
|
|
232
|
-
output.push_str("\n\n");
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
} else if ctx.convert_as_inline {
|
|
236
|
-
// In inline mode, remove trailing newlines
|
|
237
|
-
while output.ends_with('\n') {
|
|
238
|
-
output.pop();
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/// Dispatcher for definition list and related elements.
|
|
245
|
-
///
|
|
246
|
-
/// Routes `<hgroup>`, `<dl>`, `<dt>`, `<dd>`, and `<menu>` elements
|
|
247
|
-
/// to their respective handlers.
|
|
248
|
-
pub fn handle(
|
|
249
|
-
tag_name: &str,
|
|
250
|
-
node_handle: &tl::NodeHandle,
|
|
251
|
-
parser: &tl::Parser,
|
|
252
|
-
output: &mut String,
|
|
253
|
-
options: &crate::options::ConversionOptions,
|
|
254
|
-
ctx: &super::Context,
|
|
255
|
-
depth: usize,
|
|
256
|
-
dom_ctx: &super::DomContext,
|
|
257
|
-
) {
|
|
258
|
-
match tag_name {
|
|
259
|
-
"hgroup" => handle_hgroup(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
260
|
-
"dl" => handle_dl(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
261
|
-
"dt" => handle_dt(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
262
|
-
"dd" => handle_dd(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
263
|
-
"menu" => handle_menu(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
264
|
-
_ => {}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
@@ -1,391 +0,0 @@
|
|
|
1
|
-
//! Handlers for HTML5 figure elements.
|
|
2
|
-
//!
|
|
3
|
-
//! Processes figure-related semantic elements:
|
|
4
|
-
//! - `<figure>` - Self-contained illustration, diagram, photo, code listing, etc.
|
|
5
|
-
//! - `<figcaption>` - Caption or legend for a figure
|
|
6
|
-
//!
|
|
7
|
-
//! Figure elements group an image (or other media) with its associated caption.
|
|
8
|
-
//! The Markdown output preserves this relationship through content organization.
|
|
9
|
-
|
|
10
|
-
// Note: Context and DomContext are defined in converter.rs
|
|
11
|
-
// walk_node is also defined there and must be called via the parent module
|
|
12
|
-
|
|
13
|
-
/// Handles the `<figure>` element.
|
|
14
|
-
///
|
|
15
|
-
/// A figure element contains content (typically images) and optionally a figcaption.
|
|
16
|
-
/// The handler collects all content and cleans up extra line breaks.
|
|
17
|
-
///
|
|
18
|
-
/// # Behavior
|
|
19
|
-
///
|
|
20
|
-
/// - **Inline mode**: Children are processed inline without block spacing
|
|
21
|
-
/// - **Block mode**: Content is collected, line breaks normalized, and wrapped with blank lines
|
|
22
|
-
/// - **Image normalization**: Removes extra spaces before `![` to improve Markdown formatting
|
|
23
|
-
///
|
|
24
|
-
/// # Implementation Details
|
|
25
|
-
///
|
|
26
|
-
/// The handler performs the following on the collected content:
|
|
27
|
-
/// 1. Normalizes newline + image sequences: `\n![` → `![`
|
|
28
|
-
/// 2. Normalizes space + image sequences: ` ![` → `![`
|
|
29
|
-
/// 3. Trims the final content and wraps it with blank lines
|
|
30
|
-
#[cfg_attr(not(feature = "visitor"), allow(unused_variables))]
|
|
31
|
-
pub fn handle_figure(
|
|
32
|
-
_tag_name: &str,
|
|
33
|
-
node_handle: &tl::NodeHandle,
|
|
34
|
-
parser: &tl::Parser,
|
|
35
|
-
output: &mut String,
|
|
36
|
-
options: &crate::options::ConversionOptions,
|
|
37
|
-
ctx: &super::Context,
|
|
38
|
-
depth: usize,
|
|
39
|
-
dom_ctx: &super::DomContext,
|
|
40
|
-
) {
|
|
41
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
42
|
-
// In inline context, just process children inline
|
|
43
|
-
if ctx.convert_as_inline {
|
|
44
|
-
let children = tag.children();
|
|
45
|
-
{
|
|
46
|
-
for child_handle in children.top().iter() {
|
|
47
|
-
super::walk_node(child_handle, parser, output, options, ctx, depth, dom_ctx);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Check visit_figure_start before processing children.
|
|
54
|
-
#[cfg(feature = "visitor")]
|
|
55
|
-
if let Some(ref visitor_handle) = ctx.visitor {
|
|
56
|
-
use crate::converter::utility::content::collect_tag_attributes;
|
|
57
|
-
use crate::visitor::{NodeContext, NodeType, VisitResult};
|
|
58
|
-
|
|
59
|
-
let attributes = collect_tag_attributes(tag);
|
|
60
|
-
let node_id = node_handle.get_inner();
|
|
61
|
-
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
|
|
62
|
-
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
|
|
63
|
-
let node_ctx = NodeContext {
|
|
64
|
-
node_type: NodeType::Figure,
|
|
65
|
-
tag_name: "figure".to_string(),
|
|
66
|
-
attributes,
|
|
67
|
-
depth,
|
|
68
|
-
index_in_parent,
|
|
69
|
-
parent_tag,
|
|
70
|
-
is_inline: false,
|
|
71
|
-
};
|
|
72
|
-
let visit_result = {
|
|
73
|
-
let mut visitor = visitor_handle.borrow_mut();
|
|
74
|
-
visitor.visit_figure_start(&node_ctx)
|
|
75
|
-
};
|
|
76
|
-
match visit_result {
|
|
77
|
-
VisitResult::Continue => {}
|
|
78
|
-
VisitResult::Skip => return,
|
|
79
|
-
VisitResult::Custom(custom) => {
|
|
80
|
-
// Record where custom content starts so visit_figure_end can see it
|
|
81
|
-
let start_pos = output.len();
|
|
82
|
-
if !output.is_empty() && !output.ends_with("\n\n") {
|
|
83
|
-
output.push_str("\n\n");
|
|
84
|
-
}
|
|
85
|
-
output.push_str(&custom);
|
|
86
|
-
// Still call visit_figure_end with the custom content
|
|
87
|
-
let safe_start = start_pos.min(output.len());
|
|
88
|
-
let figure_output = output[safe_start..].to_owned();
|
|
89
|
-
let end_result = {
|
|
90
|
-
let mut visitor = visitor_handle.borrow_mut();
|
|
91
|
-
visitor.visit_figure_end(&node_ctx, &figure_output)
|
|
92
|
-
};
|
|
93
|
-
match end_result {
|
|
94
|
-
VisitResult::Continue => {
|
|
95
|
-
if !output.ends_with('\n') {
|
|
96
|
-
output.push_str("\n\n");
|
|
97
|
-
} else if !output.ends_with("\n\n") {
|
|
98
|
-
output.push('\n');
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
VisitResult::Custom(end_custom) => {
|
|
102
|
-
output.truncate(safe_start);
|
|
103
|
-
output.push_str(&end_custom);
|
|
104
|
-
}
|
|
105
|
-
VisitResult::Skip => {
|
|
106
|
-
output.truncate(safe_start);
|
|
107
|
-
}
|
|
108
|
-
VisitResult::PreserveHtml => {
|
|
109
|
-
use crate::converter::utility::serialization::serialize_node;
|
|
110
|
-
output.truncate(safe_start);
|
|
111
|
-
output.push_str(&serialize_node(node_handle, parser));
|
|
112
|
-
}
|
|
113
|
-
VisitResult::Error(err) => {
|
|
114
|
-
if ctx.visitor_error.borrow().is_none() {
|
|
115
|
-
*ctx.visitor_error.borrow_mut() = Some(err);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
VisitResult::PreserveHtml => {
|
|
122
|
-
use crate::converter::utility::serialization::serialize_node;
|
|
123
|
-
output.push_str(&serialize_node(node_handle, parser));
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
VisitResult::Error(err) => {
|
|
127
|
-
if ctx.visitor_error.borrow().is_none() {
|
|
128
|
-
*ctx.visitor_error.borrow_mut() = Some(err);
|
|
129
|
-
}
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Ensure spacing before the figure
|
|
136
|
-
if !output.is_empty() && !output.ends_with("\n\n") {
|
|
137
|
-
output.push_str("\n\n");
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
let figure_start = output.len();
|
|
141
|
-
|
|
142
|
-
// Collect content in a separate buffer
|
|
143
|
-
let mut figure_content = String::new();
|
|
144
|
-
let children = tag.children();
|
|
145
|
-
{
|
|
146
|
-
for child_handle in children.top().iter() {
|
|
147
|
-
super::walk_node(child_handle, parser, &mut figure_content, options, ctx, depth, dom_ctx);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Normalize image syntax
|
|
152
|
-
figure_content = figure_content.replace("\n![", "![");
|
|
153
|
-
figure_content = figure_content.replace(" ![", "![");
|
|
154
|
-
|
|
155
|
-
// Trim and output
|
|
156
|
-
let trimmed = figure_content.trim_matches(|c| c == '\n' || c == ' ' || c == '\t');
|
|
157
|
-
if !trimmed.is_empty() {
|
|
158
|
-
output.push_str(trimmed);
|
|
159
|
-
if !output.ends_with('\n') {
|
|
160
|
-
output.push('\n');
|
|
161
|
-
}
|
|
162
|
-
if !output.ends_with("\n\n") {
|
|
163
|
-
output.push('\n');
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Call visit_figure_end after collecting content.
|
|
168
|
-
#[cfg(feature = "visitor")]
|
|
169
|
-
if let Some(ref visitor_handle) = ctx.visitor {
|
|
170
|
-
use crate::converter::utility::content::collect_tag_attributes;
|
|
171
|
-
use crate::visitor::{NodeContext, NodeType, VisitResult};
|
|
172
|
-
|
|
173
|
-
let attributes = collect_tag_attributes(tag);
|
|
174
|
-
let node_id = node_handle.get_inner();
|
|
175
|
-
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
|
|
176
|
-
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
|
|
177
|
-
let node_ctx = NodeContext {
|
|
178
|
-
node_type: NodeType::Figure,
|
|
179
|
-
tag_name: "figure".to_string(),
|
|
180
|
-
attributes,
|
|
181
|
-
depth,
|
|
182
|
-
index_in_parent,
|
|
183
|
-
parent_tag,
|
|
184
|
-
is_inline: false,
|
|
185
|
-
};
|
|
186
|
-
let safe_start = figure_start.min(output.len());
|
|
187
|
-
let figure_output = output[safe_start..].to_owned();
|
|
188
|
-
let visit_result = {
|
|
189
|
-
let mut visitor = visitor_handle.borrow_mut();
|
|
190
|
-
visitor.visit_figure_end(&node_ctx, &figure_output)
|
|
191
|
-
};
|
|
192
|
-
match visit_result {
|
|
193
|
-
VisitResult::Continue => {}
|
|
194
|
-
VisitResult::Skip => {
|
|
195
|
-
output.truncate(safe_start);
|
|
196
|
-
}
|
|
197
|
-
VisitResult::Custom(custom) => {
|
|
198
|
-
output.truncate(safe_start);
|
|
199
|
-
output.push_str(&custom);
|
|
200
|
-
}
|
|
201
|
-
VisitResult::PreserveHtml => {
|
|
202
|
-
use crate::converter::utility::serialization::serialize_node;
|
|
203
|
-
output.truncate(safe_start);
|
|
204
|
-
output.push_str(&serialize_node(node_handle, parser));
|
|
205
|
-
}
|
|
206
|
-
VisitResult::Error(err) => {
|
|
207
|
-
if ctx.visitor_error.borrow().is_none() {
|
|
208
|
-
*ctx.visitor_error.borrow_mut() = Some(err);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/// Handles the `<figcaption>` element.
|
|
217
|
-
///
|
|
218
|
-
/// A figcaption element contains text that describes or supplements the figure.
|
|
219
|
-
/// It is rendered as emphasized (italic) text to distinguish it from regular content.
|
|
220
|
-
///
|
|
221
|
-
/// # Behavior
|
|
222
|
-
///
|
|
223
|
-
/// - Content is collected and trimmed
|
|
224
|
-
/// - Non-empty content is wrapped in `*text*` (emphasis) markers
|
|
225
|
-
/// - Proper spacing is maintained around the caption
|
|
226
|
-
///
|
|
227
|
-
/// # Implementation Details
|
|
228
|
-
///
|
|
229
|
-
/// The handler:
|
|
230
|
-
/// 1. Collects and processes all children
|
|
231
|
-
/// 2. Checks for existing output and adds spacing as needed
|
|
232
|
-
/// 3. Wraps content in emphasis markers: `*caption*`
|
|
233
|
-
/// 4. Ensures proper blank-line spacing after the caption
|
|
234
|
-
#[cfg_attr(not(feature = "visitor"), allow(unused_variables))]
|
|
235
|
-
pub fn handle_figcaption(
|
|
236
|
-
_tag_name: &str,
|
|
237
|
-
node_handle: &tl::NodeHandle,
|
|
238
|
-
parser: &tl::Parser,
|
|
239
|
-
output: &mut String,
|
|
240
|
-
options: &crate::options::ConversionOptions,
|
|
241
|
-
ctx: &super::Context,
|
|
242
|
-
depth: usize,
|
|
243
|
-
dom_ctx: &super::DomContext,
|
|
244
|
-
) {
|
|
245
|
-
if let Some(tl::Node::Tag(tag)) = node_handle.get(parser) {
|
|
246
|
-
let mut text = String::new();
|
|
247
|
-
let children = tag.children();
|
|
248
|
-
{
|
|
249
|
-
for child_handle in children.top().iter() {
|
|
250
|
-
super::walk_node(child_handle, parser, &mut text, options, ctx, depth + 1, dom_ctx);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
let text = text.trim().to_owned();
|
|
255
|
-
if text.is_empty() {
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
#[cfg(feature = "visitor")]
|
|
260
|
-
if let Some(ref visitor_handle) = ctx.visitor {
|
|
261
|
-
use crate::converter::utility::content::collect_tag_attributes;
|
|
262
|
-
use crate::visitor::{NodeContext, NodeType, VisitResult};
|
|
263
|
-
|
|
264
|
-
let attributes = collect_tag_attributes(tag);
|
|
265
|
-
let node_id = node_handle.get_inner();
|
|
266
|
-
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
|
|
267
|
-
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
|
|
268
|
-
let node_ctx = NodeContext {
|
|
269
|
-
node_type: NodeType::Figcaption,
|
|
270
|
-
tag_name: "figcaption".to_string(),
|
|
271
|
-
attributes,
|
|
272
|
-
depth,
|
|
273
|
-
index_in_parent,
|
|
274
|
-
parent_tag,
|
|
275
|
-
is_inline: false,
|
|
276
|
-
};
|
|
277
|
-
let visit_result = {
|
|
278
|
-
let mut visitor = visitor_handle.borrow_mut();
|
|
279
|
-
visitor.visit_figcaption(&node_ctx, &text)
|
|
280
|
-
};
|
|
281
|
-
match visit_result {
|
|
282
|
-
VisitResult::Continue => {}
|
|
283
|
-
VisitResult::Skip => return,
|
|
284
|
-
VisitResult::Custom(custom) => {
|
|
285
|
-
// Add spacing before caption if needed
|
|
286
|
-
if !output.is_empty() {
|
|
287
|
-
if output.ends_with("```\n") {
|
|
288
|
-
output.push('\n');
|
|
289
|
-
} else {
|
|
290
|
-
while output.ends_with(' ') || output.ends_with('\t') {
|
|
291
|
-
output.pop();
|
|
292
|
-
}
|
|
293
|
-
if output.ends_with('\n') && !output.ends_with("\n\n") {
|
|
294
|
-
output.push('\n');
|
|
295
|
-
} else if !output.ends_with('\n') {
|
|
296
|
-
output.push_str("\n\n");
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
output.push_str(&custom);
|
|
301
|
-
if !custom.ends_with('\n') {
|
|
302
|
-
output.push_str("\n\n");
|
|
303
|
-
}
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
VisitResult::PreserveHtml => {
|
|
307
|
-
use crate::converter::utility::serialization::serialize_node;
|
|
308
|
-
output.push_str(&serialize_node(node_handle, parser));
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
VisitResult::Error(err) => {
|
|
312
|
-
if ctx.visitor_error.borrow().is_none() {
|
|
313
|
-
*ctx.visitor_error.borrow_mut() = Some(err);
|
|
314
|
-
}
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// Add spacing before caption if needed
|
|
321
|
-
if !output.is_empty() {
|
|
322
|
-
if output.ends_with("```\n") {
|
|
323
|
-
output.push('\n');
|
|
324
|
-
} else {
|
|
325
|
-
// Trim trailing whitespace and ensure single blank line
|
|
326
|
-
while output.ends_with(' ') || output.ends_with('\t') {
|
|
327
|
-
output.pop();
|
|
328
|
-
}
|
|
329
|
-
if output.ends_with('\n') && !output.ends_with("\n\n") {
|
|
330
|
-
output.push('\n');
|
|
331
|
-
} else if !output.ends_with('\n') {
|
|
332
|
-
output.push_str("\n\n");
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// Output caption as emphasized text
|
|
338
|
-
output.push('*');
|
|
339
|
-
output.push_str(&text);
|
|
340
|
-
output.push_str("*\n\n");
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/// Dispatcher for figure-related elements.
|
|
345
|
-
///
|
|
346
|
-
/// Routes `<figure>` and `<figcaption>` elements to their respective handlers.
|
|
347
|
-
pub fn handle(
|
|
348
|
-
tag_name: &str,
|
|
349
|
-
node_handle: &tl::NodeHandle,
|
|
350
|
-
parser: &tl::Parser,
|
|
351
|
-
output: &mut String,
|
|
352
|
-
options: &crate::options::ConversionOptions,
|
|
353
|
-
ctx: &super::Context,
|
|
354
|
-
depth: usize,
|
|
355
|
-
dom_ctx: &super::DomContext,
|
|
356
|
-
) {
|
|
357
|
-
match tag_name {
|
|
358
|
-
"figure" => handle_figure(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
359
|
-
"figcaption" => handle_figcaption(tag_name, node_handle, parser, output, options, ctx, depth, dom_ctx),
|
|
360
|
-
_ => {}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
#[cfg(test)]
|
|
365
|
-
mod tests {
|
|
366
|
-
#[test]
|
|
367
|
-
fn figure_caption_separated_from_image() {
|
|
368
|
-
let html = r#"<figure><img src="photo.jpg" alt="Photo"><figcaption>A nice photo</figcaption></figure>"#;
|
|
369
|
-
let result = crate::convert(html, None).unwrap();
|
|
370
|
-
let content = result.content.unwrap_or_default();
|
|
371
|
-
assert!(
|
|
372
|
-
content.contains(""),
|
|
373
|
-
"image should be present: {}",
|
|
374
|
-
content
|
|
375
|
-
);
|
|
376
|
-
assert!(
|
|
377
|
-
content.contains("A nice photo"),
|
|
378
|
-
"caption should be present: {}",
|
|
379
|
-
content
|
|
380
|
-
);
|
|
381
|
-
// Image and caption should not be on the same line
|
|
382
|
-
let lines: Vec<&str> = content.lines().filter(|l| !l.trim().is_empty()).collect();
|
|
383
|
-
let img_line = lines.iter().position(|l| l.contains("![")).unwrap_or(999);
|
|
384
|
-
let cap_line = lines.iter().position(|l| l.contains("A nice photo")).unwrap_or(999);
|
|
385
|
-
assert!(
|
|
386
|
-
cap_line > img_line,
|
|
387
|
-
"caption should be on a separate line after image, lines: {:?}",
|
|
388
|
-
lines
|
|
389
|
-
);
|
|
390
|
-
}
|
|
391
|
-
}
|