cl_ast/
format.rs

1use delimiters::Delimiters;
2use std::fmt::Write;
3
4impl<W: Write + ?Sized> FmtAdapter for W {}
5pub trait FmtAdapter: Write {
6    fn indent(&mut self) -> Indent<Self> {
7        Indent { f: self }
8    }
9
10    fn delimit(&mut self, delim: Delimiters) -> Delimit<Self> {
11        Delimit::new(self, delim)
12    }
13
14    fn delimit_with(&mut self, open: &'static str, close: &'static str) -> Delimit<Self> {
15        Delimit::new(self, Delimiters { open, close })
16    }
17}
18
19/// Pads text with leading indentation after every newline
20pub struct Indent<'f, F: Write + ?Sized> {
21    f: &'f mut F,
22}
23
24impl<F: Write + ?Sized> Write for Indent<'_, F> {
25    fn write_str(&mut self, s: &str) -> std::fmt::Result {
26        for s in s.split_inclusive('\n') {
27            self.f.write_str(s)?;
28            if s.ends_with('\n') {
29                self.f.write_str("    ")?;
30            }
31        }
32        Ok(())
33    }
34}
35
36/// Prints [Delimiters] around anything formatted with this. Implies [Indent]
37pub struct Delimit<'f, F: Write + ?Sized> {
38    f: Indent<'f, F>,
39    delim: Delimiters,
40}
41impl<'f, F: Write + ?Sized> Delimit<'f, F> {
42    pub fn new(f: &'f mut F, delim: Delimiters) -> Self {
43        let mut f = f.indent();
44        let _ = f.write_str(delim.open);
45        Self { f, delim }
46    }
47}
48impl<F: Write + ?Sized> Drop for Delimit<'_, F> {
49    fn drop(&mut self) {
50        let Self { f: Indent { f, .. }, delim } = self;
51        let _ = f.write_str(delim.close);
52    }
53}
54
55impl<F: Write + ?Sized> Write for Delimit<'_, F> {
56    fn write_str(&mut self, s: &str) -> std::fmt::Result {
57        self.f.write_str(s)
58    }
59}
60
61pub mod delimiters {
62    #![allow(dead_code)]
63    #[derive(Clone, Copy, Debug)]
64    pub struct Delimiters {
65        pub open: &'static str,
66        pub close: &'static str,
67    }
68    /// Delimits with braces decorated with spaces  `" {\n"`, ..., `"\n}"`
69    pub const SPACED_BRACES: Delimiters = Delimiters { open: " {\n", close: "\n}" };
70    /// Delimits with braces on separate lines `{\n`, ..., `\n}`
71    pub const BRACES: Delimiters = Delimiters { open: "{\n", close: "\n}" };
72    /// Delimits with parentheses on separate lines `{\n`, ..., `\n}`
73    pub const PARENS: Delimiters = Delimiters { open: "(\n", close: "\n)" };
74    /// Delimits with square brackets on separate lines `{\n`, ..., `\n}`
75    pub const SQUARE: Delimiters = Delimiters { open: "[\n", close: "\n]" };
76    /// Delimits with braces on the same line `{ `, ..., ` }`
77    pub const INLINE_BRACES: Delimiters = Delimiters { open: "{ ", close: " }" };
78    /// Delimits with parentheses on the same line `( `, ..., ` )`
79    pub const INLINE_PARENS: Delimiters = Delimiters { open: "(", close: ")" };
80    /// Delimits with square brackets on the same line `[ `, ..., ` ]`
81    pub const INLINE_SQUARE: Delimiters = Delimiters { open: "[", close: "]" };
82}