1use std::cmp;
2use std::fmt;
3use std::io;
4use std::ops::Deref;
5#[cfg(feature = "termcolor")]
6use termcolor::{ColorSpec, WriteColor};
7
8use Doc;
9
10pub trait Render {
12 type Error;
13
14 fn write_str(&mut self, s: &str) -> Result<usize, Self::Error>;
15
16 fn write_str_all(&mut self, mut s: &str) -> Result<(), Self::Error> {
17 while !s.is_empty() {
18 let count = self.write_str(s)?;
19 s = &s[count..];
20 }
21 Ok(())
22 }
23}
24
25pub struct IoWrite<W> {
27 upstream: W,
28}
29
30impl<W> IoWrite<W> {
31 pub fn new(upstream: W) -> IoWrite<W> {
32 IoWrite { upstream }
33 }
34}
35
36impl<W> Render for IoWrite<W>
37where
38 W: io::Write,
39{
40 type Error = io::Error;
41
42 fn write_str(&mut self, s: &str) -> io::Result<usize> {
43 self.upstream.write(s.as_bytes())
44 }
45
46 fn write_str_all(&mut self, s: &str) -> io::Result<()> {
47 self.upstream.write_all(s.as_bytes())
48 }
49}
50
51pub struct FmtWrite<W> {
53 upstream: W,
54}
55
56impl<W> FmtWrite<W> {
57 pub fn new(upstream: W) -> FmtWrite<W> {
58 FmtWrite { upstream }
59 }
60}
61
62impl<W> Render for FmtWrite<W>
63where
64 W: fmt::Write,
65{
66 type Error = fmt::Error;
67
68 fn write_str(&mut self, s: &str) -> Result<usize, fmt::Error> {
69 self.write_str_all(s).map(|_| s.len())
70 }
71
72 fn write_str_all(&mut self, s: &str) -> fmt::Result {
73 self.upstream.write_str(s)
74 }
75}
76
77pub trait RenderAnnotated<A>: Render {
79 fn push_annotation(&mut self, annotation: &A) -> Result<(), Self::Error>;
80 fn pop_annotation(&mut self) -> Result<(), Self::Error>;
81}
82
83impl<A, W> RenderAnnotated<A> for IoWrite<W>
84where
85 W: io::Write,
86{
87 fn push_annotation(&mut self, _: &A) -> Result<(), Self::Error> {
88 Ok(())
89 }
90
91 fn pop_annotation(&mut self) -> Result<(), Self::Error> {
92 Ok(())
93 }
94}
95
96impl<A, W> RenderAnnotated<A> for FmtWrite<W>
97where
98 W: fmt::Write,
99{
100 fn push_annotation(&mut self, _: &A) -> Result<(), Self::Error> {
101 Ok(())
102 }
103
104 fn pop_annotation(&mut self) -> Result<(), Self::Error> {
105 Ok(())
106 }
107}
108
109#[cfg(feature = "termcolor")]
110pub struct TermColored<W> {
111 color_stack: Vec<ColorSpec>,
112 upstream: W,
113}
114
115#[cfg(feature = "termcolor")]
116impl<W> TermColored<W> {
117 pub fn new(upstream: W) -> TermColored<W> {
118 TermColored {
119 color_stack: Vec::new(),
120 upstream,
121 }
122 }
123}
124
125#[cfg(feature = "termcolor")]
126impl<W> Render for TermColored<W>
127where
128 W: io::Write,
129{
130 type Error = io::Error;
131
132 fn write_str(&mut self, s: &str) -> io::Result<usize> {
133 self.upstream.write(s.as_bytes())
134 }
135
136 fn write_str_all(&mut self, s: &str) -> io::Result<()> {
137 self.upstream.write_all(s.as_bytes())
138 }
139}
140
141#[cfg(feature = "termcolor")]
142impl<W> RenderAnnotated<ColorSpec> for TermColored<W>
143where
144 W: WriteColor,
145{
146 fn push_annotation(&mut self, color: &ColorSpec) -> Result<(), Self::Error> {
147 self.color_stack.push(color.clone());
148 self.upstream.set_color(color)
149 }
150
151 fn pop_annotation(&mut self) -> Result<(), Self::Error> {
152 self.color_stack.pop();
153 match self.color_stack.last() {
154 Some(previous) => self.upstream.set_color(previous),
155 None => self.upstream.reset(),
156 }
157 }
158}
159
160#[inline]
161pub fn best<'a, W, T, A>(doc: &'a Doc<'a, T, A>, width: usize, out: &mut W) -> Result<(), W::Error>
162where
163 T: Deref<Target = Doc<'a, T, A>>,
164 W: ?Sized + RenderAnnotated<A>,
165{
166 #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
167 enum Mode {
168 Break,
169 Flat,
170 }
171
172 type Cmd<'a, T, A> = (usize, Mode, &'a Doc<'a, T, A>);
173
174 fn write_newline<W>(ind: usize, out: &mut W) -> Result<(), W::Error>
175 where
176 W: ?Sized + Render,
177 {
178 out.write_str_all("\n")?;
179 write_spaces(ind, out)
180 }
181
182 fn write_spaces<W>(spaces: usize, out: &mut W) -> Result<(), W::Error>
183 where
184 W: ?Sized + Render,
185 {
186 macro_rules! make_spaces {
187 () => { "" };
188 ($s: tt $($t: tt)*) => { concat!(" ", make_spaces!($($t)*)) };
189 }
190
191 const SPACES: &str = make_spaces!(,,,,,,,,,,);
192 let mut inserted = 0;
193 while inserted < spaces {
194 let insert = cmp::min(SPACES.len(), spaces - inserted);
195 inserted += out.write_str(&SPACES[..insert])?;
196 }
197
198 Ok(())
199 }
200
201 #[inline]
202 fn fitting<'a, T, A>(
203 next: Cmd<'a, T, A>,
204 bcmds: &[Cmd<'a, T, A>],
205 fcmds: &mut Vec<Cmd<'a, T, A>>,
206 mut rem: isize,
207 ) -> bool
208 where
209 T: Deref<Target = Doc<'a, T, A>>,
210 {
211 let mut bidx = bcmds.len();
212 fcmds.clear(); fcmds.push(next);
214
215 while rem >= 0 {
216 match fcmds.pop() {
217 None => {
218 if bidx == 0 {
219 return true;
221 } else {
222 fcmds.push(bcmds[bidx - 1]);
223 bidx -= 1;
224 }
225 }
226 Some((ind, mode, doc)) => {
227 match *doc {
228 Doc::Nil => {}
229 Doc::Append(ref ldoc, ref rdoc) => {
230 fcmds.push((ind, mode, rdoc));
231 let mut doc = ldoc;
235 while let Doc::Append(ref l, ref r) = **doc {
236 fcmds.push((ind, mode, r));
237 doc = l;
238 }
239 fcmds.push((ind, mode, doc));
240 }
241 Doc::Group(ref doc) => {
242 fcmds.push((ind, mode, doc));
243 }
244 Doc::Nest(off, ref doc) => {
245 fcmds.push((ind + off, mode, doc));
246 }
247 Doc::Space => match mode {
248 Mode::Flat => {
249 rem -= 1;
250 }
251 Mode::Break => {
252 return true;
253 }
254 },
255 Doc::Newline => return true,
256 Doc::Text(ref str) => {
257 rem -= str.len() as isize;
258 }
259 Doc::Annotated(_, ref doc) => fcmds.push((ind, mode, doc)),
260 }
261 }
262 }
263 }
264
265 false
266 }
267
268 let mut pos = 0;
269 let mut bcmds = vec![(0, Mode::Break, doc)];
270 let mut fcmds = vec![];
271 let mut annotation_levels = vec![];
272
273 while let Some((ind, mode, doc)) = bcmds.pop() {
274 match *doc {
275 Doc::Nil => {}
276 Doc::Append(ref ldoc, ref rdoc) => {
277 bcmds.push((ind, mode, rdoc));
278 let mut doc = ldoc;
279 while let Doc::Append(ref l, ref r) = **doc {
280 bcmds.push((ind, mode, r));
281 doc = l;
282 }
283 bcmds.push((ind, mode, doc));
284 }
285 Doc::Group(ref doc) => match mode {
286 Mode::Flat => {
287 bcmds.push((ind, Mode::Flat, doc));
288 }
289 Mode::Break => {
290 let next = (ind, Mode::Flat, &**doc);
291 let rem = width as isize - pos as isize;
292 if fitting(next, &bcmds, &mut fcmds, rem) {
293 bcmds.push(next);
294 } else {
295 bcmds.push((ind, Mode::Break, doc));
296 }
297 }
298 },
299 Doc::Nest(off, ref doc) => {
300 bcmds.push((ind + off, mode, doc));
301 }
302 Doc::Space => match mode {
303 Mode::Flat => {
304 write_spaces(1, out)?;
305 }
306 Mode::Break => {
307 write_newline(ind, out)?;
308 pos = ind;
309 }
310 },
311 Doc::Newline => {
312 write_newline(ind, out)?;
313 pos = ind;
314
315 fcmds.clear();
318 let docs = bcmds.len()
319 - bcmds
320 .iter()
321 .rev()
322 .position(|t| t.1 == Mode::Break)
323 .unwrap_or_else(|| bcmds.len());
324 fcmds.extend_from_slice(&bcmds[docs..]);
325 if let Some(next) = fcmds.pop() {
326 let rem = width as isize - pos as isize;
327 if !fitting(next, &bcmds, &mut fcmds, rem) {
328 for &mut (_, ref mut mode, _) in &mut bcmds[docs..] {
329 *mode = Mode::Break;
330 }
331 }
332 }
333 }
334 Doc::Text(ref s) => {
335 out.write_str_all(s)?;
336 pos += s.len();
337 }
338 Doc::Annotated(ref ann, ref doc) => {
339 out.push_annotation(ann)?;
340 annotation_levels.push(bcmds.len());
341 bcmds.push((ind, mode, doc));
342 }
343 }
344
345 if annotation_levels.last() == Some(&bcmds.len()) {
346 annotation_levels.pop();
347 out.pop_annotation()?;
348 }
349 }
350
351 Ok(())
352}