use crate::ast::{ListItem, ListOperator};
use super::formatter::Formatter;
use super::redirects::has_heredoc_redirect_deep;
pub(super) const fn list_op_str(op: ListOperator) -> &'static str {
match op {
ListOperator::And => " && ",
ListOperator::Or => " || ",
ListOperator::Semi => "; ",
ListOperator::Background => " & ",
}
}
impl Formatter {
pub(super) fn format_list(&mut self, items: &[ListItem]) {
for (i, item) in items.iter().enumerate() {
if i > 0 {
if let Some(op) = items[i - 1].operator {
let has_heredoc = has_heredoc_redirect_deep(&items[i - 1].command);
if op == ListOperator::Semi && has_heredoc {
self.write_char('\n');
} else {
self.write_list_op(op);
}
} else {
self.write_str("; ");
}
}
self.format_node(&item.command);
}
if let Some(last) = items.last()
&& let Some(op) = last.operator
{
if has_heredoc_redirect_deep(&last.command) {
self.insert_op_before_heredoc(op);
} else {
self.write_list_op(op);
}
}
}
fn insert_op_before_heredoc(&mut self, op: ListOperator) {
if let Some(heredoc_pos) = self.out().rfind("<<")
&& let Some(nl_pos) = self.out()[heredoc_pos..].find('\n')
{
let insert_at = heredoc_pos + nl_pos;
self.insert_at(insert_at, list_op_str(op).trim_end());
return;
}
self.write_list_op(op);
}
fn write_list_op(&mut self, op: ListOperator) {
self.write_str(list_op_str(op));
}
pub(super) fn format_list_block(&mut self, items: &[ListItem]) {
for (i, item) in items.iter().enumerate() {
if i == 0 {
self.indent_here();
}
self.format_node(&item.command);
if i + 1 >= items.len() {
continue;
}
match item.operator {
Some(ListOperator::And) => self.write_str(" && "),
Some(ListOperator::Or) => self.write_str(" || "),
Some(ListOperator::Background) => {
self.write_str(" &\n");
self.indent_here();
}
Some(ListOperator::Semi) | None => {
self.write_str(";\n");
self.indent_here();
}
}
}
}
}