pulldown_html_ext/html/
default.rs1use pulldown_cmark_escape::StrWrite;
2
3use crate::html::config::HtmlConfig;
4use crate::html::state::HtmlState;
5use crate::html::writer::HtmlWriter;
6use crate::html_writer;
7
8pub struct HtmlWriterBase<W: StrWrite> {
10 writer: W,
11 config: HtmlConfig,
12 state: HtmlState,
13}
14
15impl<W: StrWrite> HtmlWriterBase<W> {
16 pub fn new(writer: W, config: HtmlConfig) -> Self {
18 Self {
19 writer,
20 config,
21 state: HtmlState::new(),
22 }
23 }
24
25 pub fn get_writer(&mut self) -> &mut W {
27 &mut self.writer
28 }
29
30 pub fn get_config(&self) -> &HtmlConfig {
32 &self.config
33 }
34
35 pub fn get_state(&mut self) -> &mut HtmlState {
37 &mut self.state
38 }
39}
40
41#[html_writer]
45pub struct DefaultHtmlWriter<W: StrWrite> {
46 base: HtmlWriterBase<W>,
47}
48
49impl<W: StrWrite> DefaultHtmlWriter<W> {
50 pub fn new(writer: W, config: HtmlConfig) -> Self {
52 Self {
53 base: HtmlWriterBase::new(writer, config.clone()),
54 }
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use pulldown_cmark_escape::{escape_html, FmtWriter};
62 use std::fmt;
63
64 #[test]
65 fn test_basic_writing() {
66 let mut output = String::new();
67 let config = HtmlConfig::default();
68 let mut writer = DefaultHtmlWriter::new(FmtWriter(&mut output), config);
69
70 writer.write_str("<p>").unwrap();
71 let _ = escape_html(&mut writer.get_writer(), "Hello & World");
72 writer.write_str("</p>").unwrap();
73
74 assert_eq!(output, "<p>Hello & World</p>");
75 }
76
77 #[test]
78 fn test_attributes() {
79 let mut output = String::new();
80 let mut config = HtmlConfig::default();
81 config.attributes.element_attributes.insert(
82 "p".to_string(),
83 [("class".to_string(), "test".to_string())]
84 .into_iter()
85 .collect(),
86 );
87
88 let mut writer = DefaultHtmlWriter::new(FmtWriter(&mut output), config);
89 writer.start_paragraph().unwrap();
90 writer.text("Test").unwrap();
91 writer.end_paragraph().unwrap();
92
93 assert_eq!(output, r#"<p class="test">Test</p>"#);
94 }
95
96 struct TestWriter(String);
97
98 impl StrWrite for TestWriter {
99 type Error = fmt::Error;
100
101 fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
102 self.0.push_str(s);
103 Ok(())
104 }
105
106 fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<(), Self::Error> {
107 fmt::write(self, args)
108 }
109 }
110
111 impl fmt::Write for TestWriter {
112 fn write_str(&mut self, s: &str) -> fmt::Result {
113 self.0.push_str(s);
114 Ok(())
115 }
116 }
117
118 #[test]
119 fn test_custom_writer() {
120 let config = HtmlConfig::default();
121 let mut writer = DefaultHtmlWriter::new(TestWriter(String::new()), config);
122
123 writer.write_str("Test").unwrap();
124 assert_eq!(writer.get_writer().0, "Test");
125 }
126
127 #[test]
128 fn test_state_tracking() {
129 let mut output = String::new();
130 let mut config = HtmlConfig::default();
131 config.html.escape_html = true;
132 let mut writer = DefaultHtmlWriter::new(FmtWriter(&mut output), config);
133
134 assert!(!writer.get_state().currently_in_code_block);
135 writer.get_state().currently_in_code_block = true;
136 writer
137 .start_code_block(pulldown_cmark::CodeBlockKind::Fenced("rust".into()))
138 .unwrap();
139 assert!(writer.get_state().currently_in_code_block);
140 writer.end_code_block().unwrap();
141 writer.get_state().currently_in_code_block = false;
142 assert!(!writer.get_state().currently_in_code_block);
143 }
144}