rushdown/parser/
auto_link.rs1extern crate alloc;
2
3use alloc::string::String;
4
5use crate::ast::{Arena, Link, NodeRef, Text};
6use crate::parser::{Context, InlineParser};
7use crate::scanner::{scan_email, scan_url};
8use crate::text::{self, Reader, Segment};
9
10#[derive(Debug, Default)]
12pub struct AutoLinkParser {}
13
14impl AutoLinkParser {
15 pub fn new() -> Self {
17 Self::default()
18 }
19}
20
21impl InlineParser for AutoLinkParser {
22 fn trigger(&self) -> &[u8] {
23 b"<"
24 }
25
26 fn parse(
27 &self,
28 arena: &mut Arena,
29 _parent_ref: NodeRef,
30 reader: &mut text::BlockReader,
31 _ctx: &mut Context,
32 ) -> Option<NodeRef> {
33 let (line, segment) = reader.peek_line_bytes()?;
34 if let Some(p) = scan_url(&line[1..]) {
35 reader.advance(1 + p);
36 if reader.peek_byte() == b'>' {
37 reader.advance(1);
38 let seg: Segment = (segment.start() + 1, segment.start() + p + 1).into();
39 let seg_text: Segment = (segment.start(), segment.start() + p + 2).into();
40 let node_ref = arena.new_node(Link::auto(seg, seg_text));
41 let text_ref = arena.new_node(Text::new(seg));
42 node_ref.append_child_fast(arena, text_ref);
43 return Some(node_ref);
44 }
45 }
46 if let Some(p) = scan_email(&line[1..]) {
47 reader.advance(1 + p);
48 if reader.peek_byte() == b'>' {
49 reader.advance(1);
50 let mut s = String::new();
51 s.push_str("mailto:");
52 let addr = unsafe { core::str::from_utf8_unchecked(&line[1..p + 1]) };
53 let addr_seg: Segment = (segment.start() + 1, segment.start() + p + 1).into();
54 s.push_str(addr);
55 let seg: Segment = (segment.start(), segment.start() + p + 2).into();
56 let node_ref = arena.new_node(Link::auto(s, seg));
57 let text_ref = arena.new_node(Text::new(addr_seg));
58 node_ref.append_child_fast(arena, text_ref);
59 return Some(node_ref);
60 }
61 }
62 None
63 }
64}