# HTML Rendering This guide explains how HTML rendering works in `pulldown-html-ext` and how to customize the rendering process. ## Core Concepts The HTML rendering system consists of several key components: 1. `HtmlRenderer` - The core renderer that processes Markdown events 2. `HtmlWriter` - The trait that defines how elements are rendered 3. `HtmlState` - Maintains state during rendering 4. `DefaultHtmlWriter` - The default implementation of `HtmlWriter` ## Basic Rendering The simplest way to render Markdown to HTML: ```rust use pulldown_cmark::Parser; use pulldown_html_ext::{HtmlConfig, push_html}; let config = HtmlConfig::default(); let markdown = "# Hello\nThis is *markdown*"; let parser = Parser::new(markdown); let mut output = String::new(); push_html(&mut output, parser, &config)?; ``` ## Working with the Renderer Directly For more control, you can work with the renderer directly: ```rust use pulldown_html_ext::{create_html_renderer, DefaultHtmlWriter}; use pulldown_cmark::{Parser, Event}; use pulldown_cmark_escape::FmtWriter; let mut output = String::new(); let writer = DefaultHtmlWriter::new(FmtWriter(&mut output), &config); let mut renderer = create_html_renderer(writer); let parser = Parser::new(markdown); renderer.run(parser)?; ``` ## State Management The renderer maintains state during processing: ```rust pub struct HtmlState { pub numbers: Vec, // For ordered lists pub table_state: TableContext, // Current table state pub table_cell_index: usize, // Current cell in table pub table_alignments: Vec, // Table column alignments pub list_stack: Vec, // Nested list tracking pub link_stack: Vec, // Nested link tracking pub heading_stack: Vec, // Header ID tracking pub currently_in_code_block: bool, // Code block state pub currently_in_footnote: bool, // Footnote state } ``` ## Event Handling The renderer processes various Markdown events: ```rust impl> HtmlRenderer { pub fn run<'a, I>(&mut self, iter: I) -> Result<()> where I: Iterator>, { let mut iter = iter.peekable(); while let Some(event) = iter.next() { match event { Event::Start(tag) => self.handle_start(&mut iter, tag)?, Event::End(tag) => self.handle_end(tag)?, Event::Text(text) => self.writer.text(&text)?, Event::Code(text) => self.handle_inline_code(&text)?, Event::Html(html) => self.writer.write_str(&html)?, Event::SoftBreak => self.writer.soft_break()?, Event::HardBreak => self.writer.hard_break()?, Event::Rule => self.writer.horizontal_rule()?, Event::FootnoteReference(name) => self.writer.footnote_reference(&name)?, Event::TaskListMarker(checked) => self.writer.task_list_item(checked)?, Event::InlineMath(_) | Event::DisplayMath(_) | Event::InlineHtml(_) => todo!(), } } Ok(()) } } ``` ## Element Handling Examples ### Headers ```rust // Input Markdown # Level 1 ## Level 2 // Generated HTML

Level 1

Level 2

``` ### Lists ```rust // Input Markdown 1. First 2. Second * Nested * Items // Generated HTML
  1. First
  2. Second
    • Nested
    • Items
``` ### Tables ```rust // Input Markdown | Left | Center | Right | |:-----|:------:|------:| | 1 | 2 | 3 | // Generated HTML
Left Center Right
1 2 3
``` ## Error Handling The renderer uses a custom error type: ```rust pub enum HtmlError { Io(io::Error), Write(fmt::Error), Theme(String), Config(String), Render(String), } ``` Handle errors appropriately: ```rust fn render_markdown(markdown: &str) -> Result { let config = HtmlConfig::default(); let parser = Parser::new(markdown); let mut output = String::new(); push_html(&mut output, parser, &config)?; Ok(output) } ``` ## Writing Output The library supports different output methods: ```rust // String output let mut output = String::new(); push_html(&mut output, parser, &config)?; // Write to formatter write_html_fmt(&mut output, parser, &config)?; // Write to IO let file = File::create("output.html")?; write_html_io(file, parser, &config)?; ``` ## Best Practices 1. **State Management** - Reset state between documents - Check state before operations - Handle nested structures carefully 2. **Error Handling** - Always handle potential errors - Use appropriate error variants - Provide meaningful error messages 3. **Performance** - Create Parser instances appropriately - Reuse writers when processing multiple documents - Consider buffer size for large documents 4. **Memory Usage** - Clear state between documents - Be mindful of string allocations - Handle large documents efficiently ## Next Steps - Learn about [Syntax Highlighting](syntax-highlighting.md) - Implement [Custom Writers](custom-writers.md) - See [Examples](../examples/basic-usage.md)