1use crate::ring::RingBuffer;
7use crate::{MARGIN, MIN_SPACE};
8use std::borrow::Cow;
9use std::cmp;
10use std::collections::VecDeque;
11use std::convert::TryFrom;
12use std::iter;
13
14#[derive(Clone, Copy, PartialEq)]
15pub(crate) enum Breaks {
16 Consistent,
17 Inconsistent,
18}
19
20#[derive(Clone, Copy, Default)]
21pub(crate) struct BreakToken {
22 pub(crate) offset: isize,
23 pub(crate) blank_space: usize,
24 pub(crate) pre_break: Option<char>,
25 pub(crate) post_break: Option<char>,
26 pub(crate) no_break: Option<char>,
27 pub(crate) if_nonempty: bool,
28 pub(crate) never_break: bool,
29}
30
31#[derive(Clone, Copy)]
32pub(crate) struct BeginToken {
33 pub(crate) offset: isize,
34 pub(crate) breaks: Breaks,
35}
36
37#[derive(Clone)]
38pub(crate) enum Token {
39 String(Cow<'static, str>),
40 Break(BreakToken),
41 Begin(BeginToken),
42 End,
43}
44
45#[derive(Copy, Clone)]
46enum PrintFrame {
47 Fits(Breaks),
48 Broken(usize, Breaks),
49}
50
51pub(crate) const SIZE_INFINITY: isize = 0xffff;
52
53pub struct Formatter {
62 out: String,
63 space: isize,
65 buf: RingBuffer<BufEntry>,
67 left_total: isize,
69 right_total: isize,
71 scan_stack: VecDeque<usize>,
77 print_stack: Vec<PrintFrame>,
79 indent: usize,
81 pending_indentation: usize,
83}
84
85#[derive(Clone)]
86struct BufEntry {
87 token: Token,
88 size: isize,
89}
90
91impl Formatter {
92 pub(crate) fn new() -> Self {
93 Formatter {
94 out: String::new(),
95 space: MARGIN,
96 buf: RingBuffer::new(),
97 left_total: 0,
98 right_total: 0,
99 scan_stack: VecDeque::new(),
100 print_stack: Vec::new(),
101 indent: 0,
102 pending_indentation: 0,
103 }
104 }
105
106 pub(crate) fn eof(mut self) -> String {
107 if !self.scan_stack.is_empty() {
108 self.check_stack(0);
109 self.advance_left();
110 }
111 self.out
112 }
113
114 pub(crate) fn scan_begin(&mut self, token: BeginToken) {
115 if self.scan_stack.is_empty() {
116 self.left_total = 1;
117 self.right_total = 1;
118 self.buf.clear();
119 }
120 let right = self.buf.push(BufEntry {
121 token: Token::Begin(token),
122 size: -self.right_total,
123 });
124 self.scan_stack.push_back(right);
125 }
126
127 pub(crate) fn scan_end(&mut self) {
128 if self.scan_stack.is_empty() {
129 self.print_end();
130 } else {
131 if !self.buf.is_empty() {
132 if let Token::Break(break_token) = self.buf.last().token {
133 if self.buf.len() >= 2 {
134 if let Token::Begin(_) = self.buf.second_last().token {
135 self.buf.pop_last();
136 self.buf.pop_last();
137 self.scan_stack.pop_back();
138 self.scan_stack.pop_back();
139 self.right_total -= break_token.blank_space as isize;
140 return;
141 }
142 }
143 if break_token.if_nonempty {
144 self.buf.pop_last();
145 self.scan_stack.pop_back();
146 self.right_total -= break_token.blank_space as isize;
147 }
148 }
149 }
150 let right = self.buf.push(BufEntry {
151 token: Token::End,
152 size: -1,
153 });
154 self.scan_stack.push_back(right);
155 }
156 }
157
158 pub(crate) fn scan_break(&mut self, token: BreakToken) {
159 if self.scan_stack.is_empty() {
160 self.left_total = 1;
161 self.right_total = 1;
162 self.buf.clear();
163 } else {
164 self.check_stack(0);
165 }
166 let right = self.buf.push(BufEntry {
167 token: Token::Break(token),
168 size: -self.right_total,
169 });
170 self.scan_stack.push_back(right);
171 self.right_total += token.blank_space as isize;
172 }
173
174 pub(crate) fn scan_string(&mut self, string: Cow<'static, str>) {
175 if self.scan_stack.is_empty() {
176 self.print_string(string);
177 } else {
178 let len = string.len() as isize;
179 self.buf.push(BufEntry {
180 token: Token::String(string),
181 size: len,
182 });
183 self.right_total += len;
184 self.check_stream();
185 }
186 }
187
188 pub(crate) fn offset(&mut self, offset: isize) {
189 match &mut self.buf.last_mut().token {
190 Token::Break(token) => token.offset += offset,
191 Token::Begin(_) => {}
192 Token::String(_) | Token::End => unreachable!(),
193 }
194 }
195
196 pub(crate) fn end_with_max_width(&mut self, max: isize) {
197 let mut depth = 1;
198 for &index in self.scan_stack.iter().rev() {
199 let entry = &self.buf[index];
200 match entry.token {
201 Token::Begin(_) => {
202 depth -= 1;
203 if depth == 0 {
204 if entry.size < 0 {
205 let actual_width = entry.size + self.right_total;
206 if actual_width > max {
207 self.buf.push(BufEntry {
208 token: Token::String(Cow::Borrowed("")),
209 size: SIZE_INFINITY,
210 });
211 self.right_total += SIZE_INFINITY;
212 }
213 }
214 break;
215 }
216 }
217 Token::End => depth += 1,
218 Token::Break(_) => {}
219 Token::String(_) => unreachable!(),
220 }
221 }
222 self.scan_end();
223 }
224
225 fn check_stream(&mut self) {
226 while self.right_total - self.left_total > self.space {
227 if *self.scan_stack.front().unwrap() == self.buf.index_of_first() {
228 self.scan_stack.pop_front().unwrap();
229 self.buf.first_mut().size = SIZE_INFINITY;
230 }
231
232 self.advance_left();
233
234 if self.buf.is_empty() {
235 break;
236 }
237 }
238 }
239
240 fn advance_left(&mut self) {
241 while self.buf.first().size >= 0 {
242 let left = self.buf.pop_first();
243
244 match left.token {
245 Token::String(string) => {
246 self.left_total += left.size;
247 self.print_string(string);
248 }
249 Token::Break(token) => {
250 self.left_total += token.blank_space as isize;
251 self.print_break(token, left.size);
252 }
253 Token::Begin(token) => self.print_begin(token, left.size),
254 Token::End => self.print_end(),
255 }
256
257 if self.buf.is_empty() {
258 break;
259 }
260 }
261 }
262
263 fn check_stack(&mut self, mut depth: usize) {
264 while let Some(&index) = self.scan_stack.back() {
265 let entry = &mut self.buf[index];
266 match entry.token {
267 Token::Begin(_) => {
268 if depth == 0 {
269 break;
270 }
271 self.scan_stack.pop_back().unwrap();
272 entry.size += self.right_total;
273 depth -= 1;
274 }
275 Token::End => {
276 self.scan_stack.pop_back().unwrap();
277 entry.size = 1;
278 depth += 1;
279 }
280 Token::Break(_) => {
281 self.scan_stack.pop_back().unwrap();
282 entry.size += self.right_total;
283 if depth == 0 {
284 break;
285 }
286 }
287 Token::String(_) => unreachable!(),
288 }
289 }
290 }
291
292 fn get_top(&self) -> PrintFrame {
293 const OUTER: PrintFrame = PrintFrame::Broken(0, Breaks::Inconsistent);
294 self.print_stack.last().map_or(OUTER, PrintFrame::clone)
295 }
296
297 fn print_begin(&mut self, token: BeginToken, size: isize) {
298 if cfg!(prettyplease_debug) {
299 self.out.push(match token.breaks {
300 Breaks::Consistent => '«',
301 Breaks::Inconsistent => '‹',
302 });
303 if cfg!(prettyplease_debug_indent) {
304 self.out
305 .extend(token.offset.to_string().chars().map(|ch| match ch {
306 '0'..='9' => ['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉']
307 [(ch as u8 - b'0') as usize],
308 '-' => '₋',
309 _ => unreachable!(),
310 }));
311 }
312 }
313 if size > self.space {
314 self.print_stack
315 .push(PrintFrame::Broken(self.indent, token.breaks));
316 self.indent = usize::try_from(self.indent as isize + token.offset).unwrap();
317 } else {
318 self.print_stack.push(PrintFrame::Fits(token.breaks));
319 }
320 }
321
322 fn print_end(&mut self) {
323 let breaks = match self.print_stack.pop().unwrap() {
324 PrintFrame::Broken(indent, breaks) => {
325 self.indent = indent;
326 breaks
327 }
328 PrintFrame::Fits(breaks) => breaks,
329 };
330 if cfg!(prettyplease_debug) {
331 self.out.push(match breaks {
332 Breaks::Consistent => '»',
333 Breaks::Inconsistent => '›',
334 });
335 }
336 }
337
338 fn print_break(&mut self, token: BreakToken, size: isize) {
339 let fits = token.never_break
340 || match self.get_top() {
341 PrintFrame::Fits(..) => true,
342 PrintFrame::Broken(.., Breaks::Consistent) => false,
343 PrintFrame::Broken(.., Breaks::Inconsistent) => size <= self.space,
344 };
345 if fits {
346 self.pending_indentation += token.blank_space;
347 self.space -= token.blank_space as isize;
348 if let Some(no_break) = token.no_break {
349 self.out.push(no_break);
350 self.space -= no_break.len_utf8() as isize;
351 }
352 if cfg!(prettyplease_debug) {
353 self.out.push('·');
354 }
355 } else {
356 if let Some(pre_break) = token.pre_break {
357 self.out.push(pre_break);
358 }
359 if cfg!(prettyplease_debug) {
360 self.out.push('·');
361 }
362 self.out.push('\n');
363 let indent = self.indent as isize + token.offset;
364 self.pending_indentation = usize::try_from(indent).unwrap();
365 self.space = cmp::max(MARGIN - indent, MIN_SPACE);
366 if let Some(post_break) = token.post_break {
367 self.print_indent();
368 self.out.push(post_break);
369 self.space -= post_break.len_utf8() as isize;
370 }
371 }
372 }
373
374 fn print_string(&mut self, string: Cow<'static, str>) {
375 self.print_indent();
376 self.out.push_str(&string);
377 self.space -= string.len() as isize;
378 }
379
380 fn print_indent(&mut self) {
381 self.out.reserve(self.pending_indentation);
382 self.out
383 .extend(iter::repeat(' ').take(self.pending_indentation));
384 self.pending_indentation = 0;
385 }
386}
387
388impl Default for Formatter {
389 fn default() -> Self {
390 Self::new()
391 }
392}