markdown-ppp 0.1.0

Feature-rich Markdown Parsing and Pretty-Printing library
Documentation

markdown-ppp

markdown-ppp is a feature-rich, flexible, and lightweight Rust library for parsing and processing Markdown documents.

It provides a clean, well-structured Abstract Syntax Tree (AST) for parsed documents, making it suitable for pretty-printing, analyzing, transforming, or rendering Markdown.


✨ Features

  • Markdown Parsing — Full Markdown parsing support with strict AST structure.
  • Pretty-printing and processing — Build, modify, and reformat Markdown easily.
  • Modular design — You can disable parsing entirely and use only the AST types.

📦 Installation

Add the crate using Cargo:

cargo add markdown-ppp

If you want only the AST definitions without parsing functionality, disable default features manually:

[dependencies]
markdown-ppp = { version = "0.1.0", default-features = false }

🛠 Usage

Parsing Markdown

The main entry point for parsing is the parse_markdown function, available at:

pub fn parse_markdown(
    state: MarkdownParserState,
    input: &str,
) -> Result<Document, nom::Err<nom::error::Error<&str>>>

Example:

use markdown_ppp::parse::parse_markdown;
use markdown_ppp::ast::Document;
use std::rc::Rc;

fn main() {
    let state = markdown_ppp::parse::MarkdownParserState::new();
    let input = "# Hello, World!";

    match parse_markdown(Rc::new(state), input) {
        Ok(document) => {
            println!("Parsed document: {:?}", document);
        }
        Err(err) => {
            eprintln!("Failed to parse Markdown: {:?}", err);
        }
    }
}

MarkdownParserState

The MarkdownParserState controls parsing behavior and can be customized.

You can create a default state easily:

use markdown_ppp::parser::config::*;

let state = MarkdownParserState::default();

Alternatively, you can configure it manually by providing a MarkdownParserConfig:

use markdown_ppp::parser::config::*;

let config = MarkdownParserConfig::default()
    .with_block_blockquote_behavior(ElementBehavior::Ignore);

let ast = parse_markdown(MarkdownParserState::with_config(config), "hello world")?;

This allows you to control how certain Markdown elements are parsed or ignored.


🧩 Customizing the Parsing Behavior

You can control how individual Markdown elements are parsed at a fine-grained level using the MarkdownParserConfig API.

Element Behavior Configuration how individual Markdown elements are parsed at a fine-grained level using the MarkdownParserConfig API.

Each element type (block-level or inline-level) can be configured with an ElementBehavior:

pub enum ElementBehavior<ELT> {
    /// The parser will parse the element normally.
    Parse,

    /// The parser will ignore the element and not parse it. In this case, alternative
    /// parsers will be tried.
    Ignore,

    /// Parse the element but do not include it in the output.
    Skip,

    /// Parse the element and apply a custom function to it.
    Map(ElementMapFn<ELT>),
}

These behaviors can be set via builder-style methods on the config. For example, to skip parsing of thematic breaks and transform blockquotes:

use markdown_ppp::parser::config::*;
use markdown_ppp::ast::Block;

let config = MarkdownParserConfig::default()
    .with_block_thematic_break_behavior(ElementBehavior::Skip)
    .with_block_blockquote_behavior(ElementBehavior::Map(|mut bq: Block| {
        // Example transformation: replace all blockquotes with empty paragraphs
        Block::Paragraph(vec![])
    }));

let ast = parse_markdown(MarkdownParserState::with_config(config), input)?;

This mechanism allows you to override, filter, or completely redefine how each Markdown element is treated during parsing, giving you deep control over the resulting AST.

Registering Custom Parsers

You can also register your own custom block-level or inline-level parsers by providing parser functions via configuration. These parsers are executed before the built-in ones and can be used to support additional syntax or override behavior.

To register a custom block parser:

use markdown_ppp::parser::config::*;
use markdown_ppp::ast::Block;
use std::{rc::Rc, cell::RefCell};
use nom::IResult;

let custom_block: CustomBlockParserFn = Rc::new(RefCell::new(Box::new(|input: &str| {
    if input.starts_with("::note") {
        let block = Block::Paragraph(vec!["This is a note block".into()]);
        Ok(("", block))
    } else {
        Err(nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Tag)))
    }
})));

let config = MarkdownParserConfig::default()
    .with_custom_block_parser(custom_block);

Similarly, to register a custom inline parser:

use markdown_ppp::parser::config::*;
use markdown_ppp::ast::Inline;
use std::{rc::Rc, cell::RefCell};
use nom::IResult;

let custom_inline: CustomInlineParserFn = Rc::new(RefCell::new(Box::new(|input: &str| {
    if input.starts_with("@@") {
        Ok((&input[2..], Inline::Text("custom-inline".into())))
    } else {
        Err(nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Tag)))
    }
})));

let config = config.with_custom_inline_parser(custom_inline);

This extensibility allows you to integrate domain-specific syntax and behaviors into the Markdown parser while reusing the base logic and AST structure provided by markdown-ppp., filter, or completely redefine how each Markdown element is treated during parsing, giving you deep control over the resulting AST.


📄 AST Structure

The complete Markdown Abstract Syntax Tree (AST) is defined inside the module markdown_ppp::ast.

The Document struct represents the root node, and from there you can traverse the full tree of blocks and inlines, such as headings, paragraphs, lists, emphasis, and more.

You can use the AST independently without the parsing functionality by disabling default features.


🔧 Optional Features

Feature Description
parser Enables Markdown parsing support. Enabled by default.
ast-serde Adds Serialize and Deserialize traits to all AST types via serde. Disabled by default.

If you only need the AST types without parsing functionality, you can add the crate without default features:

cargo add --no-default-features markdown-ppp

📚 Documentation


📝 License

Licensed under the MIT License.