wooorm / markdown-rs

CommonMark compliant markdown parser in Rust with ASTs and extensions
https://docs.rs/markdown/1.0.0-alpha.18/markdown/
MIT License
836 stars 41 forks source link

Expose to_html::compile #115

Closed mousetail closed 2 months ago

mousetail commented 2 months ago

Currently, the to_mdast method is exposed, to create a syntax tree. However, after making the necessary modifications to this syntax tree it seems there is no exposed way to turn the result into HTML.

pub mod to_html should fix it though I'm not sure what other undesired things that would expose. Something to think about.

My use case is I want to replace all code blocks with a certain language with an image based on the content of the code block.

wooorm commented 2 months ago

Hey!

should fix it

No it doesn’t. That doesn’t take an AST.


What you are looking for is discussed in several open issues. GH-27. GH-32.

mousetail commented 2 months ago

Hmm in that case I'd need a way to access and modify the event list as they are being streamed

ChristianMurphy commented 2 months ago

No, the tickets @wooorm reference are about supporting working with the syntax tree. The API you want to make public doesn't fix the problem you want to solve, the issues above do.

mousetail commented 2 months ago

I don't need a full plugin system, I just need to get between these two lines:

pub fn to_html_with_options(value: &str, options: &Options) -> Result<String, message::Message> {
    let (events, parse_state) = parser::parse(value, &options.parse)?;

    // do something with events
    Ok(to_html::compile(
        &events,
        parse_state.bytes,
        &options.compile,
    ))
}

In fact working with events is easier than working with the syntax tree since I can just modify the events I care about without needing to recursively nest a heterogeneous tree (which would either be very vebose or require a lot of macros)

A full plugin system would also solve it but since all the elements I need are already natively supported and I don't need any custom HTML it may not be necessary.

mousetail commented 2 months ago

I fully understand that just exposing the to_html API won't be enough now, just thinking about what the new simplest way to make it work is

wooorm commented 2 months ago

I don't think what you want with events is easy.

You really should use an AST. The simplest is to use JavaScript.

mousetail commented 2 months ago

Something like this should work: (Psuedocode)

let mut text = parse_state.bytes.to_vec();
let mut new_events = vec![];

let mut event_iter = events.into_iter();
while let Some(event) = event_iter.next() {
    if let Name::CodeFenced = event.name { // should also check if event.kind == EventKind::Start
       if let Some(Name::CodeFencedFence) = event_iter.next().map(|t|t.name) {
           // loop until you get a code fenced end event
           // check if the name matches your filter
           // if so, push the extra strings necessary to text
       }
    }
    // if anything doesn't match, push all the original events to new_events
}

Ok(to_html::compile(
        &new_events,
        text,
        &options.compile,
    ))

(I'm just arguing for the sake of arguing now, I'll probably just use a different library. Just want to prove it's possible)

wooorm commented 2 months ago

Everything is possible but many things are bad. The internal events are not meant to be touched. Either make the plugin system as discussed in the mentioned issues. Or use the JS ecosystem. Or even use client side JS. Or use rust HTML rewriter crates.