mirror of
https://github.com/storytold/deckcraft.git
synced 2026-11-09 11:59:36 -06:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f21fb7259e | ||
|
|
a21353c273 | ||
|
|
50b9100971 | ||
|
|
9405a06993 |
@@ -466,22 +466,26 @@ fn ctx_xfrm(doc: &deckcraft_model::Presentation, sel: &crate::Selection, shape:
|
|||||||
|
|
||||||
/// Run `f` on each target shape (copy-on-write), materialising inherited boxes first.
|
/// Run `f` on each target shape (copy-on-write), materialising inherited boxes first.
|
||||||
pub(crate) fn edit_shapes(s: &mut Session, p: &Value, cmd: &str, f: impl Fn(&mut deckcraft_model::Shape) -> Result<()>) -> Result<Value> {
|
pub(crate) fn edit_shapes(s: &mut Session, p: &Value, cmd: &str, f: impl Fn(&mut deckcraft_model::Shape) -> Result<()>) -> Result<Value> {
|
||||||
let ids = targets(s, p)?;
|
let mut ids = targets(s, p)?;
|
||||||
if ids.is_empty() {
|
if ids.is_empty() {
|
||||||
return Err(bad(cmd, "no shapes selected"));
|
return Err(bad(cmd, "no shapes selected"));
|
||||||
}
|
}
|
||||||
|
// A shape named twice is edited once.
|
||||||
|
let mut seen = std::collections::HashSet::new();
|
||||||
|
ids.retain(|id| seen.insert(*id));
|
||||||
s.edit(|doc, sel| {
|
s.edit(|doc, sel| {
|
||||||
let boxes: Vec<(ShapeId, Xfrm)> = {
|
// The boxes are read from the shapes in place: no copy of a shape (and its text) per id.
|
||||||
let st_shapes: Vec<deckcraft_model::Shape> =
|
let boxes: std::collections::HashMap<ShapeId, Xfrm> = ids
|
||||||
ids.iter().filter_map(|id| current_shapes(doc, sel).and_then(|v| deckcraft_model::find_shape(v, *id)).cloned()).collect();
|
.iter()
|
||||||
st_shapes.iter().map(|sh| (sh.id, xfrm_of(doc, sel, sh))).collect()
|
.filter_map(|id| current_shapes(doc, sel).and_then(|v| deckcraft_model::find_shape(v, *id)))
|
||||||
};
|
.map(|sh| (sh.id, xfrm_of(doc, sel, sh)))
|
||||||
|
.collect();
|
||||||
let shapes = crate::shapes_mut(doc, sel).ok_or_else(|| bad(cmd, "no slide"))?;
|
let shapes = crate::shapes_mut(doc, sel).ok_or_else(|| bad(cmd, "no slide"))?;
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
for id in &ids {
|
for id in &ids {
|
||||||
if let Some(sh) = deckcraft_model::find_shape_mut(shapes, *id) {
|
if let Some(sh) = deckcraft_model::find_shape_mut(shapes, *id) {
|
||||||
if sh.xfrm.is_none() {
|
if sh.xfrm.is_none() {
|
||||||
sh.xfrm = boxes.iter().find(|(i, _)| i == id).map(|(_, x)| *x);
|
sh.xfrm = boxes.get(id).copied();
|
||||||
}
|
}
|
||||||
f(sh)?;
|
f(sh)?;
|
||||||
n += 1;
|
n += 1;
|
||||||
|
|||||||
@@ -6483,6 +6483,18 @@ fn master_body_placeholder_format_keeps_per_level_formatting() {
|
|||||||
assert_eq!(shown(&s), vec![Some(28.0), Some(24.0)]);
|
assert_eq!(shown(&s), vec![Some(28.0), Some(24.0)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A shape named many times in one edit is edited once and not copied per mention.
|
||||||
|
#[test]
|
||||||
|
fn repeated_target_ids_edit_the_shape_once() {
|
||||||
|
let mut s = session();
|
||||||
|
let r = s.execute("shape.insert", &json!({"preset": "rect", "rect": [100, 100, 300, 100], "text": "x".repeat(100_000)})).unwrap();
|
||||||
|
let id = r["id"].as_u64().unwrap();
|
||||||
|
let edited = s.execute("shape.fill", &json!({"ids": vec![id; 50_000], "color": "#ff0000"})).unwrap();
|
||||||
|
assert_eq!(edited, json!(1));
|
||||||
|
let v = s.execute("shape.inspect", &json!({"id": id})).unwrap();
|
||||||
|
assert_eq!(v["shape"]["fill"]["color"]["base"]["rgb"], json!({"a": 255, "b": 0, "g": 0, "r": 255}));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn slide_master_view_rejects_invalid_indices() {
|
fn slide_master_view_rejects_invalid_indices() {
|
||||||
let mut s = Session::with_new();
|
let mut s = Session::with_new();
|
||||||
|
|||||||
Reference in New Issue
Block a user