pulldown-html-ext 0.4.0

Extended HTML rendering capabilities for pulldown-cmark
Documentation
# pulldown-html-ext

A configurable Markdown to HTML renderer that extends [pulldown-cmark](https://github.com/raphlinus/pulldown-cmark). This library provides a flexible HTML rendering system with extensive configuration options, custom styling support, and attribute handling capabilities.

## Features

- Configurable HTML rendering with extensive options
- Custom attribute mapping for HTML elements
- Support for heading IDs and custom classes
- Customizable code block rendering
- External link handling with `nofollow` and `target="_blank"` options
- Table support with alignment controls
- Footnote rendering
- Task list support
- XHTML-style output option
- Pretty printing support
- Syntect-based syntax highlighting for code blocks

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
pulldown-html-ext = "0.1.0"
```

## Quick Start

Here's a simple example of converting Markdown to HTML using default settings:

```rust
use pulldown_html_ext::{HtmlConfig, push_html};
use pulldown_cmark::Parser;

let config = HtmlConfig::default();
let markdown = "# Hello\nThis is *markdown*";
let mut output = String::new();
let parser = Parser::new(markdown);
let html = push_html(&mut output, parser, &config);
```

## Configuration

The library provides extensive configuration options through the `HtmlConfig` struct:

```rust
let mut config = HtmlConfig::default();

// Configure HTML options
config.html.escape_html = true;
config.html.break_on_newline = true;
config.html.xhtml_style = false;
config.html.pretty_print = true;

// Configure heading options
config.elements.headings.add_ids = true;
config.elements.headings.id_prefix = "heading-".to_string();

// Configure link options
config.elements.links.nofollow_external = true;
config.elements.links.open_external_blank = true;

// Configure code block options
config.elements.code_blocks.default_language = Some("rust".to_string());
config.elements.code_blocks.line_numbers = false;

// Configure syntax highlighting ( If feature is enabled )
config.syntect = Some(SyntectConfigStyle {
    theme: "base16-ocean.dark".to_string(),
    class_style: ClassStyle::Spaced,
    inject_css: true,
});
```

## Custom Attribute Mapping

You can add custom attributes to HTML elements:

```rust
use std::collections::HashMap;

let mut config = HtmlConfig::default();
let mut attrs = HashMap::new();
attrs.insert("class".to_string(), "custom-paragraph".to_string());
config.attributes.element_attributes.insert("p".to_string(), attrs);
```

## Custom Writers

Create custom HTML writers by implementing the `HtmlWriter` trait. This allows you to customize how specific Markdown elements are rendered to HTML:

```rust
use pulldown_html_ext::{HtmlConfig, HtmlWriter, HtmlState, create_html_renderer};
use pulldown_cmark_escape::{StrWrite, FmtWriter};
use pulldown_cmark::{HeadingLevel, Parser};

struct CustomWriter<W: StrWrite> {
    writer: W,
    config: HtmlConfig,
    state: HtmlState,
}

impl<W: StrWrite> CustomWriter<W> {
    fn new(writer: W, config: HtmlConfig) -> Self {
        Self {
            writer,
            config,
            state: HtmlState::new(),
        }
    }
}

impl<W: StrWrite> HtmlWriter<W> for CustomWriter<W> {
    fn get_writer(&mut self) -> &mut W {
        &mut self.writer
    }

    fn get_config(&self) -> &HtmlConfig {
        &self.config
    }

    fn get_state(&mut self) -> &mut HtmlState {
        &mut self.state
    }

    // Override heading rendering to add emoji markers and custom classes
    fn start_heading(&mut self, level: HeadingLevel, _id: Option<&str>, classes: Vec<&str>) {
        let level_num = self.heading_level_to_u8(level);
        let emoji = match level_num {
            1 => "🎯",
            2 => "💫",
            _ => "✨",
        };
        
        self.write_str(&format!("<h{} class=\"fancy-heading level-{}", level_num, level_num));
        if !classes.is_empty() {
            self.write_str(" ");
            self.write_str(&classes.join(" "));
        }
        self.write_str("\">");
        self.write_str(emoji);
        self.write_str(" ");
    }

    fn end_heading(&mut self, level: HeadingLevel) {
        let level_num = self.heading_level_to_u8(level);
        self.write_str(&format!(" </h{}>", level_num));
    }
}

// Usage example:
fn main() {
    let mut output = String::new();
    let writer = CustomWriter::new(FmtWriter(&mut output), HtmlConfig::default());
    let mut renderer = create_html_renderer(writer);
    
    let markdown = "# Main Title\n## Subtitle\n### Section";
    let parser = Parser::new(markdown);
    renderer.run(parser);
    
    println!("{}", output);
    // Output:
    // <h1 class="fancy-heading level-1">🎯 Main Title </h1>
    // <h2 class="fancy-heading level-2">💫 Subtitle </h2>
    // <h3 class="fancy-heading level-3">✨ Section </h3>
}
```

## Syntect-based Syntax Highlighting

The library provides an optional feature to enable syntax highlighting for code blocks using the Syntect library. To use this, you can enable the `syntect` feature in your `Cargo.toml`:

```toml
[dependencies]
pulldown-html-ext = { version = "0.1.0", features = ["syntect"] }
```

Then, you can configure the syntax highlighting options in your `HtmlConfig`:

```rust
let mut config = HtmlConfig::default();
config.syntect = Some(SyntectConfigStyle {
    theme: "base16-ocean.dark".to_string(),
    class_style: ClassStyle::Spaced,
    inject_css: true,
});
```

This will add syntax highlighting to your code blocks using the specified theme and class style.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.