Linetype rename keeps layer, object and current-linetype references (#74) (#195)

This commit is contained in:
MarekSpodBiedry authored and GitHub committed 2026-10-10 14:40:13 -04:00
1 parent 3b73884abd
commit 7f84f9c874
2 files changed
+65 -1

No files matched your search

+31
View File
@@ -477,3 +477,34 @@ fn setvar_dim_variables_apply_to_new_dimensions() {
let zero = linear(&mut s, -120.0);
assert!((text_height(&s, zero) - base).abs() < 1e-12);
}
#[test]
fn linetype_rename_updates_references() {
fn line(s: &mut Session, y: f64) -> Handle {
let r = s.execute("line", &json!({ "points": [[0.0, y], [10.0, y]] })).unwrap();
Handle::parse_hex(r["handles"][0].as_str().unwrap()).unwrap()
}
let mut s = Session::new();
s.execute("linetype", &json!({ "load": "DASHED" })).unwrap();
s.execute("layer.new", &json!({ "name": "A", "linetype": "DASHED", "current": true })).unwrap();
let by_layer = line(&mut s, 0.0);
s.execute("linetype", &json!({ "current": "DASHED" })).unwrap();
let explicit = line(&mut s, 2.0);
let in_block = line(&mut s, 4.0);
s.execute("block", &json!({ "name": "B", "base": [0, 0], "handles": [in_block.hex()], "keep": "delete" })).unwrap();
s.execute("rename", &json!({ "table": "linetype", "from": "DASHED", "to": "MYDASH" })).unwrap();
let d = s.doc().unwrap();
assert!(d.linetype("DASHED").is_none());
assert!(d.linetype("MYDASH").is_some());
assert_eq!(d.layers.iter().find(|l| l.name == "A").unwrap().linetype, "MYDASH");
assert_eq!(d.layers.iter().find(|l| l.name == "0").unwrap().linetype, "Continuous");
assert_eq!(d.entity(by_layer).unwrap().common.linetype, "ByLayer");
assert_eq!(d.entity(explicit).unwrap().common.linetype, "MYDASH");
let block: Vec<&str> = d.blocks["B"].entities.iter().map(|e| e.common.linetype.as_str()).collect();
assert_eq!(block, ["MYDASH"]);
assert_eq!(d.header.str("CELTYPE", ""), "MYDASH");
// An existing target name and the reserved linetypes are refused.
assert!(s.execute("rename", &json!({ "table": "linetype", "from": "MYDASH", "to": "Continuous" })).is_err());
assert!(s.execute("rename", &json!({ "table": "linetype", "from": "ByLayer", "to": "X" })).is_err());
assert_eq!(s.doc().unwrap().entity(by_layer).unwrap().common.linetype, "ByLayer");
}
+34 -1
View File
@@ -869,8 +869,41 @@ fn run_rename(s: &mut Session, p: &Value) -> Result<Value> {
}
"linetype" => {
let d = s.doc_mut()?;
if ["ByBlock", "ByLayer", "Continuous"].iter().any(|n| from.eq_ignore_ascii_case(n)) {
return Err(bad("rename", format!("the {from} linetype cannot be renamed")));
}
if d.linetype(&to).is_some() && !to.eq_ignore_ascii_case(&from) {
return Err(bad("rename", format!("a linetype `{to}` already exists")));
}
let st = d.linetypes.iter_mut().find(|t| t.name.eq_ignore_ascii_case(&from)).ok_or_else(|| bad("rename", "no such linetype"))?;
st.name = to;
st.name = to.clone();
// References follow the new name.
let fix = |n: &mut String| {
if n.eq_ignore_ascii_case(&from) {
*n = to.clone();
}
};
d.layers.iter_mut().for_each(|l| fix(&mut l.linetype));
if d.header.str("CELTYPE", "ByLayer").eq_ignore_ascii_case(&from) {
d.header.set_str("CELTYPE", &to);
}
let users = |st: &cadcraft_doc::EntityStore| -> Vec<cadcraft_doc::Handle> {
st.iter().filter(|e| e.common.linetype.eq_ignore_ascii_case(&from)).map(|e| e.handle).collect()
};
let mut hs = users(&d.model);
hs.extend(d.layouts.iter().flat_map(|l| users(&l.entities)));
for h in hs {
d.modify_entity(h, |e| fix(&mut e.common.linetype))?;
}
for block in d.blocks.values_mut() {
let hs = users(&block.entities);
if !hs.is_empty() {
let b = std::sync::Arc::make_mut(block);
for h in hs {
b.entities.modify(h, |e| fix(&mut e.common.linetype));
}
}
}
}
_ => return Err(bad("rename", "unsupported table")),
}