mod lists;
mod nodes;
mod redirects;
mod words;
use std::cell::Cell;
use nodes::format_node;
thread_local! {
static REFORMAT_DEPTH: Cell<usize> = const { Cell::new(0) };
}
struct DepthGuard;
impl DepthGuard {
fn enter() -> Option<Self> {
REFORMAT_DEPTH.with(|d| {
let v = d.get();
if v >= 2 {
return None;
}
d.set(v + 1);
Some(Self)
})
}
}
impl Drop for DepthGuard {
fn drop(&mut self) {
REFORMAT_DEPTH.with(|d| d.set(d.get().saturating_sub(1)));
}
}
pub fn reformat_bash(source: &str) -> Option<String> {
if source.is_empty() || source.len() > 1000 {
return None;
}
let _guard = DepthGuard::enter()?;
let dominated_by_words = source
.chars()
.all(|c| c.is_alphanumeric() || c == ' ' || c == '_' || c == '-' || c == '.' || c == '/');
if dominated_by_words {
return None;
}
let nodes = crate::parse(source, false).ok()?;
if nodes.is_empty() {
return Some(String::new());
}
let mut out = String::new();
for (i, node) in nodes.iter().enumerate() {
if i > 0 {
out.push('\n');
}
format_node(node, &mut out, 0);
}
let trimmed = out.trim_end_matches([' ', '\t']);
Some(trimmed.to_string())
}