1use std::collections::HashMap;
2
3use tan::{
4 expr::Expr,
5 util::{fmt::format_float, put_back_iterator::PutBackIterator},
6};
7
8use crate::{types::Dialect, util::escape_string};
9
10#[derive(Clone, Debug)]
24pub enum Layout {
25 Indent(Vec<Layout>, Option<usize>), Stack(Vec<Layout>),
29 Row(Vec<Layout>, String),
31 Apply(Box<Layout>),
33 Item(String),
34 Ann(HashMap<String, Expr>, Box<Layout>),
35 Separator,
36}
37
38impl Layout {
39 pub fn indent(list: Vec<Layout>) -> Self {
40 Self::Indent(list, None)
41 }
42
43 pub fn align(list: Vec<Layout>, indent_size: usize) -> Self {
44 Self::Indent(list, Some(indent_size))
45 }
46
47 pub fn row(list: impl Into<Vec<Layout>>) -> Self {
48 Self::Row(list.into(), " ".to_string())
49 }
50
51 pub fn join(list: impl Into<Vec<Layout>>) -> Self {
52 Self::Row(list.into(), "".to_string())
53 }
54
55 pub fn apply(l: Layout) -> Self {
56 Self::Apply(Box::new(l))
57 }
58
59 pub fn item(s: impl Into<String>) -> Self {
60 Self::Item(s.into())
61 }
62
63 pub fn space() -> Self {
64 Self::Item(" ".into())
65 }
66}
67
68#[derive(Clone, Copy, Eq, PartialEq, Debug)]
71enum ArrangerMode {
72 Default,
73 Let,
76 Inline,
78}
79
80pub struct Arranger<'a> {
87 pub dialect: Dialect,
90 exprs: PutBackIterator<'a, Expr>,
91 mode: ArrangerMode,
92}
93
94impl<'a> Arranger<'a> {
95 pub fn new(exprs: &'a [Expr], dialect: Dialect) -> Self {
96 Self {
97 dialect,
98 exprs: PutBackIterator::new(exprs),
99 mode: ArrangerMode::Default,
100 }
101 }
102
103 fn arrange_next(&mut self) -> Option<Layout> {
104 let expr0 = self.exprs.next()?;
105
106 let layout = self.layout_from_expr(expr0);
107
108 if let Some(expr1) = self.exprs.next() {
112 match expr1.unpack() {
113 Expr::Comment(..) => {
114 if expr1.range().unwrap().start.line == expr0.range().unwrap().start.line {
115 let comment = self.layout_from_expr(expr1);
116 return Some(Layout::row(vec![layout, comment]));
117 } else {
118 self.exprs.put_back(expr1);
119 }
120 }
121 _ => {
122 self.exprs.put_back(expr1);
123 }
124 }
125 };
126
127 Some(layout)
128 }
129
130 fn arrange_all(&mut self) -> (Vec<Layout>, bool) {
131 let mut layouts = Vec::new();
132
133 let mut force_vertical = false;
134
135 while let Some(layout) = self.arrange_next() {
136 if let Layout::Row(v, ..) = &layout {
138 if let Some(Layout::Item(t)) = &v.last() {
139 force_vertical = force_vertical || t.starts_with(';'); }
141 };
142
143 if let Layout::Item(item) = &layout {
150 force_vertical = force_vertical || item.starts_with(';') }
155
156 layouts.push(layout);
157 }
158
159 (layouts, force_vertical)
160 }
161
162 fn arrange_all_array(&mut self) -> (Vec<Layout>, bool) {
165 let mut layouts = Vec::new();
166
167 let mut force_vertical = false;
168
169 let mut items_cumulative_length = 0;
170
171 while let Some(layout) = self.arrange_next() {
172 if let Layout::Row(v, ..) = &layout {
174 if let Some(Layout::Item(t)) = &v.last() {
175 force_vertical = force_vertical || t.starts_with(';'); }
177 };
178
179 let item_length_vertical_arrange_threshold = 8;
182
183 if let Layout::Item(item) = &layout {
186 items_cumulative_length += item.len();
187
188 force_vertical = force_vertical
189 || item.starts_with(';') || (self.mode != ArrangerMode::Inline && item.len() > item_length_vertical_arrange_threshold);
191 }
193
194 layouts.push(layout);
195 }
196
197 if self.mode != ArrangerMode::Inline {
198 force_vertical = force_vertical || items_cumulative_length > 32;
201 }
202
203 (layouts, force_vertical)
204 }
205
206 fn maybe_annotated_layout_from_expr(&mut self, expr: &Expr) -> Option<Layout> {
209 let mut expr = expr;
210
211 let mut annotated = Vec::new();
212
213 while let Expr::Annotation(..) = expr.unpack() {
214 annotated.push(self.layout_from_expr(expr));
215 expr = self.exprs.next()?;
216 }
217
218 if annotated.is_empty() {
221 Some(self.layout_from_expr(expr))
222 } else {
223 annotated.push(self.layout_from_expr(expr));
224 Some(Layout::row(annotated))
225 }
226 }
227
228 fn arrange_next_pair(&mut self) -> Option<Layout> {
230 let expr = self.exprs.next()?;
233
234 if let Expr::Comment(..) = expr.unpack() {
237 return Some(self.layout_from_expr(expr));
238 }
239
240 let mut tuple = Vec::new();
241
242 tuple.push(self.maybe_annotated_layout_from_expr(expr)?);
243
244 let expr = self.exprs.next()?;
245 tuple.push(self.maybe_annotated_layout_from_expr(expr)?);
246
247 if let Some(expr) = self.exprs.next() {
249 match expr.unpack() {
250 Expr::Comment(..) => {
251 if expr.range().unwrap().start.line == expr.range().unwrap().start.line {
252 tuple.push(self.layout_from_expr(expr));
253 } else {
254 self.exprs.put_back(expr);
255 }
256 }
257 _ => {
258 self.exprs.put_back(expr);
259 }
260 }
261 };
262
263 Some(Layout::row(tuple))
264 }
265
266 fn arrange_all_pairs(&mut self) -> (Vec<Layout>, bool) {
267 let mut layouts = Vec::new();
268
269 let mut should_force_vertical = false;
270
271 while let Some(layout) = self.arrange_next_pair() {
272 if let Layout::Row(items, ..) = &layout {
273 if items.len() > 2 {
274 should_force_vertical = true;
276 }
277 };
278
279 layouts.push(layout);
280 }
281
282 (layouts, should_force_vertical)
283 }
284
285 fn arrange_list(&mut self) -> Layout {
286 let expr = self.exprs.next().unwrap();
288
289 let mut layouts = Vec::new();
290
291 let head = expr.unpack();
292
293 match head {
299 Expr::Symbol(name) if name == "quot" => {
300 let (exprs, _) = self.arrange_all();
303 layouts.push(Layout::item("'"));
304 layouts.push(Layout::row(exprs));
305 Layout::join(layouts)
306 }
307 Expr::Symbol(name) if name == "unquot" => {
308 let (exprs, _) = self.arrange_all();
310 layouts.push(Layout::item("$"));
311 layouts.push(Layout::row(exprs));
312 Layout::join(layouts)
313 }
314 Expr::Symbol(name) if name == "do" => {
315 let (exprs, _) = self.arrange_all();
317 layouts.push(Layout::item("(do"));
318 layouts.push(Layout::indent(exprs));
319 layouts.push(Layout::apply(Layout::item(")")));
320 Layout::Stack(layouts)
321 }
322 Expr::Symbol(name) | Expr::Type(name)
325 if name == "if" || name == "for" || name == "Func" =>
326 {
327 layouts.push(Layout::row(vec![
329 Layout::item(format!("({name}")),
330 if name == "Func" || name == "for" {
334 let old_mode = self.mode;
335 self.mode = ArrangerMode::Inline;
336 let layout = self.arrange_next().unwrap();
337 self.mode = old_mode;
338 layout
339 } else {
340 self.arrange_next().unwrap()
341 },
342 ]));
343 let (block, should_force_vertical) = self.arrange_all();
344
345 let should_force_vertical = should_force_vertical || block.len() > 1;
348
349 let should_force_vertical = should_force_vertical || name == "for";
354
355 let should_force_vertical = should_force_vertical || self.mode == ArrangerMode::Let;
356
357 if should_force_vertical {
358 layouts.push(Layout::indent(block));
359 layouts.push(Layout::apply(Layout::item(")")));
360 Layout::Stack(layouts)
361 } else {
362 layouts.push(Layout::item(" "));
363 layouts.push(block[0].clone());
364 layouts.push(Layout::item(")"));
365 Layout::join(layouts)
366 }
367 }
368 Expr::Symbol(name) if name == "Range" => {
369 let start = self.exprs.next().unwrap();
372 let end = self.exprs.next().unwrap();
373 let mut range = format!("{start}..{end}");
374 if let Some(step) = self.exprs.next() {
375 range = format!("{range}|{step}");
376 }
377 Layout::Item(range)
378 }
379 Expr::Symbol(name) if name == "Array" => {
380 layouts.push(Layout::item("["));
383 let (items, should_force_vertical) = self.arrange_all_array();
385
386 let should_force_vertical = should_force_vertical || self.dialect == Dialect::Data;
389
390 if !items.is_empty() {
391 if should_force_vertical {
392 layouts.push(Layout::indent(items));
393 layouts.push(Layout::apply(Layout::item("]")));
394 Layout::Stack(layouts)
395 } else {
396 match &items[0] {
397 Layout::Stack(..) | Layout::Indent(..) => {
400 layouts.push(Layout::indent(items));
401 layouts.push(Layout::apply(Layout::item("]")));
402 Layout::Stack(layouts)
403 }
404 _ => {
405 layouts.push(Layout::row(items));
406 layouts.push(Layout::item("]"));
407 Layout::join(layouts)
408 }
409 }
410 }
411 } else {
412 layouts.push(Layout::item("]"));
413 Layout::join(layouts)
414 }
415 }
416 Expr::Symbol(name) if name == "Map" => {
417 let (bindings, should_force_vertical) = self.arrange_all_pairs();
419
420 let should_force_vertical = should_force_vertical || bindings.len() > 2;
422
423 let should_force_vertical = should_force_vertical || self.dialect == Dialect::Data;
425
426 if should_force_vertical {
427 layouts.push(Layout::item("{"));
428 layouts.push(Layout::indent(bindings));
429 layouts.push(Layout::apply(Layout::item("}")));
430 Layout::Stack(layouts)
431 } else {
432 layouts.push(Layout::item("{"));
433 layouts.push(Layout::row(bindings));
434 layouts.push(Layout::item('}'));
435 Layout::join(layouts)
436 }
437 }
438 Expr::Symbol(name) if name == "let" => {
439 let old_mode = self.mode;
441 self.mode = ArrangerMode::Let;
442 let (mut bindings, should_force_vertical) = self.arrange_all_pairs();
443
444 self.mode = old_mode;
445
446 if should_force_vertical {
447 layouts.push(Layout::item("(let"));
449 layouts.push(Layout::indent(bindings));
450 layouts.push(Layout::apply(Layout::item(')')));
451 Layout::Stack(layouts)
452 } else if bindings.len() > 1 {
453 layouts.push(Layout::row(vec![Layout::item("(let"), bindings.remove(0)]));
455 if !bindings.is_empty() {
456 layouts.push(Layout::align(bindings, 5 ));
457 }
458 layouts.push(Layout::apply(Layout::item(')')));
459 Layout::Stack(layouts)
460 } else {
461 layouts.push(Layout::item("(let "));
463 layouts.push(Layout::row(bindings));
464 layouts.push(Layout::item(')'));
465 Layout::join(layouts)
466 }
467 }
468 Expr::Symbol(name) if name == "cond" => {
471 let (clauses, should_force_vertical) = self.arrange_all_pairs();
472
473 if should_force_vertical {
474 layouts.push(Layout::item("(cond"));
477 layouts.push(Layout::indent(clauses));
478 layouts.push(Layout::apply(Layout::item(')')));
479 Layout::Stack(layouts)
480 } else if clauses.len() > 1 {
481 layouts.push(Layout::item("(cond"));
483 if !clauses.is_empty() {
485 layouts.push(Layout::align(clauses, 4 ));
486 }
487 layouts.push(Layout::apply(Layout::item(')')));
488 Layout::Stack(layouts)
489 } else {
490 layouts.push(Layout::item("(cond "));
493 layouts.push(Layout::row(clauses));
494 layouts.push(Layout::item(')'));
495 Layout::join(layouts)
496 }
497 }
498 _ => {
499 layouts.push(Layout::item(format!("({head}")));
501 let (args, should_force_vertical) = self.arrange_all();
502 if !args.is_empty() {
503 if should_force_vertical {
504 layouts.push(Layout::indent(args));
505 layouts.push(Layout::apply(Layout::item(")")));
506 Layout::Stack(layouts)
507 } else {
508 layouts.push(Layout::item(" "));
509 layouts.push(Layout::row(args));
510 layouts.push(Layout::item(")"));
511 Layout::join(layouts)
512 }
513 } else {
514 layouts.push(Layout::item(")"));
515 Layout::join(layouts)
516 }
517 }
518 }
519 }
520
521 fn layout_from_expr(&self, expr: &Expr) -> Layout {
522 let (expr, _ann) = expr.extract();
523
524 let layout = match expr {
525 Expr::Comment(s, _) => Layout::Item(s.clone()),
526 Expr::TextSeparator => Layout::Separator, Expr::String(s) => Layout::Item(format!("\"{}\"", escape_string(s))),
528 Expr::Symbol(s) => Layout::Item(s.clone()),
529 Expr::Int(n) => Layout::Item(n.to_string()),
530 Expr::None => Layout::Item("()".to_string()),
532 Expr::Bool(b) => Layout::Item(b.to_string()),
533 Expr::Float(n) => Layout::Item(format_float(*n)),
534 Expr::KeySymbol(s) => Layout::Item(format!(":{s}")),
536 Expr::Char(c) => Layout::Item(format!(r#"(Char "{c}")"#)),
537 Expr::List(exprs) => {
539 if exprs.is_empty() {
540 return Layout::Item("()".to_owned());
541 }
542
543 let mut list_arranger = Arranger::new(exprs, self.dialect);
546 list_arranger.mode = self.mode;
547 list_arranger.arrange_list()
548 }
549 _ => Layout::Item(expr.to_string()),
550 };
551
552 layout
563 }
564
565 pub fn arrange(&mut self) -> Layout {
566 let (rows, _) = self.arrange_all();
567 Layout::Stack(rows)
568 }
569}