diff --git a/crates/engine/src/macros/mod.rs b/crates/engine/src/macros/mod.rs index 9a580c791..38016049d 100644 --- a/crates/engine/src/macros/mod.rs +++ b/crates/engine/src/macros/mod.rs @@ -177,7 +177,9 @@ pub fn load(wb: &mut Workbook) -> Vec { /// The item key (`macro_`, lower-cased) of a hidden macro name, and `n` when it is a number. fn macro_item(n: &DefinedName) -> Option<(String, Option)> { - let key = stash::item_key(&n.name).filter(|k| n.scope.is_none() && k.starts_with(MACRO_KEY))?; + // Only a hidden workbook-scope name is macro storage: a person's own visible name that + // happens to look like one stays a name. + let key = stash::item_key(&n.name).filter(|k| n.hidden && n.scope.is_none() && k.starts_with(MACRO_KEY))?; let i = key.strip_prefix(MACRO_KEY).and_then(|i| i.parse().ok()); Some((key, i)) } diff --git a/crates/engine/src/macros/tests.rs b/crates/engine/src/macros/tests.rs index 4bd2ac1bc..9a28f14f9 100644 --- a/crates/engine/src/macros/tests.rs +++ b/crates/engine/src/macros/tests.rs @@ -127,6 +127,19 @@ fn hidden(name: &str, text: &str) -> DefinedName { DefinedName { name: name.into(), scope: None, formula: format!("\"{}\"", text.replace('"', "\"\"")), comment: String::new(), hidden: true } } +#[test] +fn a_visible_name_that_looks_like_macro_storage_is_left_alone() { + // Macro storage is hidden workbook-scope names; a visible `_gc_macro_0_0` someone defined + // is neither read as a macro nor removed when the workbook opens. + let mut wb = Workbook::new(); + let name = DefinedName { hidden: false, ..hidden("_gc_macro_0_0", "x") }; + wb.names.push(name.clone()); + let warnings = load(&mut wb); + assert!(warnings.is_empty(), "{warnings:?}"); + assert!(wb.macros.is_empty()); + assert_eq!(wb.names, vec![name]); +} + #[test] fn scripts_and_vba_stay_as_they_are() { // Automate scripts keep their own storage, and a VBA project is carried through unchanged.