oak_pretty_print/document/
mod.rs1use crate::{config::FormatConfig, document::printer::Printer};
2use alloc::{borrow::Cow, boxed::Box, string::String, vec::Vec};
3use core::fmt;
4
5pub mod printer;
6
7#[derive(Clone, serde::Serialize)]
9#[serde(tag = "kind", content = "value", rename_all = "camelCase")]
10pub enum Document<'a> {
11 Nil,
13 Text(Cow<'a, str>),
15 Concat(Vec<Document<'a>>),
17 Group(Box<Document<'a>>),
19 Indent(Box<Document<'a>>),
21 Line,
23 SoftLine,
25 SoftLineSpace,
27 HardLine,
29}
30
31impl<'a> fmt::Debug for Document<'a> {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 #[cfg(debug_assertions)]
34 {
35 match self {
36 Document::Nil => write!(f, "Nil"),
37 Document::Text(s) => write!(f, "Text({:?})", s),
38 Document::Concat(docs) => f.debug_list().entries(docs).finish(),
39 Document::Group(d) => f.debug_tuple("Group").field(d).finish(),
40 Document::Indent(d) => f.debug_tuple("Indent").field(d).finish(),
41 Document::Line => write!(f, "Line"),
42 Document::SoftLine => write!(f, "SoftLine"),
43 Document::SoftLineSpace => write!(f, "SoftLineSpace"),
44 Document::HardLine => write!(f, "HardLine"),
45 }
46 }
47 #[cfg(not(debug_assertions))]
48 {
49 match self {
50 Document::Nil => write!(f, "Doc::Nil"),
51 Document::Text(_) => write!(f, "Doc::Text"),
52 Document::Concat(_) => write!(f, "Doc::Concat"),
53 Document::Group(_) => write!(f, "Doc::Group"),
54 Document::Indent(_) => write!(f, "Doc::Indent"),
55 Document::Line => write!(f, "Doc::Line"),
56 Document::SoftLine => write!(f, "Doc::SoftLine"),
57 Document::SoftLineSpace => write!(f, "Doc::SoftLineSpace"),
58 Document::HardLine => write!(f, "Doc::HardLine"),
59 }
60 }
61 }
62}
63
64impl<'a> Document<'a> {
65 pub fn render(&self, config: FormatConfig) -> String {
67 Printer::new(config).print(self)
68 }
69
70 pub fn text<S: Into<Cow<'a, str>>>(text: S) -> Self {
72 Document::Text(text.into())
73 }
74
75 pub fn concat(docs: Vec<Document<'a>>) -> Self {
77 Document::Concat(docs)
78 }
79
80 pub fn group(doc: Document<'a>) -> Self {
82 Document::Group(Box::new(doc))
83 }
84
85 pub fn indent(doc: Document<'a>) -> Self {
87 Document::Indent(Box::new(doc))
88 }
89
90 pub fn join<I>(docs: I, separator: Document<'a>) -> Self
92 where
93 I: IntoIterator<Item = Document<'a>>,
94 {
95 let mut result = Vec::new();
96 for (i, doc) in docs.into_iter().enumerate() {
97 if i > 0 {
98 result.push(separator.clone());
99 }
100 result.push(doc);
101 }
102 Document::Concat(result)
103 }
104}
105
106impl<'a> From<Cow<'a, str>> for Document<'a> {
107 fn from(s: Cow<'a, str>) -> Self {
108 Document::Text(s)
109 }
110}
111
112impl From<String> for Document<'_> {
113 fn from(s: String) -> Self {
114 Document::Text(s.into())
115 }
116}
117
118impl<'a> From<&'a str> for Document<'a> {
119 fn from(s: &'a str) -> Self {
120 Document::Text(s.into())
121 }
122}
123
124pub trait JoinDoc<'a> {
125 fn join_doc(self, separator: Document<'a>) -> Vec<Document<'a>>;
126}
127
128impl<'a, I> JoinDoc<'a> for I
129where
130 I: IntoIterator<Item = Document<'a>>,
131{
132 fn join_doc(self, separator: Document<'a>) -> Vec<Document<'a>> {
133 let mut result = Vec::new();
134 for (i, doc) in self.into_iter().enumerate() {
135 if i > 0 {
136 result.push(separator.clone());
137 }
138 result.push(doc);
139 }
140 result
141 }
142}