From 82340cee5c5e7bf26c5c0b3fde55c13973821844 Mon Sep 17 00:00:00 2001 From: Vikram Bhaskaran Date: Sat, 10 Oct 2026 16:21:47 +1100 Subject: [PATCH] Snap selected clips to their neighbours instead of past them. Snap to Next and Snap to Previous ignored other selected clips when looking for a destination, so a multi-clip selection piled onto the same later clip or left the gap between the selected clips in place. --- crates/engine/src/cmd/edit_more.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/crates/engine/src/cmd/edit_more.rs b/crates/engine/src/cmd/edit_more.rs index d27bb975..ae16f884 100644 --- a/crates/engine/src/cmd/edit_more.rs +++ b/crates/engine/src/cmd/edit_more.rs @@ -663,8 +663,10 @@ fn snap(e: &mut Engine, p: &Value, next: bool) -> Result { let mut moved = 0; for (id, _) in order { let Some((t, c)) = s.find_clip(id).map(|(t, c)| (t, c.clone())) else { continue }; - let others = - s.track(t).map(|tr| tr.clips().iter().filter(|x| x.id != id && !ids.contains(&x.id)).cloned().collect::>()).unwrap_or_default(); + // Selected neighbours are real destinations. Ignoring them made Snap to Next + // pile every selected clip onto the same later clip, and Snap to Previous + // leave the gap between the selected clips in place. + let others = s.track(t).map(|tr| tr.clips().iter().filter(|x| x.id != id).cloned().collect::>()).unwrap_or_default(); let delta = if next { others.iter().filter(|x| x.start >= c.end()).map(|x| x.start).min().map(|st| st - c.end()) } else { @@ -982,6 +984,19 @@ mod tests { assert_eq!(starts(&e, t), vec![0, 900, 1000]); } + #[test] + fn snap_selected_neighbours_keeps_both_clips() { + let (mut e, t, ids) = session_with_clips(&[(0, 100), (300, 100), (1000, 100)]); + e.execute("edit.snap_next", &json!({"clips": [ids[0].0, ids[1].0]})).unwrap(); + assert_eq!(e.session().track(t).unwrap().clips().len(), 3); + assert_eq!(starts(&e, t), vec![800, 900, 1000]); + + let (mut e, t, ids) = session_with_clips(&[(0, 100), (300, 100), (1000, 100)]); + e.execute("edit.snap_previous", &json!({"clips": [ids[0].0, ids[1].0]})).unwrap(); + assert_eq!(e.session().track(t).unwrap().clips().len(), 3); + assert_eq!(starts(&e, t), vec![0, 100, 1000]); + } + #[test] fn copy_and_paste_automation_only() { let (mut e, t, _) = session_with_clips(&[(0, 1000)]);