citum_engine/render/
org.rs1use super::format::OutputFormat;
9use citum_schema::template::WrapPunctuation;
10
11#[derive(Default, Clone)]
13pub struct OrgOutputFormat;
14
15impl OutputFormat for OrgOutputFormat {
16 type Output = String;
17
18 fn text(&self, s: &str) -> Self::Output {
19 s.to_string()
20 }
21
22 fn join(&self, items: Vec<Self::Output>, delimiter: &str) -> Self::Output {
23 items.join(delimiter)
24 }
25
26 fn finish(&self, output: Self::Output) -> String {
27 output
28 }
29
30 fn emph(&self, content: Self::Output) -> Self::Output {
32 if content.is_empty() {
33 return content;
34 }
35 format!("/{content}/")
36 }
37
38 fn strong(&self, content: Self::Output) -> Self::Output {
40 if content.is_empty() {
41 return content;
42 }
43 format!("*{content}*")
44 }
45
46 fn small_caps(&self, content: Self::Output) -> Self::Output {
48 if content.is_empty() {
49 return content;
50 }
51 format!("~{content}~")
52 }
53
54 fn superscript(&self, content: Self::Output) -> Self::Output {
55 if content.is_empty() {
56 return content;
57 }
58 format!("^{content}^")
59 }
60
61 fn quote(&self, content: Self::Output) -> Self::Output {
62 if content.is_empty() {
63 return content;
64 }
65 format!("\u{201C}{content}\u{201D}")
67 }
68
69 fn affix(&self, prefix: &str, content: Self::Output, suffix: &str) -> Self::Output {
70 format!("{prefix}{content}{suffix}")
71 }
72
73 fn inner_affix(&self, prefix: &str, content: Self::Output, suffix: &str) -> Self::Output {
74 format!("{prefix}{content}{suffix}")
75 }
76
77 fn wrap_punctuation(&self, wrap: &WrapPunctuation, content: Self::Output) -> Self::Output {
78 match wrap {
79 WrapPunctuation::Parentheses => format!("({content})"),
80 WrapPunctuation::Brackets => format!("[{content}]"),
81 WrapPunctuation::Quotes => format!("\u{201C}{content}\u{201D}"),
82 }
83 }
84
85 fn semantic(&self, _class: &str, content: Self::Output) -> Self::Output {
86 content
88 }
89
90 fn annotation(&self, content: Self::Output) -> Self::Output {
91 if content.is_empty() {
92 return content;
93 }
94 format!(
95 "\n\n#+begin_citum_annotation\n{}\n#+end_citum_annotation",
96 content
97 )
98 }
99
100 fn link(&self, url: &str, content: Self::Output) -> Self::Output {
102 format!("[[{url}][{content}]]")
103 }
104
105 fn entry(
106 &self,
107 _id: &str,
108 content: Self::Output,
109 _url: Option<&str>,
110 _metadata: &super::format::ProcEntryMetadata,
111 ) -> Self::Output {
112 content
113 }
114}
115
116#[cfg(test)]
117#[allow(
118 clippy::unwrap_used,
119 clippy::expect_used,
120 clippy::panic,
121 clippy::indexing_slicing,
122 clippy::todo,
123 clippy::unimplemented,
124 clippy::unreachable,
125 clippy::get_unwrap,
126 reason = "Panicking is acceptable and often desired in tests."
127)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn test_org_emph() {
133 let fmt = OrgOutputFormat;
134 let result = fmt.emph(fmt.text("italic text"));
135 assert_eq!(result, "/italic text/");
136 }
137
138 #[test]
139 fn test_org_strong() {
140 let fmt = OrgOutputFormat;
141 let result = fmt.strong(fmt.text("bold text"));
142 assert_eq!(result, "*bold text*");
143 }
144
145 #[test]
146 fn test_org_small_caps() {
147 let fmt = OrgOutputFormat;
148 let result = fmt.small_caps(fmt.text("small caps"));
149 assert_eq!(result, "~small caps~");
150 }
151
152 #[test]
153 fn test_org_link() {
154 let fmt = OrgOutputFormat;
155 let result = fmt.link("https://example.com", fmt.text("Example"));
156 assert_eq!(result, "[[https://example.com][Example]]");
157 }
158
159 #[test]
160 fn test_org_empty_content() {
161 let fmt = OrgOutputFormat;
162 let result = fmt.emph(fmt.text(""));
163 assert_eq!(result, "");
164 }
165}