diff --git a/crates/engine/src/cmd/slide.rs b/crates/engine/src/cmd/slide.rs index 4a82f2a7..b203f083 100644 --- a/crates/engine/src/cmd/slide.rs +++ b/crates/engine/src/cmd/slide.rs @@ -218,6 +218,9 @@ fn duplicate(s: &mut Session, p: &Value) -> Result { && let Some(sec) = doc.sections.get_mut(si) { sec.slides.push(nid); + // Keep the section list in document order so the copy sits next to its source. + let order: Vec = doc.slides.iter().map(|x| x.id).collect(); + sec.slides.sort_by_key(|x| order.iter().position(|o| o == x).unwrap_or(usize::MAX)); } } sel.slide = (last + new_ids.len()).min(doc.slides.len().saturating_sub(1)); @@ -634,6 +637,23 @@ mod tests { use crate::Session; + #[test] + fn duplicate_keeps_section_order_in_step_with_slides() { + let mut s = Session::with_new(); + while s.doc().expect("doc").doc.slides.len() < 3 { + s.execute("slide.new", &json!({})).expect("new slide"); + } + s.execute("section.add", &json!({"at": 0})).expect("section"); + let orig = s.doc().expect("doc").doc.slides.first().expect("slide").id; + s.execute("slide.duplicate", &json!({"index": 0})).expect("dup"); + let st = s.doc().expect("doc"); + let all: Vec<_> = st.doc.slides.iter().map(|x| x.id).collect(); + let sec = &st.doc.sections.first().expect("section").slides; + assert_eq!(all.len(), 4); + assert_eq!(sec, &all, "section order must match slide order"); + assert_eq!(sec.first(), Some(&orig)); + } + #[test] fn new_slide_body_leading_tabs_become_levels() { let mut s = Session::with_new();