citum_engine/render/
plain.rs1use super::format::{OutputFormat, QuoteMarks};
9use citum_schema::template::WrapPunctuation;
10
11#[derive(Default, Clone)]
12pub struct PlainText;
14
15impl OutputFormat for PlainText {
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 heading(&self, level: u8, content: Self::Output) -> Self::Output {
31 let marks = "#".repeat(level.max(1) as usize);
32 format!("{marks} {content}\n\n")
33 }
34
35 fn emph(&self, content: Self::Output) -> Self::Output {
36 if content.is_empty() {
37 return content;
38 }
39 format!("_{content}_")
40 }
41
42 fn strong(&self, content: Self::Output) -> Self::Output {
43 if content.is_empty() {
44 return content;
45 }
46 format!("**{content}**")
47 }
48
49 fn small_caps(&self, content: Self::Output) -> Self::Output {
50 content.to_uppercase()
51 }
52
53 fn superscript(&self, content: Self::Output) -> Self::Output {
54 if content.is_empty() {
55 return content;
56 }
57 format!("^{content}^")
58 }
59
60 fn quote(&self, content: Self::Output, marks: &QuoteMarks) -> Self::Output {
61 if content.is_empty() {
62 return content;
63 }
64 let (open, close) = marks.for_depth(0);
65 format!("{open}{content}{close}")
66 }
67
68 fn affix(&self, prefix: &str, content: Self::Output, suffix: &str) -> Self::Output {
69 format!("{prefix}{content}{suffix}")
70 }
71
72 fn inner_affix(&self, prefix: &str, content: Self::Output, suffix: &str) -> Self::Output {
73 format!("{prefix}{content}{suffix}")
74 }
75
76 fn wrap_punctuation(
77 &self,
78 wrap: &WrapPunctuation,
79 content: Self::Output,
80 marks: &QuoteMarks,
81 ) -> Self::Output {
82 match wrap {
83 WrapPunctuation::Parentheses => format!("({content})"),
84 WrapPunctuation::Brackets => format!("[{content}]"),
85 WrapPunctuation::Quotes => self.quote(content, marks),
86 }
87 }
88
89 fn semantic(&self, _class: &str, content: Self::Output) -> Self::Output {
90 content
92 }
93
94 fn annotation(&self, content: Self::Output) -> Self::Output {
95 if content.is_empty() {
96 return content;
97 }
98
99 format!("\n\n{content}")
100 }
101
102 fn link(&self, _url: &str, content: Self::Output) -> Self::Output {
103 content
105 }
106
107 fn entry(
108 &self,
109 _id: &str,
110 content: Self::Output,
111 _url: Option<&str>,
112 _metadata: &super::format::ProcEntryMetadata,
113 ) -> Self::Output {
114 content
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn small_caps_preserves_empty_text() {
124 let fmt = PlainText;
125
126 assert_eq!(fmt.small_caps(String::new()), "");
127 }
128
129 #[test]
130 fn small_caps_uppercases_plain_text() {
131 let fmt = PlainText;
132
133 assert_eq!(
134 fmt.small_caps("Smith and Lumière".to_string()),
135 "SMITH AND LUMIÈRE"
136 );
137 }
138}