use crate::predoc::{Doc, Pretty, hardline, hardspace};
use crate::types::{
Ann, Expression, FirstToken, Item, Items, Leaf, Selector, SimpleSelector, Term, Token, Trivia,
Trivium,
};
#[derive(Clone, Copy, PartialEq, Eq)]
pub(super) enum Width {
Regular,
Wide,
}
pub(super) fn has_trivia<T>(ann: &Ann<T>) -> bool {
!ann.pre_trivia.is_empty() || ann.trail_comment.is_some()
}
pub(super) fn is_lone_ann<T>(ann: &Ann<T>) -> bool {
!has_trivia(ann)
}
pub(super) fn term_first_token_has_pre_trivia(term: &Term) -> bool {
!term.first_token().pre_trivia.is_empty()
}
pub(super) fn items_has_only_comments<T>(items: &Items<T>) -> bool {
!items.0.is_empty() && items.0.iter().all(|i| matches!(i, Item::Comments(_)))
}
pub(super) fn is_spaces(s: &str) -> bool {
s.chars().all(char::is_whitespace)
}
pub(super) const fn is_simple_selector(selector: &Selector) -> bool {
matches!(selector.selector, SimpleSelector::ID(_))
}
pub(super) fn is_simple_term(term: &Term) -> bool {
match term {
Term::SimpleString(s) | Term::IndentedString(s) => is_lone_ann(s),
Term::Path(p) => is_lone_ann(p),
Term::Token(leaf)
if is_lone_ann(leaf)
&& matches!(
leaf.value,
Token::Identifier(_) | Token::Integer(_) | Token::Float(_) | Token::EnvPath(_)
) =>
{
true
}
Term::Selection(term, selectors, def) => {
is_simple_term(term) && selectors.iter().all(is_simple_selector) && def.is_none()
}
Term::Parenthesized(open, expr, close) => {
is_lone_ann(open) && is_lone_ann(close) && is_simple_expression(expr)
}
_ => false,
}
}
pub(super) fn is_simple_expression(expr: &Expression) -> bool {
match expr {
Expression::Term(term) => is_simple_term(term),
Expression::Application(f, a) => {
if let Expression::Application(f2, _) = &**f
&& matches!(**f2, Expression::Application(_, _))
{
return false;
}
is_simple_expression(f) && is_simple_expression(a)
}
_ => false,
}
}
pub(super) fn push_empty_brackets(doc: &mut Doc, open: &Leaf, close: &Leaf) {
open.pretty(doc);
if open.span.start_line == close.span.start_line {
doc.push(hardspace());
} else {
doc.push(hardline());
}
close.pretty(doc);
}
pub(super) fn pretty_ann_with<T>(doc: &mut Doc, ann: &Ann<T>, f: impl FnOnce(&mut Doc, &T)) {
ann.pre_trivia.pretty(doc);
f(doc, &ann.value);
ann.trail_comment.pretty(doc);
}
pub(super) fn move_trailing_comment_up<T: Clone>(ann: &Ann<T>) -> Ann<T> {
let mut out = ann.clone();
if let Some(tc) = out.trail_comment.take() {
out.pre_trivia.push(Trivium::from(&tc));
}
out
}
pub(super) fn split_paren_trivia(
open: &Ann<Token>,
close: &Ann<Token>,
) -> (Ann<Token>, Trivia, Trivia, Ann<Token>) {
let mut open = open.clone();
let trail: Trivia = open
.trail_comment
.take()
.map(|tc| vec![Trivium::from(&tc)])
.unwrap_or_default()
.into();
let mut close = close.clone();
let close_pre = std::mem::replace(&mut close.pre_trivia, Trivia::new());
(open, trail, close_pre, close)
}