use std::fmt;
use crate::ast::{Node, NodeKind};
use super::ansi_c::process_ansi_c_content;
use super::word::{self, WordSegment};
use super::{normalize_cmdsub_content, write_escaped_word};
pub(super) fn write_redirect(
f: &mut fmt::Formatter<'_>,
op: &str,
target: &Node,
_fd: i32,
) -> fmt::Result {
write!(f, "(redirect \"{op}\" ")?;
if let NodeKind::Word { value, spans, .. } = &target.kind {
let is_fd_op =
op.starts_with(">&") || op.starts_with("<&") || op.ends_with("&-") || op.ends_with('&');
if is_fd_op && !value.is_empty() && value.chars().all(|c| c.is_ascii_digit()) {
write!(f, "{value})")
} else if !spans.is_empty() {
write!(f, "\"")?;
let segments = word::segments_from_spans(value, spans);
write_redirect_segments(f, &segments)?;
write!(f, "\")")
} else {
write!(f, "\"{value}\")")
}
} else {
write!(f, "{target})")
}
}
pub(super) fn write_heredoc(
f: &mut fmt::Formatter<'_>,
content: &str,
strip_tabs: bool,
) -> fmt::Result {
let op = if strip_tabs { "<<-" } else { "<<" };
write!(f, "(redirect \"{op}\" \"{content}\")")
}
pub(super) fn write_redirect_segments(
f: &mut fmt::Formatter<'_>,
segments: &[WordSegment],
) -> fmt::Result {
for seg in segments {
match seg {
WordSegment::Literal(text) => write!(f, "{text}")?,
WordSegment::AnsiCQuote(raw) => {
let chars: Vec<char> = raw.chars().collect();
let mut pos = 0;
let processed = process_ansi_c_content(&chars, &mut pos);
write!(f, "'{processed}'")?;
}
WordSegment::LocaleString(content) => {
write!(f, "{content}")?;
}
WordSegment::CommandSubstitution(content) => {
write!(f, "$(")?;
if let Some(reformatted) = crate::format::reformat_bash(content) {
write!(f, "{reformatted}")?;
} else {
let normalized = normalize_cmdsub_content(content);
write!(f, "{normalized}")?;
}
write!(f, ")")?;
}
WordSegment::ProcessSubstitution(dir, content) => {
write!(f, "{dir}(")?;
if let Some(reformatted) = crate::format::reformat_bash(content) {
write!(f, "{reformatted}")?;
} else {
let normalized = normalize_cmdsub_content(content);
write!(f, "{normalized}")?;
}
write!(f, ")")?;
}
WordSegment::ParamExpansion(text)
| WordSegment::SimpleVar(text)
| WordSegment::BraceExpansion(text) => {
write!(f, "{text}")?;
}
WordSegment::ArithmeticSub(inner) => {
write!(f, "$(({inner}))")?;
}
}
}
Ok(())
}
pub(super) fn write_arith_command(f: &mut fmt::Formatter<'_>, raw_content: &str) -> fmt::Result {
write!(f, "(arith (word \"")?;
write_escaped_word(f, raw_content)?;
write!(f, "\"))")
}