normalize_languages/
markdown.rs1use crate::{ContainerBody, Language, LanguageSymbols};
4use tree_sitter::Node;
5
6pub struct Markdown;
8
9impl Language for Markdown {
10 fn name(&self) -> &'static str {
11 "Markdown"
12 }
13 fn extensions(&self) -> &'static [&'static str] {
14 &["md", "markdown"]
15 }
16 fn grammar_name(&self) -> &'static str {
17 "markdown"
18 }
19
20 fn as_symbols(&self) -> Option<&dyn LanguageSymbols> {
21 Some(self)
22 }
23
24 fn container_body<'a>(&self, node: &'a Node<'a>) -> Option<Node<'a>> {
28 Some(*node)
31 }
32 fn analyze_container_body(
33 &self,
34 section_node: &Node,
35 _content: &str,
36 _inner_indent: &str,
37 ) -> Option<ContainerBody> {
38 let mut cursor = section_node.walk();
40 let mut children = section_node.children(&mut cursor);
41 children.next(); let content_start = children
43 .next()
44 .map(|n| n.start_byte())
45 .unwrap_or(section_node.end_byte());
46 let content_end = section_node.end_byte();
47 Some(ContainerBody {
48 content_start,
49 content_end,
50 inner_indent: String::new(),
51 is_empty: content_start >= content_end,
52 })
53 }
54
55 fn node_name<'a>(&self, node: &Node, content: &'a str) -> Option<&'a str> {
56 let heading = node.child(0).filter(|c| c.kind() == "atx_heading")?;
58 let mut cursor = heading.walk();
59 let inline = heading
60 .children(&mut cursor)
61 .find(|c| c.kind() == "inline")?;
62 Some(content[inline.byte_range()].trim())
63 }
64}
65
66impl LanguageSymbols for Markdown {}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use crate::validate_unused_kinds_audit;
72
73 #[test]
74 fn unused_node_kinds_audit() {
75 #[rustfmt::skip]
76 let documented_unused: &[&str] = &[
77 "block_continuation", "block_quote", "block_quote_marker",
78 "fenced_code_block", "fenced_code_block_delimiter",
79 "html_block", "indented_code_block", "link_reference_definition",
80 ];
81 validate_unused_kinds_audit(&Markdown, documented_unused)
84 .expect("Markdown unused node kinds audit failed");
85 }
86}