catlog/tt/util/
pretty.rs

1//! Helper functions for writing pretty-printers.
2
3use pretty::RcDoc;
4use std::{borrow::Cow, fmt, ops};
5
6/// A wrapper around RcDoc that allows us to add some new methods, and also is
7/// shorter to type.
8///
9/// In particular, we implement [ops::Add], which allows concatenating docs with
10/// `+`.
11#[derive(Clone)]
12pub struct D<'a>(pub RcDoc<'a, ()>);
13
14impl<'a> ops::Add for D<'a> {
15    type Output = D<'a>;
16
17    fn add(self, rhs: Self) -> Self::Output {
18        D(self.0.append(rhs.0))
19    }
20}
21
22/// Creates a text doc.
23pub fn t<'a, U: Into<Cow<'a, str>>>(data: U) -> D<'a> {
24    D(RcDoc::text(data))
25}
26
27/// Creates a space.
28pub fn s<'a>() -> D<'a> {
29    D(RcDoc::line())
30}
31
32/// Creates a binary operator applied to two arguments.
33pub fn binop<'a>(op: &'a str, l: D<'a>, r: D<'a>) -> D<'a> {
34    ((l + s() + t(op)).group() + (s() + r).indented()).group()
35}
36
37/// Creates a tuple in [fnotation]: (`[x, y, z, ...]`)
38pub fn tuple<'a, I: IntoIterator<Item = D<'a>>>(i: I) -> D<'a> {
39    D(RcDoc::intersperse(i.into_iter().map(|d| d.0.group()), (t(",") + s()).0))
40        .brackets()
41        .group()
42}
43
44impl<'a> D<'a> {
45    /// Try to lay out this document as a group; either on one line or uniformly split
46    pub fn group(self) -> D<'a> {
47        D(self.0.group())
48    }
49
50    /// Surround this document with parentheses
51    pub fn parens(self) -> D<'a> {
52        t("(") + self.group() + t(")")
53    }
54
55    /// Increase the indentation level
56    pub fn indented(self) -> Self {
57        D(self.0.nest(2))
58    }
59
60    /// Surround this document with brackets
61    pub fn brackets(self) -> D<'a> {
62        t("[") + (s() + self + s()).indented() + t("]")
63    }
64
65    /// Use this to print a document
66    pub fn pretty(&self) -> impl fmt::Display {
67        self.0.pretty(80)
68    }
69}