use super::*;
pub(crate) fn command_group_commands(command: &Command) -> Option<(&StmtSeq, char)> {
match command {
Command::Compound(CompoundCommand::BraceGroup(commands)) => Some((commands, '{')),
Command::Compound(CompoundCommand::Subshell(commands)) => Some((commands, '(')),
_ => None,
}
}
pub(crate) fn branch_open_keyword_start(
sequence: &StmtSeq,
source: &str,
keyword: &str,
) -> Option<usize> {
let first = sequence.first()?;
SourceView::new(source)
.last_uncommented_shell_keyword_before(stmt_span(first).start.offset, keyword)
}
pub(crate) fn if_next_branch_region_with_body_end(
command: &IfCommand,
branch_index: usize,
source: &str,
mut branch_body_end: impl FnMut(&StmtSeq) -> usize,
) -> Option<(usize, usize)> {
let current_branch_end = if branch_index == 0 {
branch_body_end(&command.then_branch)
} else {
command
.elif_branches
.get(branch_index - 1)
.map(|(_, body)| branch_body_end(body))
.unwrap_or_else(|| branch_body_end(&command.then_branch))
};
if let Some((condition, _)) = command.elif_branches.get(branch_index) {
let keyword = SourceView::new(source)
.branch_keyword_offset(current_branch_end, condition.span.start.offset, "elif")
.unwrap_or(condition.span.start.offset);
Some((current_branch_end, keyword))
} else if branch_index == command.elif_branches.len() {
command.else_branch.as_ref().map(|body| {
let keyword = SourceView::new(source)
.branch_keyword_offset(current_branch_end, body.span.start.offset, "else")
.unwrap_or(body.span.start.offset);
(current_branch_end, keyword)
})
} else {
None
}
}
pub(crate) fn collect_pipeline_parts<'a, T>(
command: &'a BinaryCommand,
statements: &mut Vec<&'a Stmt>,
operators: &mut Vec<T>,
operator_for: &impl Fn(&BinaryCommand) -> T,
) {
collect_pipeline_stmt_parts(command.left.as_ref(), statements, operators, operator_for);
operators.push(operator_for(command));
collect_pipeline_stmt_parts(command.right.as_ref(), statements, operators, operator_for);
}
fn collect_pipeline_stmt_parts<'a, T>(
stmt: &'a Stmt,
statements: &mut Vec<&'a Stmt>,
operators: &mut Vec<T>,
operator_for: &impl Fn(&BinaryCommand) -> T,
) {
if let Some(binary) = stmt_plain_pipeline_binary(stmt) {
collect_pipeline_parts(binary, statements, operators, operator_for);
} else {
statements.push(stmt);
}
}
fn stmt_plain_pipeline_binary(stmt: &Stmt) -> Option<&BinaryCommand> {
if let Command::Binary(binary) = &stmt.command
&& stmt.redirects.is_empty()
&& !stmt.negated
&& stmt.terminator.is_none()
&& matches!(
binary.op,
shuck_ast::BinaryOp::Pipe | shuck_ast::BinaryOp::PipeAll
)
{
Some(binary)
} else {
None
}
}
pub(crate) fn collect_binary_list_first<'a, T>(
command: &'a BinaryCommand,
rest: &mut Vec<T>,
item_for: &impl Fn(&'a BinaryCommand) -> T,
) -> &'a Stmt {
if let Command::Binary(left_binary) = &command.left.command
&& command.left.redirects.is_empty()
&& !command.left.negated
&& command.left.terminator.is_none()
&& matches!(left_binary.op, BinaryOp::And | BinaryOp::Or)
{
let first = collect_binary_list_first(left_binary, rest, item_for);
rest.push(item_for(command));
return first;
}
let first = command.left.as_ref();
rest.push(item_for(command));
first
}