1
- use pretty:: RcDoc ;
1
+ use pretty:: { RcAllocator , RcDoc } ;
2
2
3
3
pub const INDENT_SPACE : isize = 2 ;
4
4
pub const LINE_WIDTH : usize = 80 ;
5
5
6
- fn is_empty ( doc : & RcDoc ) -> bool {
7
- use pretty:: Doc :: * ;
8
- match & * * doc {
9
- Nil => true ,
10
- FlatAlt ( t1, t2) => is_empty ( t2) || is_empty ( t1) ,
11
- Union ( t1, t2) => is_empty ( t1) && is_empty ( t2) ,
12
- Group ( t) | Nest ( _, t) | Annotated ( ( ) , t) => is_empty ( t) ,
13
- _ => false ,
14
- }
15
- }
16
-
17
6
pub fn enclose < ' a > ( left : & ' a str , doc : RcDoc < ' a > , right : & ' a str ) -> RcDoc < ' a > {
18
- if is_empty ( & doc) {
19
- RcDoc :: text ( left) . append ( right)
20
- } else {
21
- RcDoc :: text ( left)
22
- . append ( RcDoc :: line_ ( ) )
23
- . append ( doc)
24
- . nest ( INDENT_SPACE )
25
- . append ( RcDoc :: line_ ( ) )
26
- . append ( right)
27
- . group ( )
28
- }
7
+ RcDoc :: text ( left)
8
+ . append ( RcDoc :: line_ ( ) )
9
+ . append ( doc)
10
+ . nest ( INDENT_SPACE )
11
+ . append ( RcDoc :: line_ ( ) )
12
+ . append ( right)
13
+ . group ( )
29
14
}
30
15
31
16
pub fn enclose_space < ' a > ( left : & ' a str , doc : RcDoc < ' a > , right : & ' a str ) -> RcDoc < ' a > {
32
- if is_empty ( & doc) {
33
- RcDoc :: text ( left) . append ( right)
34
- } else {
35
- RcDoc :: text ( left)
36
- . append ( RcDoc :: line ( ) )
37
- . append ( doc)
38
- . nest ( INDENT_SPACE )
39
- . append ( RcDoc :: line ( ) )
40
- . append ( right)
41
- . group ( )
42
- }
17
+ RcDoc :: text ( left)
18
+ . append ( RcDoc :: line ( ) )
19
+ . append ( doc)
20
+ . nest ( INDENT_SPACE )
21
+ . append ( RcDoc :: line ( ) )
22
+ . append ( right)
23
+ . group ( )
43
24
}
44
25
45
26
/// Intersperse the separator between each item in `docs`.
50
31
RcDoc :: intersperse ( docs, RcDoc :: text ( sep) . append ( RcDoc :: line ( ) ) )
51
32
}
52
33
53
- /// Append the separator to each item in `docs`. If it is displayed in a single line, omit the last separator.
54
- pub fn concat < ' a , D > ( docs : D , sep : & ' a str ) -> RcDoc < ' a >
55
- where
56
- D : Iterator < Item = RcDoc < ' a > > ,
57
- {
58
- let mut docs = docs. peekable ( ) ;
59
- if docs. peek ( ) . is_none ( ) {
60
- return RcDoc :: nil ( ) ;
61
- }
62
- let singleline = RcDoc :: intersperse ( docs, RcDoc :: text ( sep) . append ( RcDoc :: line ( ) ) ) ;
63
- let multiline = singleline. clone ( ) . append ( sep) ;
64
- multiline. flat_alt ( singleline)
65
- }
66
-
67
34
pub fn lines < ' a , D > ( docs : D ) -> RcDoc < ' a >
68
35
where
69
36
D : Iterator < Item = RcDoc < ' a > > ,
@@ -90,15 +57,120 @@ pub fn quote_ident(id: &str) -> RcDoc<'_> {
90
57
. append ( RcDoc :: space ( ) )
91
58
}
92
59
60
+ /// Separate each item in `docs` with the separator `sep`, and enclose the result in `open` and `close`.
61
+ /// When placed on multiple lines, the last element gets a trailing separator.
62
+ pub fn sep_enclose < ' a , D , S , O , C > ( docs : D , sep : S , open : O , close : C ) -> RcDoc < ' a >
63
+ where
64
+ D : IntoIterator < Item = RcDoc < ' a > > ,
65
+ S : pretty:: Pretty < ' a , RcAllocator > ,
66
+ O : pretty:: Pretty < ' a , RcAllocator > ,
67
+ C : pretty:: Pretty < ' a , RcAllocator > ,
68
+ {
69
+ let sep = sep. pretty ( & RcAllocator ) ;
70
+ let elems = RcDoc :: intersperse ( docs, sep. clone ( ) . append ( RcDoc :: line ( ) ) ) ;
71
+ open. pretty ( & RcAllocator )
72
+ . into_doc ( )
73
+ . append ( RcDoc :: line_ ( ) )
74
+ . append ( elems)
75
+ . append ( sep. flat_alt ( RcDoc :: nil ( ) ) )
76
+ . nest ( INDENT_SPACE )
77
+ . append ( RcDoc :: line_ ( ) )
78
+ . append ( close. pretty ( & RcAllocator ) )
79
+ . group ( )
80
+ }
81
+
82
+ /// Like `sep_enclose`, but inserts a space between the opening delimiter and the first element,
83
+ /// and between the last element and the closing delimiter when placed on a single line.
84
+ pub fn sep_enclose_space < ' a , D , S , O , C > ( docs : D , sep : S , open : O , close : C ) -> RcDoc < ' a >
85
+ where
86
+ D : IntoIterator < Item = RcDoc < ' a > > ,
87
+ S : pretty:: Pretty < ' a , RcAllocator > ,
88
+ O : pretty:: Pretty < ' a , RcAllocator > ,
89
+ C : pretty:: Pretty < ' a , RcAllocator > ,
90
+ {
91
+ let mut docs = docs. into_iter ( ) . peekable ( ) ;
92
+ if docs. peek ( ) . is_none ( ) {
93
+ return open. pretty ( & RcAllocator ) . append ( close) . into_doc ( ) ;
94
+ }
95
+ let open = open
96
+ . pretty ( & RcAllocator )
97
+ . append ( RcDoc :: nil ( ) . flat_alt ( RcDoc :: space ( ) ) ) ;
98
+ let close = RcDoc :: nil ( ) . flat_alt ( RcDoc :: space ( ) ) . append ( close) ;
99
+ sep_enclose ( docs, sep, open, close)
100
+ }
101
+
93
102
#[ cfg( test) ]
94
- mod test {
103
+ mod tests {
95
104
use super :: * ;
96
105
97
106
#[ test]
98
- fn concat_empty ( ) {
99
- let t = concat ( vec ! [ ] . into_iter ( ) , "," )
107
+ fn enclose_empty ( ) {
108
+ let t = sep_enclose ( vec ! [ ] , "," , "(" , ") ")
100
109
. pretty ( LINE_WIDTH )
101
110
. to_string ( ) ;
102
- assert_eq ! ( t, "" ) ;
111
+ assert_eq ! ( t, "()" ) ;
112
+ }
113
+
114
+ #[ test]
115
+ fn enclose_single_line ( ) {
116
+ let printed = sep_enclose ( vec ! [ str ( "a" ) , str ( "b" ) ] , "," , "(" , ")" )
117
+ . pretty ( LINE_WIDTH )
118
+ . to_string ( ) ;
119
+ assert_eq ! ( printed, "(a, b)" ) ;
120
+ }
121
+
122
+ #[ test]
123
+ fn enclose_multiline ( ) {
124
+ let docs: Vec < RcDoc > = vec ! [
125
+ str ( "Very long line to make sure we get a multiline document" ) ,
126
+ str ( "Very long line to make sure we get a multiline document" ) ,
127
+ ] ;
128
+ let printed = sep_enclose ( docs, "," , "(" , ")" ) . pretty ( 20 ) . to_string ( ) ;
129
+ assert_eq ! (
130
+ printed,
131
+ "
132
+ (
133
+ Very long line to make sure we get a multiline document,
134
+ Very long line to make sure we get a multiline document,
135
+ )
136
+ "
137
+ . trim( )
138
+ ) ;
139
+ }
140
+
141
+ #[ test]
142
+ fn enclose_empty_space ( ) {
143
+ let t = sep_enclose_space ( vec ! [ ] , "," , "(" , ")" )
144
+ . pretty ( LINE_WIDTH )
145
+ . to_string ( ) ;
146
+ assert_eq ! ( t, "()" ) ;
147
+ }
148
+
149
+ #[ test]
150
+ fn enclose_single_line_space ( ) {
151
+ let printed = sep_enclose_space ( vec ! [ str ( "a" ) , str ( "b" ) ] , "," , "(" , ")" )
152
+ . pretty ( LINE_WIDTH )
153
+ . to_string ( ) ;
154
+ assert_eq ! ( printed, "( a, b )" ) ;
155
+ }
156
+
157
+ #[ test]
158
+ fn enclose_multiline_space ( ) {
159
+ let docs: Vec < RcDoc > = vec ! [
160
+ str ( "Very long line to make sure we get a multiline document" ) ,
161
+ str ( "Very long line to make sure we get a multiline document" ) ,
162
+ ] ;
163
+ let printed = sep_enclose_space ( docs, "," , "(" , ")" )
164
+ . pretty ( 20 )
165
+ . to_string ( ) ;
166
+ assert_eq ! (
167
+ printed,
168
+ "
169
+ (
170
+ Very long line to make sure we get a multiline document,
171
+ Very long line to make sure we get a multiline document,
172
+ )"
173
+ . trim( )
174
+ ) ;
103
175
}
104
176
}
0 commit comments