marco_core/intelligence/markdown/
inlines.rs1use super::ast::{is_inline_kind, Node, NodeKind};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum InlineCategory {
9 Text,
10 TaskCheckboxInline,
11 Emphasis,
12 Strong,
13 StrongEmphasis,
14 Strikethrough,
15 Mark,
16 Superscript,
17 Subscript,
18 Link,
19 LinkReference,
20 FootnoteReference,
21 Image,
22 CodeSpan,
23 InlineHtml,
24 HardBreak,
25 SoftBreak,
26 PlatformMention,
27 InlineMath,
28 DisplayMath,
29}
30
31pub fn classify_inline_kind(kind: &NodeKind) -> Option<InlineCategory> {
32 match kind {
33 NodeKind::Text(_) => Some(InlineCategory::Text),
34 NodeKind::TaskCheckboxInline { .. } => Some(InlineCategory::TaskCheckboxInline),
35 NodeKind::Emphasis => Some(InlineCategory::Emphasis),
36 NodeKind::Strong => Some(InlineCategory::Strong),
37 NodeKind::StrongEmphasis => Some(InlineCategory::StrongEmphasis),
38 NodeKind::Strikethrough => Some(InlineCategory::Strikethrough),
39 NodeKind::Mark => Some(InlineCategory::Mark),
40 NodeKind::Superscript => Some(InlineCategory::Superscript),
41 NodeKind::Subscript => Some(InlineCategory::Subscript),
42 NodeKind::Link { .. } => Some(InlineCategory::Link),
43 NodeKind::LinkReference { .. } => Some(InlineCategory::LinkReference),
44 NodeKind::FootnoteReference { .. } => Some(InlineCategory::FootnoteReference),
45 NodeKind::Image { .. } => Some(InlineCategory::Image),
46 NodeKind::CodeSpan(_) => Some(InlineCategory::CodeSpan),
47 NodeKind::InlineHtml(_) => Some(InlineCategory::InlineHtml),
48 NodeKind::HardBreak => Some(InlineCategory::HardBreak),
49 NodeKind::SoftBreak => Some(InlineCategory::SoftBreak),
50 NodeKind::PlatformMention { .. } => Some(InlineCategory::PlatformMention),
51 NodeKind::InlineMath { .. } => Some(InlineCategory::InlineMath),
52 NodeKind::DisplayMath { .. } => Some(InlineCategory::DisplayMath),
53 _ => None,
54 }
55}
56
57pub fn is_inline_node(node: &Node) -> bool {
58 is_inline_kind(&node.kind)
59}
60
61pub fn collect_inline_nodes<'a>(nodes: &'a [Node], out: &mut Vec<&'a Node>) {
63 for node in nodes {
64 if is_inline_node(node) {
65 out.push(node);
66 }
67 if !node.children.is_empty() {
68 collect_inline_nodes(&node.children, out);
69 }
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn smoke_test_classify_inline_kind_basic() {
79 assert_eq!(
80 classify_inline_kind(&NodeKind::Text("x".to_string())),
81 Some(InlineCategory::Text)
82 );
83 assert_eq!(classify_inline_kind(&NodeKind::Paragraph), None);
84 }
85
86 #[test]
87 fn smoke_test_collect_inline_nodes_recursive() {
88 let nodes = vec![Node {
89 kind: NodeKind::Paragraph,
90 span: None,
91 children: vec![Node {
92 kind: NodeKind::Link {
93 url: "https://example.com".to_string(),
94 title: None,
95 },
96 span: None,
97 children: vec![Node {
98 kind: NodeKind::Text("example".to_string()),
99 span: None,
100 children: vec![],
101 }],
102 }],
103 }];
104
105 let mut inlines = Vec::new();
106 collect_inline_nodes(&nodes, &mut inlines);
107
108 assert_eq!(inlines.len(), 2);
109 assert!(matches!(inlines[0].kind, NodeKind::Link { .. }));
110 assert!(matches!(inlines[1].kind, NodeKind::Text(_)));
111 }
112}