Skip to main content

rushdown_link_attribute/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4extern crate alloc;
5use alloc::boxed::Box;
6use alloc::rc::Rc;
7use alloc::vec::Vec;
8use core::cell::RefCell;
9use rushdown::ast::Arena;
10use rushdown::ast::NodeRef;
11use rushdown::ast::Text;
12use rushdown::context::ContextKey;
13use rushdown::context::ContextKeyRegistry;
14use rushdown::context::ObjectValue;
15use rushdown::matches_kind;
16use rushdown::parser;
17use rushdown::parser::parse_attributes;
18use rushdown::parser::parser_extension;
19use rushdown::parser::AnyInlineParser;
20use rushdown::parser::InlineParser;
21use rushdown::parser::NoParserOptions;
22use rushdown::parser::Parser;
23use rushdown::parser::ParserExtension;
24use rushdown::text;
25
26// Parser {{{
27
28#[derive(Debug)]
29struct LinkAttributeParser {
30    list: ContextKey<ObjectValue>,
31}
32
33impl LinkAttributeParser {
34    fn new(reg: Rc<RefCell<ContextKeyRegistry>>) -> Self {
35        Self {
36            list: reg.borrow_mut().create::<ObjectValue>(),
37        }
38    }
39}
40
41impl InlineParser for LinkAttributeParser {
42    fn trigger(&self) -> &[u8] {
43        b"{"
44    }
45
46    fn parse(
47        &self,
48        arena: &mut Arena,
49        parent_ref: NodeRef,
50        reader: &mut text::BlockReader,
51        ctx: &mut parser::Context,
52    ) -> Option<NodeRef> {
53        let prev = arena[parent_ref].last_child()?;
54        if !matches_kind!(arena[prev], Link) && !matches_kind!(arena[prev], Image) {
55            return None;
56        }
57        let attributes = parse_attributes(reader)?;
58        arena[prev].attributes_mut().extend(attributes);
59        let n = arena.new_node(Text::new(text::Index::new(0, 0)));
60
61        let mut list_opt = ctx.get_mut(self.list);
62        if list_opt.is_none() {
63            ctx.insert(self.list, Box::new(Vec::<NodeRef>::new()));
64            list_opt = ctx.get_mut(self.list);
65        }
66        let list = list_opt.unwrap().downcast_mut::<Vec<NodeRef>>().unwrap();
67        list.push(n);
68
69        Some(n)
70    }
71
72    fn close_block(
73        &self,
74        arena: &mut Arena,
75        _node_ref: NodeRef,
76        _reader: &mut text::BlockReader,
77        ctx: &mut parser::Context,
78    ) {
79        if let Some(list) = ctx.get_mut(self.list) {
80            let list = list.downcast_mut::<Vec<NodeRef>>().unwrap();
81            for n in list.drain(..) {
82                n.delete(arena);
83            }
84        }
85    }
86}
87
88impl From<LinkAttributeParser> for AnyInlineParser {
89    fn from(p: LinkAttributeParser) -> Self {
90        AnyInlineParser::Extension(Box::new(p))
91    }
92}
93
94// }}}
95
96// Extension {{{
97
98/// Returns a parser extension that parses link attributes.
99pub fn link_attribute_parser_extension() -> impl ParserExtension {
100    parser_extension(|p: &mut Parser| {
101        p.add_inline_parser(LinkAttributeParser::new, NoParserOptions, 500);
102    })
103}
104
105// }}}