[][src]Crate markedit

An ergonomic library for manipulating markdown documents.

There are two fundamental concepts in markedit,

  • Matcher - something which can match an Event from pulldown-cmark (typically implemented using state machines or simple functions)
  • Rewriter - something which can rewrite part of a stream of Events (typically just a function)

Together we can use these to transform a stream of Events on the fly with minimal overhead.

Examples

The use case which prompted this entire library was to insert arbitrary markdown after a heading.

use pulldown_cmark::{Event, Tag};
use markedit::{Matcher, Heading};

let src = "# Heading\n Some text\n some more text \n\n # Another Heading";

// first we need to construct our predicate
let matcher = markedit::text_containing("Heading")
    .inside_any_header()
    .then_start_of_next_line();

// we also need a rewriting rule
let rule = markedit::insert_after("## Sub-Heading", matcher);

// create our stream of events
let events = markedit::parse(src);
// then mutate them and collect them into a vector so we can inspect the
// results
let mutated: Vec<_> = markedit::rewrite(events, rule).collect();

// the heading before we want to insert
assert_eq!(mutated[1], Event::Text("Heading".into()));
// our inserted tags
assert_eq!(mutated[3], Event::Start(Tag::Heading(2)));
assert_eq!(mutated[4], Event::Text("Sub-Heading".into()));
assert_eq!(mutated[5], Event::End(Tag::Heading(2)));
// "Some text" is the line after
assert_eq!(mutated[7], Event::Text("Some text".into()));

You can also use change_text() to upper-case text based on a predicate (e.g. the text contains a certain keyword).

use pulldown_cmark::Event;

let src = "# Heading\n Some text \n some more text \n\n # Another Heading";

// first we construct the rewriting rule
let rule = markedit::change_text(
    |text| text.contains("Heading"),
    |text| text.to_uppercase(),
);

// let's parse the input text into Events
let events_before: Vec<_> = markedit::parse(src).collect();

// some sanity checks on the initial input
assert_eq!(events_before[1], Event::Text("Heading".into()));
assert_eq!(events_before[9], Event::Text("Another Heading".into()));

// now rewrite the events using our rewriter rule
let events_after: Vec<_> = markedit::rewrite(events_before, rule)
    .collect();

// and check the results
println!("{:?}", events_after);
assert_eq!(events_after[1], Event::Text("HEADING".into()));
assert_eq!(events_after[9], Event::Text("ANOTHER HEADING".into()));

Note that everything works with streaming iterators, we only needed to collect() the events into a Vec for demonstration purposes.

Re-exports

pub extern crate pulldown_cmark;

Structs

Always

A Matcher which matches everything.

Heading

Matches the start of a heading.

OneShot

A Matcher which will only ever return true once.

StartOfNextLine

A Matcher which will match the start of the next top-level element after some inner Matcher matches.

Writer

The output buffer used when rewrite() calls Rewriter::rewrite().

Traits

Matcher

A predicate which can be fed a stream of Events and tell you whether they match a desired condition.

Rewriter

Something which can rewrite events.

Functions

between

Gets all Events between (inclusive) two matchers.

change_text

A Rewriter which lets you update a Event::Text node based on some predicate.

exact_text

Match an Event::Text event with this exact text.

insert_after

Inserts some markdown text after whatever is matched by the Matcher.

link_with_url_containing

Matches the start of a link who's URL contains a certain string.

match_indices

Get an iterator over the indices of matching events.

parse

A convenience function for parsing some text into Events without needing to add pulldown_cmark as an explicit dependency.

rewrite

The whole point.

text

Match a Event::Text node using an arbitrary predicate.

text_containing

Match an Event::Text event which contains the provided string.