twrite_core/batteries/markdown/
links.rs1use std::ops::Range;
2
3use pulldown_cmark::{Event, Options, Parser, Tag, TagEnd};
4
5pub fn extract_markdown_links(line_text: &str) -> Vec<(Range<usize>, String)> {
7 let mut options = Options::empty();
8 options.insert(Options::ENABLE_STRIKETHROUGH);
9 options.insert(Options::ENABLE_TASKLISTS);
10 let parser = Parser::new_ext(line_text, options).into_offset_iter();
11 let mut links = Vec::new();
12 let mut current_link: Option<(usize, String)> = None;
13
14 for (event, range) in parser {
15 match event {
16 Event::Start(Tag::Link { dest_url, .. }) => {
17 current_link = Some((range.start, dest_url.to_string()));
18 }
19 Event::End(TagEnd::Link) => {
20 if let Some((start, dest_url)) = current_link.take() {
21 let end = range.end.min(line_text.len());
22 if let Some(bracket_idx) = line_text[start..end].find("](") {
23 let label_start = start + 1;
24 let label_end = start + bracket_idx;
25 links.push((label_start..label_end, dest_url));
26 } else if let Some(bracket_idx) = line_text[start..end].find("][") {
27 let label_start = start + 1;
28 let label_end = start + bracket_idx;
29 links.push((label_start..label_end, dest_url));
30 } else if line_text[start..end].starts_with('<')
31 && line_text[start..end].ends_with('>')
32 {
33 links.push((start + 1..end - 1, dest_url));
34 } else {
35 links.push((start..end, dest_url));
36 }
37 }
38 }
39 _ => {}
40 }
41 }
42 links
43}
44
45#[cfg(test)]
46mod tests {
47 use super::super::highlight::MarkdownHighlighter;
48 use crate::{EditorBuffer, SyntaxHighlighter};
49
50 #[test]
51 fn test_markdown_highlighter_extract_links_trait() {
52 let buffer = EditorBuffer::new("[Google](https://google.com)");
53 let highlighter = MarkdownHighlighter::new();
54 let links = highlighter.extract_links(&buffer, 0, "[Google](https://google.com)");
55 assert_eq!(links.len(), 1);
56 assert_eq!(links[0].0, 1..7);
57 assert_eq!(links[0].1, "https://google.com");
58
59 let none = highlighter.extract_links(&buffer, 0, "plain text");
60 assert!(none.is_empty());
61 }
62}