wowlab_common/markdown/
doc.rs1use super::inline::quote;
2
3const H2_LEVEL: u8 = 2;
4
5const H3_LEVEL: u8 = 3;
6
7#[derive(Debug)]
9pub struct Doc(Vec<Box<str>>);
10
11impl Doc {
12 #[must_use]
13 pub fn new() -> Self {
14 Self(Vec::new())
15 }
16
17 #[must_use]
18 pub fn line(mut self, text: &str) -> Self {
19 self.0.push(text.into());
20
21 self
22 }
23
24 #[must_use]
25 pub fn blank(mut self) -> Self {
26 self.0.push(Box::from(""));
27
28 self
29 }
30
31 #[must_use]
32 pub fn heading(mut self, level: u8, text: &str) -> Self {
33 self.0
34 .push(format!("{} {text}", "#".repeat(level as usize)).into_boxed_str());
35
36 self
37 }
38
39 #[must_use]
40 pub fn h1(self, text: &str) -> Self {
41 self.heading(1, text)
42 }
43
44 #[must_use]
45 pub fn h2(self, text: &str) -> Self {
46 self.heading(H2_LEVEL, text)
47 }
48
49 #[must_use]
50 pub fn h3(self, text: &str) -> Self {
51 self.heading(H3_LEVEL, text)
52 }
53
54 #[must_use]
55 pub fn numbered(mut self, n: usize, text: &str) -> Self {
56 self.0.push(format!("{n}. {text}").into_boxed_str());
57
58 self
59 }
60
61 #[must_use]
62 pub fn bullet(mut self, text: &str) -> Self {
63 self.0.push(format!("- {text}").into_boxed_str());
64
65 self
66 }
67
68 #[must_use]
70 pub fn kv_bullet(mut self, key: &str, value: &str) -> Self {
71 self.0
72 .push(format!("- **{key}:** {value}").into_boxed_str());
73
74 self
75 }
76
77 #[must_use]
79 pub fn def(mut self, term: &str, desc: &str) -> Self {
80 self.0.push(format!("- `{term}` — {desc}").into_boxed_str());
81
82 self
83 }
84
85 #[must_use]
87 pub fn def_detail(mut self, term: &str, detail: &str, desc: &str) -> Self {
88 self.0
89 .push(format!("- `{term}` ({detail}) — {desc}").into_boxed_str());
90
91 self
92 }
93
94 #[must_use]
97 pub fn quote(self, text: &str) -> Self {
98 self.raw(quote(text))
99 }
100
101 #[must_use]
102 pub fn code_block(mut self, language: &str, content: &str) -> Self {
103 if language.is_empty() {
104 self.0.push(format!("```\n{content}\n```").into_boxed_str());
105 } else {
106 self.0
107 .push(format!("```{language}\n{content}\n```").into_boxed_str());
108 }
109
110 self
111 }
112
113 #[must_use]
114 pub fn raw(mut self, text: String) -> Self {
115 self.0.push(text.into_boxed_str());
116
117 self
118 }
119
120 #[must_use]
121 pub fn build(self) -> String {
122 self.0.join("\n")
123 }
124}
125
126impl Default for Doc {
127 fn default() -> Self {
128 Self::new()
129 }
130}