use crate::parser::Ref;
use crate::types::ParseError;
use super::translate::collect_shiftable_refs;
fn same_sheet(a: &str, b: &str) -> bool {
a.to_uppercase() == b.to_uppercase()
}
fn ref_sheet(r: &Ref) -> Option<&str> {
match r {
Ref::Cell { sheet: Some(s), .. } | Ref::Range { sheet: Some(s), .. } => Some(s.as_str()),
_ => None,
}
}
fn renamed_ref_text(r: &Ref, new: &str) -> String {
match r {
Ref::Cell { addr, .. } => Ref::Cell { sheet: Some(new.to_string()), addr: *addr }.to_string(),
Ref::Range { start, end, .. } => {
Ref::Range { sheet: Some(new.to_string()), start: *start, end: *end }.to_string()
}
Ref::Name(_) => unreachable!("collect_shiftable_refs never returns Ref::Name"),
}
}
pub(crate) fn rename_sheet_refs_text(
formula: &str,
old: &str,
new: &str,
) -> Result<String, ParseError> {
let expr = crate::parser::parse_formula(formula)?;
let mut spans: Vec<_> = collect_shiftable_refs(&expr)
.into_iter()
.filter(|(_, r)| ref_sheet(r).is_some_and(|s| same_sheet(s, old)))
.collect();
spans.sort_by_key(|s| std::cmp::Reverse(s.0.offset)); let mut out = formula.to_string();
for (span, r) in spans {
let replacement = renamed_ref_text(&r, new);
let start = span.offset;
let end = span.offset + span.length;
out.replace_range(start..end, &replacement);
}
Ok(out)
}
#[cfg(test)]
mod tests;