From a3742e56684d724030d8a9181dfd3e2c3a6e934d Mon Sep 17 00:00:00 2001 From: Karim Jerbi Date: Fri, 9 Oct 2026 20:43:11 +0100 Subject: [PATCH] fix(styles): follow text rename into dimstyle dimtxsty rename_style_storage and rename_symbol rewrote entities and table rows but left dimtxsty stale, so the next Apply resolved a NULL handle. The follow now lives in both shared functions; the plugin workaround is removed as redundant. Tests: text_rename_follows_dimtxsty drives the manager path (RED first); pre-existing plugin rename test stays green via the shared path. Full suite: 2015 passed / 0 failed / 25 ignored. --- src/app/commands/styleprops.rs | 7 +++++++ src/app/plugin_host.rs | 9 +-------- src/app/style_ops.rs | 35 ++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/app/commands/styleprops.rs b/src/app/commands/styleprops.rs index d8faa16c4..65727b6bf 100644 --- a/src/app/commands/styleprops.rs +++ b/src/app/commands/styleprops.rs @@ -3572,6 +3572,13 @@ fn rename_symbol(doc: &mut codec::CadDocument, ty: &str, old: &str, new: &str) - if doc.header.current_text_style_name.eq_ignore_ascii_case(old) { doc.header.current_text_style_name = new.to_string(); } + // Dimension styles name their text style; follow the rename (same + // as rename_style_storage — see #42). + for ds in doc.dim_styles.iter_mut() { + if ds.dimtxsty.eq_ignore_ascii_case(old) { + ds.dimtxsty = new.to_string(); + } + } true } "DIMSTYLE" => { diff --git a/src/app/plugin_host.rs b/src/app/plugin_host.rs index 6b1d737de..bfb53916f 100644 --- a/src/app/plugin_host.rs +++ b/src/app/plugin_host.rs @@ -2160,14 +2160,7 @@ impl<'a> HostSession<'a> { } self.push_undo("Rename style"); self.app.rename_style_storage(kind_of(kind), &from, &to); - if kind == TableStyleKind::Text { - // A dimension style names its text style; follow the rename. - for dim in self.document_mut().dim_styles.iter_mut() { - if dim.dimtxsty.eq_ignore_ascii_case(&from) { - dim.dimtxsty = to.clone(); - } - } - } + // dimtxsty follow lives in rename_style_storage (#42). self.finish_style_change(kind_of(kind)); Ok(handle) } diff --git a/src/app/style_ops.rs b/src/app/style_ops.rs index 841f1b91f..64ea03ce8 100644 --- a/src/app/style_ops.rs +++ b/src/app/style_ops.rs @@ -610,6 +610,13 @@ impl OpenCADStudio { } } } + // Dimension styles name their text style; follow the rename so + // Apply keeps resolving the handle instead of collapsing to NULL. + for ds in doc.dim_styles.iter_mut() { + if ds.dimtxsty.eq_ignore_ascii_case(old) { + ds.dimtxsty = new.to_string(); + } + } } StyleKind::Dim => { let doc = &mut self.tabs[i].scene.document; @@ -1270,3 +1277,31 @@ impl OpenCADStudio { } } } + +#[cfg(test)] +mod rename_follow_tests { + // #42: renaming a text style must follow into dimstyle dimtxsty. + use super::{OpenCADStudio, StyleKind}; + use codec::tables::{DimStyle, TextStyle}; + + #[test] + fn text_rename_follows_dimtxsty() { + let mut app = OpenCADStudio::new_for_test(); + app.automation_op(r#"{"op":"new"}"#); + let i = app.active_tab; + let mut ts = TextStyle::new("OLD"); + ts.handle = app.tabs[i].scene.document.allocate_handle(); + app.tabs[i].scene.document.text_styles.add(ts).unwrap(); + let mut ds = DimStyle::new("D"); + ds.dimtxsty = "OLD".to_string(); + app.tabs[i].scene.document.dim_styles.add(ds).unwrap(); + app.style_rename = Some("OLD".to_string()); + app.style_rename_buf = "NEW".to_string(); + app.style_rename_commit(StyleKind::Text); + let dim = app.tabs[i].scene.document.dim_styles.get("D").unwrap(); + assert_eq!( + dim.dimtxsty, "NEW", + "dimstyle must follow the text-style rename" + ); + } +}