quake_core/markdown/
entry_reference.rs

1use lazy_static::lazy_static;
2use regex::Regex;
3use std::fmt;
4
5lazy_static! {
6    static ref ENTRY_LINK_RE: Regex =
7        Regex::new(r#"^(?P<type>[^#|:]+):(?P<id>\d+)(#(?P<section>.+?))??(\|(?P<label>.+?))??(\s["'“](?P<title>.+?)["'”])??$"#).unwrap();
8}
9
10/// one markdown file link to other markdown file
11#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
12pub struct PageReference {
13    pub(crate) entry_type: String,
14    pub(crate) entry_id: String,
15    pub(crate) entry_title: String,
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub(crate) label: Option<String>,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub(crate) section: Option<String>,
20}
21
22impl PageReference {
23    #[allow(clippy::all)]
24    pub fn from_str(text: &str) -> PageReference {
25        let captures = match ENTRY_LINK_RE.captures(text) {
26            None => return PageReference::default(),
27            Some(capts) => capts,
28        };
29
30        let entry_type = captures.name("type").map(|v| v.as_str()).unwrap_or("");
31        let entry_id = captures.name("id").map(|v| v.as_str()).unwrap_or("");
32        let entry_title = captures.name("title").map(|v| v.as_str()).unwrap_or("");
33
34        let label = captures.name("label").map(|v| v.as_str().to_string());
35        let section = captures.name("section").map(|v| v.as_str().to_string());
36
37        PageReference {
38            entry_type: entry_type.to_string(),
39            entry_id: entry_id.to_string(),
40            entry_title: entry_title.to_string(),
41            label,
42            section,
43        }
44    }
45
46    pub fn display(&self) -> String {
47        format!("{}", self)
48    }
49}
50
51impl<'a> fmt::Display for PageReference {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        let label = self
54            .label
55            .as_ref()
56            .map(|text| format!("|{:}", text))
57            .unwrap_or_else(|| "".to_string());
58        let section = self
59            .section
60            .as_ref()
61            .map(|text| format!("#{:}", text))
62            .unwrap_or_else(|| "".to_string());
63
64        write!(
65            f,
66            "{}:{}{}{} \"{}\"",
67            self.entry_type, self.entry_id, section, label, self.entry_title
68        )
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use crate::markdown::entry_reference::PageReference;
75
76    #[test]
77    fn parse_quake_down_link() {
78        let text = r#"note:0001#Heading|Label "file name""#;
79        let reference = PageReference::from_str(text);
80
81        assert_eq!("note", reference.entry_type);
82        assert_eq!("file name", reference.entry_title);
83        assert_eq!("0001", reference.entry_id);
84
85        assert_eq!("Label", reference.label.unwrap());
86        assert_eq!("Heading", reference.section.unwrap());
87    }
88
89    #[test]
90    fn parse_normal() {
91        let text = r#"note:0001 "file name""#;
92        let reference = PageReference::from_str(text);
93
94        assert_eq!("note", reference.entry_type);
95        assert_eq!("file name", reference.entry_title);
96        assert_eq!("0001", reference.entry_id);
97
98        assert!(reference.label.is_none());
99        assert!(reference.section.is_none());
100    }
101
102    #[test]
103    fn print_reference() {
104        let text = r#"note:0001 "file name""#;
105        let reference = PageReference::from_str(text);
106        assert_eq!(text, reference.to_string());
107
108        let with_title = r#"note:0001#heading "file name""#;
109        let title_ref = PageReference::from_str(with_title);
110        assert_eq!(with_title, title_ref.to_string());
111
112        let with_label = r#"note:0001#heading|label "file name""#;
113        let label_ref = PageReference::from_str(with_label);
114        assert_eq!(with_label, label_ref.to_string());
115
116        let only_label = r#"Note:0001|Label "file name""#;
117        let only_label_ref = PageReference::from_str(only_label);
118        assert_eq!(only_label, only_label_ref.to_string());
119    }
120}