1use std::marker::PhantomData;
4
5use crate::syntax::{Blocks, Comments, Literals};
6
7pub struct Code<L> {
9 out: String,
10 depth: usize,
11 lang: PhantomData<L>,
12}
13
14impl<L: Blocks + Comments + Literals> Code<L> {
15 pub fn new() -> Self {
17 Self::starting(String::new())
18 }
19
20 pub fn starting(text: impl Into<String>) -> Self {
22 Self {
23 out: text.into(),
24 depth: 0,
25 lang: PhantomData,
26 }
27 }
28
29 pub fn str(&self, text: &str) -> String {
31 L::string(text)
32 }
33
34 pub fn line(&mut self, text: impl AsRef<str>) -> &mut Self {
36 for _ in 0..self.depth {
37 self.out.push_str(L::INDENT);
38 }
39 self.out.push_str(text.as_ref());
40 self.out.push('\n');
41 self
42 }
43
44 pub fn blank(&mut self) -> &mut Self {
46 self.out.push('\n');
47 self
48 }
49
50 pub fn doc(&mut self, text: impl AsRef<str>) -> &mut Self {
52 self.line(L::doc(text.as_ref()))
53 }
54
55 pub fn open(&mut self, head: impl AsRef<str>) -> &mut Self {
57 self.line(L::open(head.as_ref()));
58 self.depth += 1;
59 self
60 }
61
62 pub fn close(&mut self, tail: &str) -> &mut Self {
64 self.depth = self.depth.saturating_sub(1);
65 self.line(L::close(tail))
66 }
67
68 pub fn finish(self) -> String {
70 self.out
71 }
72}
73
74impl<L: Blocks + Comments + Literals> Default for Code<L> {
75 fn default() -> Self {
76 Self::new()
77 }
78}
79
80#[cfg(test)]
81mod tests;