#[cfg(feature = "visitor")]
use crate::converter::utility::content::collect_tag_attributes;
use crate::options::{ConversionOptions, OutputFormat};
#[cfg(feature = "visitor")]
use std::collections::BTreeMap;
use tl::{NodeHandle, Parser};
type Context = crate::converter::Context;
type DomContext = crate::converter::DomContext;
pub fn handle_mark(
node_handle: &NodeHandle,
parser: &Parser,
output: &mut String,
options: &ConversionOptions,
ctx: &Context,
depth: usize,
dom_ctx: &DomContext,
) {
use crate::converter::walk_node;
let Some(node) = node_handle.get(parser) else { return };
let tag = match node {
tl::Node::Tag(tag) => tag,
_ => return,
};
if ctx.convert_as_inline {
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
}
} else {
use crate::options::HighlightStyle;
match options.highlight_style {
HighlightStyle::DoubleEqual => {
if options.output_format == OutputFormat::Djot {
output.push_str("{=");
} else {
output.push_str("==");
}
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
}
if options.output_format == OutputFormat::Djot {
output.push_str("=}");
} else {
output.push_str("==");
}
}
HighlightStyle::Html => {
output.push_str("<mark>");
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
}
output.push_str("</mark>");
}
HighlightStyle::Bold => {
let mut symbol = String::with_capacity(2);
symbol.push(options.strong_em_symbol);
symbol.push(options.strong_em_symbol);
output.push_str(&symbol);
let bold_ctx = Context {
in_strong: true,
..ctx.clone()
};
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, output, options, &bold_ctx, depth + 1, dom_ctx);
}
output.push_str(&symbol);
}
HighlightStyle::None => {
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
}
}
}
}
}
#[allow(unused_variables)]
pub fn handle_strikethrough(
tag_name: &str,
node_handle: &NodeHandle,
parser: &Parser,
output: &mut String,
options: &ConversionOptions,
ctx: &Context,
depth: usize,
dom_ctx: &DomContext,
) {
use crate::converter::{append_inline_suffix, chomp_inline, walk_node};
let Some(node) = node_handle.get(parser) else { return };
let tag = match node {
tl::Node::Tag(tag) => tag,
_ => return,
};
if ctx.in_code {
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
}
} else {
let mut content = String::with_capacity(32);
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, &mut content, options, ctx, depth + 1, dom_ctx);
}
#[cfg(feature = "visitor")]
let strikethrough_output = if let Some(ref visitor_handle) = ctx.visitor {
use crate::converter::get_text_content;
use crate::visitor::{NodeContext, NodeType, VisitResult};
let text_content = get_text_content(node_handle, parser, dom_ctx);
let attributes: BTreeMap<String, String> = collect_tag_attributes(tag);
let node_id = node_handle.get_inner();
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
let node_ctx = NodeContext {
node_type: NodeType::Strikethrough,
tag_name: tag_name.to_string(),
attributes,
depth,
index_in_parent,
parent_tag,
is_inline: true,
};
let visit_result = {
let mut visitor = visitor_handle.borrow_mut();
visitor.visit_strikethrough(&node_ctx, &text_content)
};
match visit_result {
VisitResult::Continue => None,
VisitResult::Custom(custom) => Some(custom),
VisitResult::Skip => Some(String::new()),
VisitResult::PreserveHtml => {
use crate::converter::serialize_node;
Some(serialize_node(node_handle, parser))
}
VisitResult::Error(err) => {
if ctx.visitor_error.borrow().is_none() {
*ctx.visitor_error.borrow_mut() = Some(err);
}
None
}
}
} else {
None
};
#[cfg(feature = "visitor")]
if let Some(custom_output) = strikethrough_output {
output.push_str(&custom_output);
} else {
let (prefix, suffix, trimmed) = chomp_inline(&content);
if !content.trim().is_empty() {
output.push_str(prefix);
if options.output_format == OutputFormat::Djot {
output.push_str("{-");
} else {
output.push_str("~~");
}
output.push_str(trimmed);
if options.output_format == OutputFormat::Djot {
output.push_str("-}");
} else {
output.push_str("~~");
}
append_inline_suffix(output, suffix, !trimmed.is_empty(), node_handle, parser, dom_ctx);
} else if !content.is_empty() {
output.push_str(prefix);
append_inline_suffix(output, suffix, false, node_handle, parser, dom_ctx);
}
}
#[cfg(not(feature = "visitor"))]
{
let (prefix, suffix, trimmed) = chomp_inline(&content);
if !content.trim().is_empty() {
output.push_str(prefix);
if options.output_format == OutputFormat::Djot {
output.push_str("{-");
} else {
output.push_str("~~");
}
output.push_str(trimmed);
if options.output_format == OutputFormat::Djot {
output.push_str("-}");
} else {
output.push_str("~~");
}
append_inline_suffix(output, suffix, !trimmed.is_empty(), node_handle, parser, dom_ctx);
} else if !content.is_empty() {
output.push_str(prefix);
append_inline_suffix(output, suffix, false, node_handle, parser, dom_ctx);
}
}
}
}
pub fn handle_inserted(
node_handle: &NodeHandle,
parser: &Parser,
output: &mut String,
options: &ConversionOptions,
ctx: &Context,
depth: usize,
dom_ctx: &DomContext,
) {
use crate::converter::{append_inline_suffix, chomp_inline, walk_node};
let Some(node) = node_handle.get(parser) else { return };
let tag = match node {
tl::Node::Tag(tag) => tag,
_ => return,
};
let mut content = String::with_capacity(32);
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, &mut content, options, ctx, depth + 1, dom_ctx);
}
#[cfg(feature = "visitor")]
let underline_output = if let Some(ref visitor_handle) = ctx.visitor {
use crate::converter::get_text_content;
use crate::visitor::{NodeContext, NodeType, VisitResult};
let text_content = get_text_content(node_handle, parser, dom_ctx);
let attributes: BTreeMap<String, String> = collect_tag_attributes(tag);
let node_id = node_handle.get_inner();
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
let node_ctx = NodeContext {
node_type: NodeType::Underline,
tag_name: "ins".to_string(),
attributes,
depth,
index_in_parent,
parent_tag,
is_inline: true,
};
let visit_result = {
let mut visitor = visitor_handle.borrow_mut();
visitor.visit_underline(&node_ctx, &text_content)
};
match visit_result {
VisitResult::Continue => None,
VisitResult::Custom(custom) => Some(custom),
VisitResult::Skip => Some(String::new()),
VisitResult::PreserveHtml => {
use crate::converter::serialize_node;
Some(serialize_node(node_handle, parser))
}
VisitResult::Error(err) => {
if ctx.visitor_error.borrow().is_none() {
*ctx.visitor_error.borrow_mut() = Some(err);
}
None
}
}
} else {
None
};
#[cfg(feature = "visitor")]
if let Some(custom_output) = underline_output {
output.push_str(&custom_output);
} else {
let (prefix, suffix, trimmed) = chomp_inline(&content);
if !trimmed.is_empty() {
output.push_str(prefix);
if options.output_format == OutputFormat::Djot {
output.push_str("{+");
} else {
output.push_str("==");
}
output.push_str(trimmed);
if options.output_format == OutputFormat::Djot {
output.push_str("+}");
} else {
output.push_str("==");
}
append_inline_suffix(output, suffix, !trimmed.is_empty(), node_handle, parser, dom_ctx);
}
}
#[cfg(not(feature = "visitor"))]
{
let (prefix, suffix, trimmed) = chomp_inline(&content);
if !trimmed.is_empty() {
output.push_str(prefix);
if options.output_format == OutputFormat::Djot {
output.push_str("{+");
} else {
output.push_str("==");
}
output.push_str(trimmed);
if options.output_format == OutputFormat::Djot {
output.push_str("+}");
} else {
output.push_str("==");
}
append_inline_suffix(output, suffix, !trimmed.is_empty(), node_handle, parser, dom_ctx);
}
}
}
pub fn handle_underline(
node_handle: &NodeHandle,
parser: &Parser,
output: &mut String,
options: &ConversionOptions,
ctx: &Context,
depth: usize,
dom_ctx: &DomContext,
) {
use crate::converter::walk_node;
let Some(node) = node_handle.get(parser) else { return };
let tag = match node {
tl::Node::Tag(tag) => tag,
_ => return,
};
#[cfg(feature = "visitor")]
if let Some(ref visitor_handle) = ctx.visitor {
use crate::converter::get_text_content;
use crate::visitor::{NodeContext, NodeType, VisitResult};
let text_content = get_text_content(node_handle, parser, dom_ctx);
let attributes: BTreeMap<String, String> = collect_tag_attributes(tag);
let node_id = node_handle.get_inner();
let parent_tag = dom_ctx.parent_tag_name(node_id, parser);
let index_in_parent = dom_ctx.get_sibling_index(node_id).unwrap_or(0);
let node_ctx = NodeContext {
node_type: NodeType::Underline,
tag_name: "u".to_string(),
attributes,
depth,
index_in_parent,
parent_tag,
is_inline: true,
};
let visit_result = {
let mut visitor = visitor_handle.borrow_mut();
visitor.visit_underline(&node_ctx, &text_content)
};
match visit_result {
VisitResult::Continue => {
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
}
}
VisitResult::Custom(custom) => {
output.push_str(&custom);
}
VisitResult::Skip => {}
VisitResult::PreserveHtml => {
use crate::converter::serialize_node;
output.push_str(&serialize_node(node_handle, parser));
}
VisitResult::Error(err) => {
if ctx.visitor_error.borrow().is_none() {
*ctx.visitor_error.borrow_mut() = Some(err);
}
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
}
}
}
} else {
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
}
}
#[cfg(not(feature = "visitor"))]
{
let children = tag.children();
for child_handle in children.top().iter() {
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
}
}
}