microcad_lang_markdown/
code_block.rs1#[derive(Debug, Clone, PartialEq)]
8pub struct CodeBlockHeader {
9 pub name: Option<String>,
11 pub fragment: Option<String>,
13 pub parameters: Vec<String>,
15}
16
17impl CodeBlockHeader {
19 pub fn test_banner_string(name: &str) -> String {
21 format!("[](.test/{name}.log)")
22 }
23
24 pub(crate) fn is_test_banner(line: &str) -> bool {
25 line.starts_with("[![test]")
26 }
27
28 pub(crate) fn is_code_block_start(line: &str) -> bool {
29 microcad_lang_base::MICROCAD_EXTENSIONS
30 .iter()
31 .any(|ext| line.starts_with(&format!("```{ext}")))
32 || Self::is_test_banner(line)
33 }
34}
35
36impl std::fmt::Display for CodeBlockHeader {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 if let Some(name) = &self.name {
39 writeln!(f, "{}\n", Self::test_banner_string(name))?
40 }
41
42 write!(f, "```µcad")?;
43 if let Some(name) = &self.name {
44 write!(f, ",{name}")?
45 }
46
47 match &self.fragment {
48 None => {}
49 Some(fragment) => {
50 write!(f, "#{fragment}")?;
51 }
52 };
53 if !self.parameters.is_empty() {
54 write!(f, "({})", self.parameters.join(","))?;
55 }
56 Ok(())
57 }
58}
59
60#[derive(Debug, Clone, PartialEq)]
62pub struct CodeBlock {
63 pub header: CodeBlockHeader,
65 pub code: String,
67 pub line_offset: usize,
69}
70
71impl CodeBlock {
72 pub fn name(&self) -> &Option<String> {
76 &self.header.name
77 }
78
79 pub fn fragment(&self) -> &Option<String> {
81 &self.header.fragment
82 }
83
84 pub fn code(&self) -> &str {
85 &self.code
86 }
87
88 pub fn line_offset(&self) -> usize {
89 self.line_offset
90 }
91
92 pub fn can_format(&self) -> bool {
96 !self.header.parameters.contains(&String::from("no_format"))
97 }
98}
99
100impl std::fmt::Display for CodeBlock {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 writeln!(f, "{}", self.header)?;
103 if !self.code.is_empty() {
104 writeln!(f, "{}", self.code)?;
105 }
106 write!(f, "```")
107 }
108}