#![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::vec::Vec;
use core::cell::RefCell;
use rushdown::ast::Arena;
use rushdown::ast::NodeRef;
use rushdown::ast::Text;
use rushdown::context::ContextKey;
use rushdown::context::ContextKeyRegistry;
use rushdown::context::ObjectValue;
use rushdown::matches_kind;
use rushdown::parser;
use rushdown::parser::parse_attributes;
use rushdown::parser::parser_extension;
use rushdown::parser::AnyInlineParser;
use rushdown::parser::InlineParser;
use rushdown::parser::NoParserOptions;
use rushdown::parser::Parser;
use rushdown::parser::ParserExtension;
use rushdown::text;
#[derive(Debug)]
struct LinkAttributeParser {
list: ContextKey<ObjectValue>,
}
impl LinkAttributeParser {
fn new(reg: Rc<RefCell<ContextKeyRegistry>>) -> Self {
Self {
list: reg.borrow_mut().create::<ObjectValue>(),
}
}
}
impl InlineParser for LinkAttributeParser {
fn trigger(&self) -> &[u8] {
b"{"
}
fn parse(
&self,
arena: &mut Arena,
parent_ref: NodeRef,
reader: &mut text::BlockReader,
ctx: &mut parser::Context,
) -> Option<NodeRef> {
let prev = arena[parent_ref].last_child()?;
if !matches_kind!(arena[prev], Link) && !matches_kind!(arena[prev], Image) {
return None;
}
let attributes = parse_attributes(reader)?;
arena[prev].attributes_mut().extend(attributes);
let n = arena.new_node(Text::new(text::Index::new(0, 0)));
let mut list_opt = ctx.get_mut(self.list);
if list_opt.is_none() {
ctx.insert(self.list, Box::new(Vec::<NodeRef>::new()));
list_opt = ctx.get_mut(self.list);
}
let list = list_opt.unwrap().downcast_mut::<Vec<NodeRef>>().unwrap();
list.push(n);
Some(n)
}
fn close_block(
&self,
arena: &mut Arena,
_node_ref: NodeRef,
_reader: &mut text::BlockReader,
ctx: &mut parser::Context,
) {
if let Some(list) = ctx.get_mut(self.list) {
let list = list.downcast_mut::<Vec<NodeRef>>().unwrap();
for n in list.drain(..) {
n.delete(arena);
}
}
}
}
impl From<LinkAttributeParser> for AnyInlineParser {
fn from(p: LinkAttributeParser) -> Self {
AnyInlineParser::Extension(Box::new(p))
}
}
pub fn link_attribute_parser_extension() -> impl ParserExtension {
parser_extension(|p: &mut Parser| {
p.add_inline_parser(LinkAttributeParser::new, NoParserOptions, 500);
})
}