From ebcc564f1e0cc20b2fcbe9985b7c74c39ac53399 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Mon, 9 Nov 2026 03:09:46 +0100 Subject: [PATCH] Keep the outline intact when move_bookmark gets an invalid target (#4901) --- crates/organize/src/outline.rs | 3 ++- crates/organize/src/tests.rs | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/organize/src/outline.rs b/crates/organize/src/outline.rs index 84cf3d164d..e9e20bd9fc 100644 --- a/crates/organize/src/outline.rs +++ b/crates/organize/src/outline.rs @@ -700,6 +700,8 @@ pub fn move_bookmark(doc: &mut Document, from: &[usize], to_parent: &[usize], in return Err(OutlineError::IntoItself); } let (r, old_parent) = resolve_path(doc, from)?; + // Validate the target before touching the old parent, so an error leaves the outline intact. + let parent = container(doc, to_parent)?; let mut old = children_of(doc, old_parent, &mut HashSet::from([old_parent])); old.retain(|k| *k != r); relink(doc, old_parent, &old)?; @@ -709,7 +711,6 @@ pub fn move_bookmark(doc: &mut Document, from: &[usize], to_parent: &[usize], in if to_parent.len() > depth && to_parent[..depth] == from[..depth] && to_parent[depth] > from[depth] { to_parent[depth] -= 1; } - let parent = container(doc, &to_parent)?; let mut kids = children_of(doc, parent, &mut HashSet::from([parent])); let at = index.min(kids.len()); kids.insert(at, r); diff --git a/crates/organize/src/tests.rs b/crates/organize/src/tests.rs index b0d22f7b59..6e8f2df4be 100644 --- a/crates/organize/src/tests.rs +++ b/crates/organize/src/tests.rs @@ -1731,6 +1731,15 @@ fn count_of(doc: &Document, r: ObjRef) -> Option { doc.get(r).as_dict().and_then(|d| d.int(b"Count")) } +#[test] +fn move_bookmark_to_missing_parent_keeps_outline() { + let mut d = doc_a(); + crate::add_bookmark(&mut d, &[], 0, "Intro", 0).unwrap(); + crate::add_bookmark(&mut d, &[], 9, "Results", 2).unwrap(); + assert!(crate::move_bookmark(&mut d, &[0], &[7], 0).is_err()); + assert_eq!(titles(&crate::bookmarks(&d)), ["Intro", "Results"]); +} + #[test] fn bookmarks_add_rename_move_delete() { let mut d = doc_a();