html-to-markdown 3.4.0 → 3.6.0.pre.rc.24
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,434 +0,0 @@
|
|
|
1
|
-
//! Code and pre element handlers for HTML to Markdown conversion.
|
|
2
|
-
//!
|
|
3
|
-
//! Handles `<code>` and `<pre>` elements including:
|
|
4
|
-
//! - Inline code with backtick formatting
|
|
5
|
-
//! - Code block formatting (indented or fenced)
|
|
6
|
-
//! - Language detection from class attributes
|
|
7
|
-
//! - Whitespace normalization and dedenting
|
|
8
|
-
//! - Visitor callback integration
|
|
9
|
-
|
|
10
|
-
use crate::converter::Context;
|
|
11
|
-
use crate::converter::dom_context::DomContext;
|
|
12
|
-
use crate::converter::main::walk_node;
|
|
13
|
-
use crate::converter::text::dedent_code_block;
|
|
14
|
-
use crate::options::ConversionOptions;
|
|
15
|
-
|
|
16
|
-
#[cfg(feature = "visitor")]
|
|
17
|
-
#[cfg(feature = "visitor")]
|
|
18
|
-
use crate::converter::utility::content::collect_tag_attributes;
|
|
19
|
-
#[cfg(feature = "visitor")]
|
|
20
|
-
use std::collections::BTreeMap;
|
|
21
|
-
|
|
22
|
-
#[cfg(feature = "visitor")]
|
|
23
|
-
use crate::converter::utility::serialization::serialize_node;
|
|
24
|
-
|
|
25
|
-
/// Handle an inline `<code>` element and convert to Markdown.
|
|
26
|
-
///
|
|
27
|
-
/// This handler processes inline code elements including:
|
|
28
|
-
/// - Extracting code content and applying backtick delimiters
|
|
29
|
-
/// - Handling backticks in content by using multiple delimiters
|
|
30
|
-
/// - Invoking visitor callbacks when the visitor feature is enabled
|
|
31
|
-
/// - Generating appropriate markdown output with proper escaping
|
|
32
|
-
#[allow(clippy::too_many_arguments)]
|
|
33
|
-
#[allow(clippy::too_many_lines)]
|
|
34
|
-
#[cfg_attr(not(feature = "visitor"), allow(unused_variables))]
|
|
35
|
-
pub fn handle_code(
|
|
36
|
-
node_handle: &tl::NodeHandle,
|
|
37
|
-
tag: &tl::HTMLTag,
|
|
38
|
-
parser: &tl::Parser,
|
|
39
|
-
output: &mut String,
|
|
40
|
-
options: &ConversionOptions,
|
|
41
|
-
ctx: &Context,
|
|
42
|
-
depth: usize,
|
|
43
|
-
dom_ctx: &DomContext,
|
|
44
|
-
) {
|
|
45
|
-
let code_ctx = Context {
|
|
46
|
-
in_code: true,
|
|
47
|
-
..ctx.clone()
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
if ctx.in_code {
|
|
51
|
-
let children = tag.children();
|
|
52
|
-
{
|
|
53
|
-
for child_handle in children.top().iter() {
|
|
54
|
-
walk_node(child_handle, parser, output, options, &code_ctx, depth + 1, dom_ctx);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
} else {
|
|
58
|
-
let mut content = String::with_capacity(32);
|
|
59
|
-
let children = tag.children();
|
|
60
|
-
{
|
|
61
|
-
for child_handle in children.top().iter() {
|
|
62
|
-
walk_node(
|
|
63
|
-
child_handle,
|
|
64
|
-
parser,
|
|
65
|
-
&mut content,
|
|
66
|
-
options,
|
|
67
|
-
&code_ctx,
|
|
68
|
-
depth + 1,
|
|
69
|
-
dom_ctx,
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
let trimmed = &content;
|
|
75
|
-
|
|
76
|
-
if !content.trim().is_empty() {
|
|
77
|
-
#[cfg(feature = "visitor")]
|
|
78
|
-
let code_output = if let Some(ref visitor_handle) = ctx.visitor {
|
|
79
|
-
use crate::visitor::{NodeContext, NodeType, VisitResult};
|
|
80
|
-
|
|
81
|
-
let attributes: BTreeMap<String, String> = collect_tag_attributes(tag);
|
|
82
|
-
|
|
83
|
-
let node_id = node_handle.get_inner();
|
|
84
|
-
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
|
|
85
|
-
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
|
|
86
|
-
|
|
87
|
-
let node_ctx = NodeContext {
|
|
88
|
-
node_type: NodeType::Code,
|
|
89
|
-
tag_name: "code".to_string(),
|
|
90
|
-
attributes,
|
|
91
|
-
depth,
|
|
92
|
-
index_in_parent,
|
|
93
|
-
parent_tag,
|
|
94
|
-
is_inline: true,
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
let visit_result = {
|
|
98
|
-
let mut visitor = visitor_handle.borrow_mut();
|
|
99
|
-
visitor.visit_code_inline(&node_ctx, trimmed)
|
|
100
|
-
};
|
|
101
|
-
match visit_result {
|
|
102
|
-
VisitResult::Continue => None,
|
|
103
|
-
VisitResult::Custom(custom) => Some(custom),
|
|
104
|
-
VisitResult::Skip => Some(String::new()),
|
|
105
|
-
VisitResult::PreserveHtml => Some(serialize_node(node_handle, parser)),
|
|
106
|
-
VisitResult::Error(err) => {
|
|
107
|
-
if ctx.visitor_error.borrow().is_none() {
|
|
108
|
-
*ctx.visitor_error.borrow_mut() = Some(err);
|
|
109
|
-
}
|
|
110
|
-
None
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
} else {
|
|
114
|
-
None
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
#[cfg(feature = "visitor")]
|
|
118
|
-
if let Some(custom_output) = code_output {
|
|
119
|
-
output.push_str(&custom_output);
|
|
120
|
-
} else {
|
|
121
|
-
format_inline_code(trimmed, output);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
#[cfg(not(feature = "visitor"))]
|
|
125
|
-
{
|
|
126
|
-
format_inline_code(trimmed, output);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/// Handle a `<pre>` element and convert to Markdown.
|
|
133
|
-
///
|
|
134
|
-
/// This handler processes code block elements including:
|
|
135
|
-
/// - Extracting language information from class attributes
|
|
136
|
-
/// - Processing whitespace and dedenting code content
|
|
137
|
-
/// - Supporting multiple code block styles (indented, backticks, tildes)
|
|
138
|
-
/// - Invoking visitor callbacks when the visitor feature is enabled
|
|
139
|
-
/// - Generating appropriate markdown output
|
|
140
|
-
#[allow(clippy::too_many_arguments)]
|
|
141
|
-
#[allow(clippy::too_many_lines)]
|
|
142
|
-
#[cfg_attr(not(feature = "visitor"), allow(unused_variables))]
|
|
143
|
-
pub fn handle_pre(
|
|
144
|
-
node_handle: &tl::NodeHandle,
|
|
145
|
-
tag: &tl::HTMLTag,
|
|
146
|
-
parser: &tl::Parser,
|
|
147
|
-
output: &mut String,
|
|
148
|
-
options: &ConversionOptions,
|
|
149
|
-
ctx: &Context,
|
|
150
|
-
depth: usize,
|
|
151
|
-
dom_ctx: &DomContext,
|
|
152
|
-
) {
|
|
153
|
-
let code_ctx = Context {
|
|
154
|
-
in_code: true,
|
|
155
|
-
..ctx.clone()
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
#[cfg_attr(not(feature = "visitor"), allow(unused_variables))]
|
|
159
|
-
let language: Option<String> = {
|
|
160
|
-
let mut lang: Option<String> = None;
|
|
161
|
-
|
|
162
|
-
// First, try to extract language from <pre> tag's class attribute
|
|
163
|
-
if let Some(class_attr) = tag.attributes().get("class") {
|
|
164
|
-
if let Some(class_bytes) = class_attr {
|
|
165
|
-
let class_str = class_bytes.as_utf8_str();
|
|
166
|
-
for cls in class_str.split_whitespace() {
|
|
167
|
-
if let Some(stripped) = cls.strip_prefix("language-") {
|
|
168
|
-
lang = Some(String::from(stripped));
|
|
169
|
-
break;
|
|
170
|
-
} else if let Some(stripped) = cls.strip_prefix("lang-") {
|
|
171
|
-
lang = Some(String::from(stripped));
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// If not found on <pre>, try to extract from nested <code> tag's class attribute
|
|
179
|
-
if lang.is_none() {
|
|
180
|
-
let children = tag.children();
|
|
181
|
-
for child_handle in children.top().iter() {
|
|
182
|
-
if let Some(tl::Node::Tag(child_tag)) = child_handle.get(parser) {
|
|
183
|
-
if child_tag.name() == "code" {
|
|
184
|
-
if let Some(class_attr) = child_tag.attributes().get("class") {
|
|
185
|
-
if let Some(class_bytes) = class_attr {
|
|
186
|
-
let class_str = class_bytes.as_utf8_str();
|
|
187
|
-
for cls in class_str.split_whitespace() {
|
|
188
|
-
if let Some(stripped) = cls.strip_prefix("language-") {
|
|
189
|
-
lang = Some(String::from(stripped));
|
|
190
|
-
break;
|
|
191
|
-
} else if let Some(stripped) = cls.strip_prefix("lang-") {
|
|
192
|
-
lang = Some(String::from(stripped));
|
|
193
|
-
break;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
break;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
lang
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
let mut content = String::with_capacity(256);
|
|
208
|
-
let children = tag.children();
|
|
209
|
-
{
|
|
210
|
-
for child_handle in children.top().iter() {
|
|
211
|
-
walk_node(
|
|
212
|
-
child_handle,
|
|
213
|
-
parser,
|
|
214
|
-
&mut content,
|
|
215
|
-
options,
|
|
216
|
-
&code_ctx,
|
|
217
|
-
depth + 1,
|
|
218
|
-
dom_ctx,
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if !content.is_empty() {
|
|
224
|
-
let leading_newlines = content.chars().take_while(|&c| c == '\n').count();
|
|
225
|
-
let trailing_newlines = content.chars().rev().take_while(|&c| c == '\n').count();
|
|
226
|
-
let core = content.trim_matches('\n');
|
|
227
|
-
let is_whitespace_only = core.trim().is_empty();
|
|
228
|
-
|
|
229
|
-
let processed_content = if options.whitespace_mode == crate::options::WhitespaceMode::Strict {
|
|
230
|
-
content
|
|
231
|
-
} else {
|
|
232
|
-
// Always dedent code blocks to remove common leading whitespace
|
|
233
|
-
let mut core_text = dedent_code_block(core);
|
|
234
|
-
|
|
235
|
-
if is_whitespace_only {
|
|
236
|
-
let mut rebuilt = String::new();
|
|
237
|
-
for _ in 0..leading_newlines {
|
|
238
|
-
rebuilt.push('\n');
|
|
239
|
-
}
|
|
240
|
-
rebuilt.push_str(&core_text);
|
|
241
|
-
for _ in 0..trailing_newlines {
|
|
242
|
-
rebuilt.push('\n');
|
|
243
|
-
}
|
|
244
|
-
rebuilt
|
|
245
|
-
} else {
|
|
246
|
-
for _ in 0..trailing_newlines {
|
|
247
|
-
core_text.push('\n');
|
|
248
|
-
}
|
|
249
|
-
core_text
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
#[cfg(feature = "visitor")]
|
|
254
|
-
let code_block_output = if let Some(ref visitor_handle) = ctx.visitor {
|
|
255
|
-
use crate::visitor::{NodeContext, NodeType, VisitResult};
|
|
256
|
-
|
|
257
|
-
let attributes: BTreeMap<String, String> = collect_tag_attributes(tag);
|
|
258
|
-
|
|
259
|
-
let node_id = node_handle.get_inner();
|
|
260
|
-
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
|
|
261
|
-
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
|
|
262
|
-
|
|
263
|
-
let node_ctx = NodeContext {
|
|
264
|
-
node_type: NodeType::Pre,
|
|
265
|
-
tag_name: "pre".to_string(),
|
|
266
|
-
attributes,
|
|
267
|
-
depth,
|
|
268
|
-
index_in_parent,
|
|
269
|
-
parent_tag,
|
|
270
|
-
is_inline: false,
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
let visit_result = {
|
|
274
|
-
let mut visitor = visitor_handle.borrow_mut();
|
|
275
|
-
visitor.visit_code_block(&node_ctx, language.as_deref(), &processed_content)
|
|
276
|
-
};
|
|
277
|
-
match visit_result {
|
|
278
|
-
VisitResult::Continue => None,
|
|
279
|
-
VisitResult::Custom(custom) => Some(custom),
|
|
280
|
-
VisitResult::Skip => Some(String::new()),
|
|
281
|
-
VisitResult::PreserveHtml => Some(serialize_node(node_handle, parser)),
|
|
282
|
-
VisitResult::Error(err) => {
|
|
283
|
-
if ctx.visitor_error.borrow().is_none() {
|
|
284
|
-
*ctx.visitor_error.borrow_mut() = Some(err);
|
|
285
|
-
}
|
|
286
|
-
None
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
} else {
|
|
290
|
-
None
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
#[cfg(feature = "visitor")]
|
|
294
|
-
if let Some(custom_output) = code_block_output {
|
|
295
|
-
output.push_str(&custom_output);
|
|
296
|
-
} else {
|
|
297
|
-
format_code_block(&processed_content, language.as_deref(), output, options, ctx);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
#[cfg(not(feature = "visitor"))]
|
|
301
|
-
{
|
|
302
|
-
format_code_block(&processed_content, language.as_deref(), output, options, ctx);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
if let Some(ref sc) = ctx.structure_collector {
|
|
306
|
-
sc.borrow_mut().push_code(&processed_content, language.as_deref());
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/// Format inline code with appropriate backtick delimiters.
|
|
312
|
-
///
|
|
313
|
-
/// Handles:
|
|
314
|
-
/// - Single backticks for normal content
|
|
315
|
-
/// - Double backticks when content contains backticks
|
|
316
|
-
/// - Space padding when needed to avoid backtick adjacency
|
|
317
|
-
fn format_inline_code(content: &str, output: &mut String) {
|
|
318
|
-
let contains_backtick = content.contains('`');
|
|
319
|
-
|
|
320
|
-
let needs_delimiter_spaces = {
|
|
321
|
-
let first_char = content.chars().next();
|
|
322
|
-
let last_char = content.chars().last();
|
|
323
|
-
let starts_with_space = first_char == Some(' ');
|
|
324
|
-
let ends_with_space = last_char == Some(' ');
|
|
325
|
-
let starts_with_backtick = first_char == Some('`');
|
|
326
|
-
let ends_with_backtick = last_char == Some('`');
|
|
327
|
-
let all_spaces = content.chars().all(|c| c == ' ');
|
|
328
|
-
|
|
329
|
-
all_spaces
|
|
330
|
-
|| starts_with_backtick
|
|
331
|
-
|| ends_with_backtick
|
|
332
|
-
|| (starts_with_space && ends_with_space && contains_backtick)
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
let (num_backticks, needs_spaces) = if contains_backtick {
|
|
336
|
-
let max_consecutive = content
|
|
337
|
-
.chars()
|
|
338
|
-
.fold((0, 0), |(max, current), c| {
|
|
339
|
-
if c == '`' {
|
|
340
|
-
let new_current = current + 1;
|
|
341
|
-
(max.max(new_current), new_current)
|
|
342
|
-
} else {
|
|
343
|
-
(max, 0)
|
|
344
|
-
}
|
|
345
|
-
})
|
|
346
|
-
.0;
|
|
347
|
-
let num = if max_consecutive == 1 { 2 } else { 1 };
|
|
348
|
-
(num, needs_delimiter_spaces)
|
|
349
|
-
} else {
|
|
350
|
-
(1, needs_delimiter_spaces)
|
|
351
|
-
};
|
|
352
|
-
|
|
353
|
-
for _ in 0..num_backticks {
|
|
354
|
-
output.push('`');
|
|
355
|
-
}
|
|
356
|
-
if needs_spaces {
|
|
357
|
-
output.push(' ');
|
|
358
|
-
}
|
|
359
|
-
output.push_str(content);
|
|
360
|
-
if needs_spaces {
|
|
361
|
-
output.push(' ');
|
|
362
|
-
}
|
|
363
|
-
for _ in 0..num_backticks {
|
|
364
|
-
output.push('`');
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/// Format a code block with the specified style and language.
|
|
369
|
-
///
|
|
370
|
-
/// Supports:
|
|
371
|
-
/// - Indented style (4-space indentation)
|
|
372
|
-
/// - Fenced style with backticks (```language)
|
|
373
|
-
/// - Fenced style with tildes (~~~language)
|
|
374
|
-
fn format_code_block(
|
|
375
|
-
content: &str,
|
|
376
|
-
language: Option<&str>,
|
|
377
|
-
output: &mut String,
|
|
378
|
-
options: &ConversionOptions,
|
|
379
|
-
ctx: &Context,
|
|
380
|
-
) {
|
|
381
|
-
match options.code_block_style {
|
|
382
|
-
crate::options::CodeBlockStyle::Indented => {
|
|
383
|
-
if !ctx.convert_as_inline && !output.is_empty() && !output.ends_with("\n\n") {
|
|
384
|
-
if output.ends_with('\n') {
|
|
385
|
-
output.push('\n');
|
|
386
|
-
} else {
|
|
387
|
-
output.push_str("\n\n");
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
let indented = content
|
|
392
|
-
.lines()
|
|
393
|
-
.map(|line| {
|
|
394
|
-
if line.is_empty() {
|
|
395
|
-
String::new()
|
|
396
|
-
} else {
|
|
397
|
-
format!(" {line}")
|
|
398
|
-
}
|
|
399
|
-
})
|
|
400
|
-
.collect::<Vec<_>>()
|
|
401
|
-
.join("\n");
|
|
402
|
-
output.push_str(&indented);
|
|
403
|
-
|
|
404
|
-
output.push_str("\n\n");
|
|
405
|
-
}
|
|
406
|
-
crate::options::CodeBlockStyle::Backticks | crate::options::CodeBlockStyle::Tildes => {
|
|
407
|
-
if !ctx.convert_as_inline && !output.is_empty() && !output.ends_with("\n\n") {
|
|
408
|
-
if output.ends_with('\n') {
|
|
409
|
-
output.push('\n');
|
|
410
|
-
} else {
|
|
411
|
-
output.push_str("\n\n");
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
let fence = if options.code_block_style == crate::options::CodeBlockStyle::Backticks {
|
|
416
|
-
"```"
|
|
417
|
-
} else {
|
|
418
|
-
"~~~"
|
|
419
|
-
};
|
|
420
|
-
|
|
421
|
-
output.push_str(fence);
|
|
422
|
-
if let Some(lang) = language {
|
|
423
|
-
output.push_str(lang);
|
|
424
|
-
} else if !options.code_language.is_empty() {
|
|
425
|
-
output.push_str(&options.code_language);
|
|
426
|
-
}
|
|
427
|
-
output.push('\n');
|
|
428
|
-
output.push_str(content);
|
|
429
|
-
output.push('\n');
|
|
430
|
-
output.push_str(fence);
|
|
431
|
-
output.push('\n');
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
//! Graphic element handler for HTML to Markdown conversion.
|
|
2
|
-
//!
|
|
3
|
-
//! Handles `<graphic>` elements including:
|
|
4
|
-
//! - Alternative source attributes (url, href, xlink:href, src)
|
|
5
|
-
//! - Fallback alt text from filename attribute
|
|
6
|
-
//! - Metadata collection for graphic extraction
|
|
7
|
-
//! - Visitor callback integration
|
|
8
|
-
|
|
9
|
-
use std::borrow::Cow;
|
|
10
|
-
#[cfg(any(feature = "metadata", feature = "visitor"))]
|
|
11
|
-
use std::collections::BTreeMap;
|
|
12
|
-
|
|
13
|
-
use crate::converter::Context;
|
|
14
|
-
use crate::converter::dom_context::DomContext;
|
|
15
|
-
#[cfg(feature = "visitor")]
|
|
16
|
-
use crate::converter::utility::content::collect_tag_attributes;
|
|
17
|
-
use crate::options::ConversionOptions;
|
|
18
|
-
|
|
19
|
-
#[cfg(feature = "visitor")]
|
|
20
|
-
use crate::converter::utility::serialization::serialize_node;
|
|
21
|
-
|
|
22
|
-
#[cfg(feature = "metadata")]
|
|
23
|
-
type GraphicMetadataPayload = (BTreeMap<String, String>, Option<u32>, Option<u32>);
|
|
24
|
-
|
|
25
|
-
/// Handle a `<graphic>` element and convert to Markdown.
|
|
26
|
-
///
|
|
27
|
-
/// This handler processes graphic elements including:
|
|
28
|
-
/// - Extracting source from url, href, xlink:href, or src attributes
|
|
29
|
-
/// - Using alt attribute, with fallback to filename
|
|
30
|
-
/// - Collecting metadata when the metadata feature is enabled
|
|
31
|
-
/// - Invoking visitor callbacks when the visitor feature is enabled
|
|
32
|
-
/// - Generating appropriate markdown output
|
|
33
|
-
#[allow(clippy::too_many_arguments)]
|
|
34
|
-
#[allow(clippy::too_many_lines)]
|
|
35
|
-
#[cfg_attr(not(feature = "visitor"), allow(unused_variables))]
|
|
36
|
-
pub fn handle_graphic(
|
|
37
|
-
node_handle: &tl::NodeHandle,
|
|
38
|
-
tag: &tl::HTMLTag,
|
|
39
|
-
parser: &tl::Parser,
|
|
40
|
-
output: &mut String,
|
|
41
|
-
options: &ConversionOptions,
|
|
42
|
-
ctx: &Context,
|
|
43
|
-
depth: usize,
|
|
44
|
-
dom_ctx: &DomContext,
|
|
45
|
-
) {
|
|
46
|
-
// Check source attributes in order: url, href, xlink:href, src
|
|
47
|
-
let src = tag
|
|
48
|
-
.attributes()
|
|
49
|
-
.get("url")
|
|
50
|
-
.flatten()
|
|
51
|
-
.or_else(|| tag.attributes().get("href").flatten())
|
|
52
|
-
.or_else(|| tag.attributes().get("xlink:href").flatten())
|
|
53
|
-
.or_else(|| tag.attributes().get("src").flatten())
|
|
54
|
-
.map_or(Cow::Borrowed(""), |v| v.as_utf8_str());
|
|
55
|
-
|
|
56
|
-
// Use "alt" attribute, fallback to "filename"
|
|
57
|
-
let alt = tag
|
|
58
|
-
.attributes()
|
|
59
|
-
.get("alt")
|
|
60
|
-
.flatten()
|
|
61
|
-
.map(|v| v.as_utf8_str())
|
|
62
|
-
.or_else(|| tag.attributes().get("filename").flatten().map(|v| v.as_utf8_str()))
|
|
63
|
-
.unwrap_or(Cow::Borrowed(""));
|
|
64
|
-
|
|
65
|
-
let title = tag.attributes().get("title").flatten().map(|v| v.as_utf8_str());
|
|
66
|
-
|
|
67
|
-
// Collect metadata payload if metadata feature is enabled
|
|
68
|
-
#[cfg(feature = "metadata")]
|
|
69
|
-
#[allow(clippy::useless_let_if_seq)]
|
|
70
|
-
let mut metadata_payload: Option<GraphicMetadataPayload> = None;
|
|
71
|
-
#[cfg(feature = "metadata")]
|
|
72
|
-
if ctx.metadata_wants_images {
|
|
73
|
-
let mut attributes_map = BTreeMap::new();
|
|
74
|
-
let mut width: Option<u32> = None;
|
|
75
|
-
let mut height: Option<u32> = None;
|
|
76
|
-
for (key, value_opt) in tag.attributes().iter() {
|
|
77
|
-
let key_str = key.to_string();
|
|
78
|
-
if key_str == "url" || key_str == "href" || key_str == "xlink:href" || key_str == "src" {
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
let value = value_opt.map(|v| v.to_string()).unwrap_or_default();
|
|
82
|
-
if key_str == "width" {
|
|
83
|
-
if let Ok(parsed) = value.parse::<u32>() {
|
|
84
|
-
width = Some(parsed);
|
|
85
|
-
}
|
|
86
|
-
} else if key_str == "height" {
|
|
87
|
-
if let Ok(parsed) = value.parse::<u32>() {
|
|
88
|
-
height = Some(parsed);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
attributes_map.insert(key_str, value);
|
|
92
|
-
}
|
|
93
|
-
metadata_payload = Some((attributes_map, width, height));
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
let keep_as_markdown = ctx.in_heading && ctx.heading_allow_inline_images;
|
|
97
|
-
|
|
98
|
-
let should_use_alt_text =
|
|
99
|
-
!keep_as_markdown && (ctx.convert_as_inline || (ctx.in_heading && !ctx.heading_allow_inline_images));
|
|
100
|
-
|
|
101
|
-
// Generate graphic output with visitor integration
|
|
102
|
-
#[cfg(feature = "visitor")]
|
|
103
|
-
let graphic_output = if let Some(ref visitor_handle) = ctx.visitor {
|
|
104
|
-
use crate::visitor::{NodeContext, NodeType, VisitResult};
|
|
105
|
-
|
|
106
|
-
let attributes: BTreeMap<String, String> = collect_tag_attributes(tag);
|
|
107
|
-
|
|
108
|
-
let node_id = node_handle.get_inner();
|
|
109
|
-
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
|
|
110
|
-
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
|
|
111
|
-
|
|
112
|
-
let node_ctx = NodeContext {
|
|
113
|
-
node_type: NodeType::Image,
|
|
114
|
-
tag_name: "graphic".to_string(),
|
|
115
|
-
attributes,
|
|
116
|
-
depth,
|
|
117
|
-
index_in_parent,
|
|
118
|
-
parent_tag,
|
|
119
|
-
is_inline: true,
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
let visit_result = {
|
|
123
|
-
let mut visitor = visitor_handle.borrow_mut();
|
|
124
|
-
visitor.visit_image(&node_ctx, &src, &alt, title.as_deref())
|
|
125
|
-
};
|
|
126
|
-
match visit_result {
|
|
127
|
-
VisitResult::Continue => Some(format_graphic_markdown(
|
|
128
|
-
&src,
|
|
129
|
-
&alt,
|
|
130
|
-
title.as_deref(),
|
|
131
|
-
should_use_alt_text,
|
|
132
|
-
options.link_style,
|
|
133
|
-
ctx.reference_collector.as_ref(),
|
|
134
|
-
)),
|
|
135
|
-
VisitResult::Custom(custom) => Some(custom),
|
|
136
|
-
VisitResult::Skip => None,
|
|
137
|
-
VisitResult::Error(err) => {
|
|
138
|
-
if ctx.visitor_error.borrow().is_none() {
|
|
139
|
-
*ctx.visitor_error.borrow_mut() = Some(err);
|
|
140
|
-
}
|
|
141
|
-
None
|
|
142
|
-
}
|
|
143
|
-
VisitResult::PreserveHtml => Some(serialize_node(node_handle, parser)),
|
|
144
|
-
}
|
|
145
|
-
} else {
|
|
146
|
-
Some(format_graphic_markdown(
|
|
147
|
-
&src,
|
|
148
|
-
&alt,
|
|
149
|
-
title.as_deref(),
|
|
150
|
-
should_use_alt_text,
|
|
151
|
-
options.link_style,
|
|
152
|
-
ctx.reference_collector.as_ref(),
|
|
153
|
-
))
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
#[cfg(not(feature = "visitor"))]
|
|
157
|
-
let graphic_output = Some(format_graphic_markdown(
|
|
158
|
-
&src,
|
|
159
|
-
&alt,
|
|
160
|
-
title.as_deref(),
|
|
161
|
-
should_use_alt_text,
|
|
162
|
-
options.link_style,
|
|
163
|
-
ctx.reference_collector.as_ref(),
|
|
164
|
-
));
|
|
165
|
-
|
|
166
|
-
if !options.skip_images {
|
|
167
|
-
if let Some(graphic_text) = graphic_output {
|
|
168
|
-
output.push_str(&graphic_text);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Add graphic to metadata collector
|
|
173
|
-
#[cfg(feature = "metadata")]
|
|
174
|
-
if ctx.metadata_wants_images {
|
|
175
|
-
if let Some(ref collector) = ctx.metadata_collector {
|
|
176
|
-
if let Some((attributes_map, width, height)) = metadata_payload {
|
|
177
|
-
if !src.is_empty() {
|
|
178
|
-
let dimensions = match (width, height) {
|
|
179
|
-
(Some(w), Some(h)) => Some((w, h)),
|
|
180
|
-
_ => None,
|
|
181
|
-
};
|
|
182
|
-
collector.borrow_mut().add_image(
|
|
183
|
-
src.to_string(),
|
|
184
|
-
if alt.is_empty() { None } else { Some(alt.to_string()) },
|
|
185
|
-
title.as_deref().map(std::string::ToString::to_string),
|
|
186
|
-
dimensions,
|
|
187
|
-
attributes_map,
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/// Format a graphic as Markdown syntax.
|
|
196
|
-
///
|
|
197
|
-
/// If `use_alt_only` is true, returns just the alt text.
|
|
198
|
-
/// Otherwise returns the full `` syntax.
|
|
199
|
-
fn format_graphic_markdown(
|
|
200
|
-
src: &str,
|
|
201
|
-
alt: &str,
|
|
202
|
-
title: Option<&str>,
|
|
203
|
-
use_alt_only: bool,
|
|
204
|
-
link_style: crate::options::validation::LinkStyle,
|
|
205
|
-
reference_collector: Option<&crate::converter::reference_collector::ReferenceCollectorHandle>,
|
|
206
|
-
) -> String {
|
|
207
|
-
if use_alt_only {
|
|
208
|
-
return alt.to_string();
|
|
209
|
-
}
|
|
210
|
-
if link_style == crate::options::validation::LinkStyle::Reference {
|
|
211
|
-
if let Some(collector) = reference_collector {
|
|
212
|
-
let ref_num = collector.borrow_mut().get_or_insert(src, title);
|
|
213
|
-
let mut buf = String::with_capacity(alt.len() + 10);
|
|
214
|
-
buf.push_str("![");
|
|
215
|
-
buf.push_str(alt);
|
|
216
|
-
buf.push_str("][");
|
|
217
|
-
buf.push_str(&ref_num.to_string());
|
|
218
|
-
buf.push(']');
|
|
219
|
-
return buf;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
let mut buf = String::with_capacity(src.len() + alt.len() + 10);
|
|
223
|
-
buf.push_str(";
|
|
226
|
-
buf.push_str(src);
|
|
227
|
-
if let Some(title_text) = title {
|
|
228
|
-
buf.push_str(" \"");
|
|
229
|
-
buf.push_str(title_text);
|
|
230
|
-
buf.push('"');
|
|
231
|
-
}
|
|
232
|
-
buf.push(')');
|
|
233
|
-
buf
|
|
234
|
-
}
|