From a41f254aa097a4fb673f54e3d883033fc686a96f Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sat, 24 Oct 2026 15:19:28 -0700 Subject: [PATCH] Fades: Create refuses a shape that is not a string over a selection edit.fades_create over tracks and a range read a null, boolean or number shape as absent and made Equal Power fades. It now returns an error that lists the accepted shapes, as the clip form already did, and leaves the session and the undo history unchanged. --- crates/engine/src/cmd/edit.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/crates/engine/src/cmd/edit.rs b/crates/engine/src/cmd/edit.rs index 5536668b..698fb1df 100644 --- a/crates/engine/src/cmd/edit.rs +++ b/crates/engine/src/cmd/edit.rs @@ -805,9 +805,13 @@ fn strip_silence(e: &mut Engine, p: &Value) -> Result { } fn fades_create(e: &mut Engine, p: &Value) -> Result { - let shape = str_param(p, "shape") - .map_or(Some(FadeShape::EqualPower), FadeShape::from_id) - .ok_or_else(|| bad("edit.fades_create", "unknown fade shape"))?; + let shape = match p.get("shape") { + None => FadeShape::EqualPower, + Some(v) => v + .as_str() + .and_then(FadeShape::from_id) + .ok_or_else(|| bad("edit.fades_create", "shape must be linear|equal power|s-curve|exponential|logarithmic"))?, + }; if p.get("clip").is_some() || p.get("side").is_some() { let curvature = match p.get("curvature") { None => 0.0, @@ -835,9 +839,6 @@ fn fades_create(e: &mut Engine, p: &Value) -> Result { if available <= 0 { return Err(bad("edit.fades_create", "clip has no length")); } - if p.get("shape").is_some_and(|v| !v.is_string()) { - return Err(bad("edit.fades_create", "shape must be a fade shape name")); - } let fade = Fade { len: length.min(available), shape, curvature }; let clip = e.session_mut().find_clip_mut(id).ok_or_else(|| bad("edit.fades_create", "clip not found"))?; if fade_in { @@ -1074,6 +1075,19 @@ mod tests { assert_eq!(e.session(), &before); } + #[test] + fn range_fades_refuse_a_shape_that_is_not_a_shape_name() { + for shape in [json!("bad"), json!(null), json!(true), json!(1)] { + let (mut e, t, _) = trim_session(&[(0, 10_000, 0), (10_000, 10_000, 10_000)]); + let before = e.session().clone(); + let history = e.undo_history(); + let params = json!({"tracks": [t], "start": 9_500, "end": 10_500, "shape": shape}); + assert!(e.execute("edit.fades_create", ¶ms).is_err(), "{params}"); + assert_eq!(e.session(), &before, "{params}"); + assert_eq!(e.undo_history(), history, "{params}"); + } + } + #[test] fn targeted_fades_support_one_sample_clips() { let mut e = crate::demo::demo_engine();