use ox_content_ast::{
BlockQuote, CodeBlock, Heading, Html, List, ListItem, Paragraph, Table, TableCell, TableRow,
ThematicBreak,
};
use super::super::code_annotations::normalize_code_block_language;
use super::super::toc::is_toc_marker_paragraph;
use super::HtmlRenderer;
impl HtmlRenderer {
pub(in crate::html::renderer) fn render_paragraph(&mut self, paragraph: &Paragraph<'_>) {
crate::profile_span!("renderer::visit_paragraph");
if self.document_has_toc_marker && is_toc_marker_paragraph(paragraph) {
self.render_inline_toc();
return;
}
self.output.push_str("<p>");
for child in ¶graph.children {
self.visit_inline_node(child);
}
self.output.push_str("</p>\n");
}
pub(in crate::html::renderer) fn render_heading(&mut self, heading: &Heading<'_>) {
crate::profile_span!("renderer::visit_heading");
let depth = heading.depth.clamp(1, 6);
self.output.push_str("<h");
self.output.push((b'0' + depth) as char);
self.output.push_str(" id=\"");
self.write_heading_id(heading);
self.output.push_str("\">");
for child in &heading.children {
self.visit_inline_node(child);
}
self.output.push_str("</h");
self.output.push((b'0' + depth) as char);
self.output.push_str(">\n");
}
pub(in crate::html::renderer) fn render_thematic_break(
&mut self,
_thematic_break: &ThematicBreak,
) {
if self.options.xhtml {
self.write("<hr />\n");
} else {
self.write("<hr>\n");
}
}
pub(in crate::html::renderer) fn render_block_quote(&mut self, block_quote: &BlockQuote<'_>) {
crate::profile_span!("renderer::visit_block_quote");
if self.render_callout_block_quote(block_quote) {
return;
}
self.write("<blockquote>\n");
for child in &block_quote.children {
self.render_node(child);
}
self.write("</blockquote>\n");
}
pub(in crate::html::renderer) fn render_list(&mut self, list: &List<'_>) {
crate::profile_span!("renderer::visit_list");
if list.ordered {
if let Some(start) = list.start {
if start != 1 {
self.write("<ol start=\"");
self.write_display(start);
self.write("\">\n");
} else {
self.write("<ol>\n");
}
} else {
self.write("<ol>\n");
}
} else {
self.write("<ul>\n");
}
for child in &list.children {
self.render_list_item(child);
}
if list.ordered {
self.write("</ol>\n");
} else {
self.write("</ul>\n");
}
}
pub(in crate::html::renderer) fn render_list_item(&mut self, list_item: &ListItem<'_>) {
self.write("<li>");
if let Some(checked) = list_item.checked {
if checked {
self.write("<input type=\"checkbox\" checked disabled> ");
} else {
self.write("<input type=\"checkbox\" disabled> ");
}
}
for child in &list_item.children {
self.render_node(child);
}
self.write("</li>\n");
}
pub(in crate::html::renderer) fn render_code_block(&mut self, code_block: &CodeBlock<'_>) {
crate::profile_span!("renderer::visit_code_block");
if !self.options.code_annotations {
self.write("<pre><code");
if let Some(lang) = normalize_code_block_language(code_block.lang) {
self.write(" class=\"language-");
self.write_escaped(lang);
self.write("\"");
}
self.write(">");
self.write_escaped(code_block.value);
self.write("</code></pre>\n");
return;
}
let state = self.build_code_block_state(code_block);
let block_classes = state.block_classes();
self.write("<pre");
if !block_classes.is_empty() {
self.write(" class=\"");
self.write(&block_classes.join(" "));
self.write("\"");
}
if let Some(title) = state.title.as_deref() {
self.write(" data-code-title=\"");
self.write_escaped(title);
self.write("\"");
}
if let Some(start) = state.line_numbers_start {
self.write(" data-line-numbers=\"true\" data-line-number-start=\"");
self.write_display(start);
self.write("\"");
}
self.write("><code");
if let Some(lang) = state.language.as_deref() {
self.write(" class=\"language-");
self.write_escaped(lang);
self.write("\"");
}
self.write(">");
if state.needs_line_wrappers() {
self.write_code_lines(&state);
} else {
self.write_escaped(code_block.value);
}
self.write("</code></pre>\n");
}
pub(in crate::html::renderer) fn render_html(&mut self, html: &Html<'_>) {
self.write_html_value(html.value);
self.write("\n");
}
pub(in crate::html::renderer) fn render_table(&mut self, table: &Table<'_>) {
crate::profile_span!("renderer::visit_table");
self.write("<table>\n");
for (i, row) in table.children.iter().enumerate() {
if i == 0 {
self.write("<thead>\n");
} else if i == 1 {
self.write("<tbody>\n");
}
self.visit_table_row_with_header(row, i == 0, &table.align);
if i == 0 {
self.write("</thead>\n");
}
}
if !table.children.is_empty() {
self.write("</tbody>\n");
}
self.write("</table>\n");
}
pub(in crate::html::renderer) fn visit_table_row_with_header(
&mut self,
row: &TableRow<'_>,
is_header: bool,
align: &ox_content_allocator::Vec<'_, ox_content_ast::AlignKind>,
) {
self.write("<tr>\n");
let tag = if is_header { "th" } else { "td" };
for (idx, cell) in row.children.iter().enumerate() {
self.write("<");
self.write(tag);
match align.get(idx).copied().unwrap_or(ox_content_ast::AlignKind::None) {
ox_content_ast::AlignKind::Left => self.write(" align=\"left\""),
ox_content_ast::AlignKind::Center => self.write(" align=\"center\""),
ox_content_ast::AlignKind::Right => self.write(" align=\"right\""),
ox_content_ast::AlignKind::None => {}
}
self.write(">");
self.visit_table_cell(cell);
self.write("</");
self.write(tag);
self.write(">\n");
}
self.write("</tr>\n");
}
pub(in crate::html::renderer) fn visit_table_cell(&mut self, cell: &TableCell<'_>) {
for child in &cell.children {
self.visit_inline_node(child);
}
}
}