markdown_it/plugins/
sourcepos.rs1use crate::common::sourcemap::SourceWithLineStarts;
11use crate::parser::block::builtin::BlockParserRule;
12use crate::parser::core::{CoreRule, Root};
13use crate::parser::inline::builtin::InlineParserRule;
14use crate::{MarkdownIt, Node};
15
16pub fn add(md: &mut MarkdownIt) {
17 md.add_rule::<SyntaxPosRule>()
18 .after::<BlockParserRule>()
19 .after::<InlineParserRule>();
20}
21
22#[doc(hidden)]
23pub struct SyntaxPosRule;
24impl CoreRule for SyntaxPosRule {
25 fn run(root: &mut Node, _: &MarkdownIt) {
26 let source = root.cast::<Root>().unwrap().content.as_str();
27 let mapping = SourceWithLineStarts::new(source);
28
29 root.walk_mut(|node, _| {
30 if let Some(map) = node.srcmap {
31 let ((startline, startcol), (endline, endcol)) = map.get_positions(&mapping);
32 node.attrs.push(("data-sourcepos", format!("{}:{}-{}:{}", startline, startcol, endline, endcol)));
33 }
34 });
35 }
36}
37
38
39#[cfg(test)]
40mod tests {
41 #[test]
42 fn header_test() {
43 let md = &mut crate::MarkdownIt::new();
46 crate::plugins::cmark::add(md);
47 crate::plugins::sourcepos::add(md);
48
49 let html = md.parse("# hello").render();
50 assert_eq!(html.trim(), r#"<h1 data-sourcepos="1:1-1:7">hello</h1>"#);
51 }
52}