use crate::predoc::{
Doc, DocE, Pretty, hardline, hardspace, line, line_prime, push_group, push_nested,
push_surrounded,
};
use crate::types::{Ann, Binder, Expression, Item, Items, Leaf, Term, Token, Trivium};
use super::absorb::{is_absorbable_expr, is_absorbable_term, push_absorb_expr};
use super::app::push_pretty_app;
use super::util::{
Width, has_trivia, is_lone_ann, items_has_only_comments, push_empty_brackets,
split_paren_trivia,
};
pub(super) fn push_pretty_term_list(doc: &mut Doc, open: &Leaf, items: &Items<Term>, close: &Leaf) {
if items.0.is_empty() && open.trail_comment.is_none() && close.pre_trivia.is_empty() {
push_empty_brackets(doc, open, close);
} else {
push_render_list(doc, &hardline(), open, items, close);
}
}
pub(super) fn push_pretty_term(doc: &mut Doc, term: &Term) {
match term {
Term::List(open, items, close) => push_pretty_term_list(doc, open, items, close),
_ => term.pretty(doc),
}
}
pub(super) fn push_pretty_term_wide(doc: &mut Doc, term: &Term) {
match term {
Term::Set(krec, open, items, close) => {
push_pretty_set(doc, Width::Wide, krec.as_ref(), open, items, close);
}
Term::List(open, items, close) => push_pretty_term_list(doc, open, items, close),
_ => term.pretty(doc),
}
}
pub(super) fn push_render_list(
doc: &mut Doc,
item_sep: &DocE,
open: &Ann<Token>,
items: &Items<Term>,
close: &Ann<Token>,
) {
open.without_trail().pretty(doc);
let sur = if open.span.start_line != close.span.start_line
|| items_has_only_comments(items)
|| (has_trivia(open) && items.0.is_empty())
{
hardline()
} else if items.0.is_empty() {
hardspace()
} else {
line()
};
push_surrounded(doc, &vec![sur], |d| {
push_nested(d, |inner| {
open.trail_comment.pretty(inner);
push_pretty_items_sep(inner, items, item_sep);
});
});
close.pretty(doc);
}
pub(super) fn push_pretty_set(
doc: &mut Doc,
wide: Width,
krec: Option<&Ann<Token>>,
open: &Ann<Token>,
items: &Items<Binder>,
close: &Ann<Token>,
) {
if items.0.is_empty() && is_lone_ann(open) && close.pre_trivia.is_empty() {
if let Some(rec) = krec {
rec.pretty(doc);
doc.push(hardspace());
}
push_empty_brackets(doc, open, close);
return;
}
if let Some(rec) = krec {
rec.pretty(doc);
doc.push(hardspace());
}
open.without_trail().pretty(doc);
let starts_with_emptyline = match items.0.first() {
Some(Item::Comments(trivia)) => trivia.iter().any(|t| matches!(t, Trivium::EmptyLine())),
_ => false,
};
let sep = if (!items.0.is_empty() && (wide == Width::Wide || starts_with_emptyline))
|| open.span.start_line != close.span.start_line
{
vec![hardline()]
} else {
vec![line()]
};
push_surrounded(doc, &sep, |d| {
push_nested(d, |inner| {
open.trail_comment.pretty(inner);
push_pretty_items(inner, items);
});
});
close.pretty(doc);
}
pub(super) fn push_pretty_items<T: Pretty>(doc: &mut Doc, items: &Items<T>) {
push_pretty_items_sep(doc, items, &hardline());
}
fn push_pretty_items_sep<T: Pretty>(doc: &mut Doc, items: &Items<T>, sep: &DocE) {
let items = &items.0;
match items.as_slice() {
[] => {}
[item] => item.pretty(doc),
items => {
let mut i = 0;
while i < items.len() {
if i > 0 {
doc.push(sep.clone());
}
if i + 1 < items.len()
&& let Item::Comments(trivia) = &items[i]
&& trivia.len() == 1
&& let Trivium::LanguageAnnotation(lang) = &trivia[0]
&& let Item::Item(string_item) = &items[i + 1]
{
Trivium::LanguageAnnotation(lang.clone()).pretty(doc);
doc.push(hardspace());
push_group(doc, |d| string_item.pretty(d));
i += 2;
continue;
}
items[i].pretty(doc);
i += 1;
}
}
}
}
pub(super) fn push_parenthesized_inner(doc: &mut Doc, expr: &Expression) {
match expr {
_ if is_absorbable_expr(expr) => {
push_group(doc, |inner| {
push_absorb_expr(inner, Width::Regular, expr);
});
}
Expression::Application(_, _) => {
push_pretty_app(doc, true, &[], true, expr);
}
Expression::Term(Term::Selection(term, _, _)) if is_absorbable_term(term) => {
doc.push(line_prime());
push_group(doc, |inner| {
expr.pretty(inner);
});
doc.push(line_prime());
}
Expression::Term(Term::Selection(_, _, _)) => {
push_group(doc, |inner| {
expr.pretty(inner);
});
doc.push(line_prime());
}
_ => {
doc.push(line_prime());
push_group(doc, |inner| {
expr.pretty(inner);
});
doc.push(line_prime());
}
}
}
pub(super) fn push_pretty_parenthesized(
doc: &mut Doc,
open: &Ann<Token>,
expr: &Expression,
close: &Ann<Token>,
) {
let (mut open, trail, close_pre, close) = split_paren_trivia(open, close);
open.pre_trivia.extend(trail);
push_group(doc, |g| {
open.pretty(g);
push_nested(g, |nested| {
push_parenthesized_inner(nested, expr);
close_pre.pretty(nested);
});
close.pretty(g);
});
}