M7: a batch of content edits refreshes the added content and page marks

A content-only edit re-reads Document::added() and marks() only when the
edit itself is one that changes them. Edit::Batch has Scope::Content when
all its parts do, but content_refresh_lists never looked inside it, so a
batch of AddText/DeleteContent or AddWatermark edits left both lists stale
until the next full refresh or undo. It now answers for its parts.

Co-Authored-By: Opus 5.5 medium ultracode <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gEgu9NcTcPqKovsLyfPxK
This commit is contained in:
nleva
2026-10-23 17:09:29 +02:00
co-authored by Opus 5.5 medium ultracode
parent 57e531ccca
commit d8aff8bfc7
2 changed files with 22 additions and 0 deletions
+7
View File
@@ -4177,6 +4177,13 @@ impl Session {
/// Which derived lists a content-only edit can change: added content (`None`, from
/// undo/redo, re-reads both: always correct, rarely paid).
fn content_refresh_lists(edit: Option<&Edit>) -> (bool, bool) {
if let Some(Edit::Batch { edits, .. }) = edit {
// A batch of content edits (from a script, say) changes what its parts change.
return edits.iter().fold((false, false), |(added, marks), part| {
let (a, m) = Self::content_refresh_lists(Some(part));
(added || a, marks || m)
});
}
let touches_added = edit.is_none_or(|e| {
matches!(
e,
+15
View File
@@ -3155,6 +3155,21 @@ fn added_text_and_images_render_and_stay_editable() {
assert_eq!(s.get(id).unwrap().added().len(), 2);
}
#[test]
fn a_batch_of_content_edits_refreshes_the_added_content_and_marks() {
let (mut s, id) = session_with(1);
let text = |t: &str, y: f64| AddedText { rect: [20.0, y, 180.0, y + 14.4], text: t.into(), ..AddedText::default() };
let edits = vec![Edit::AddText { page: 0, text: text("One", 200.0) }, Edit::AddText { page: 0, text: text("Two", 150.0) }];
s.apply(id, Edit::Batch { label: "Script".into(), edits }).unwrap();
assert_eq!(s.get(id).unwrap().added().len(), 2);
s.apply(id, Edit::Batch { label: "Script".into(), edits: vec![Edit::DeleteContent { page: 0, index: 0 }] }).unwrap();
assert_eq!(s.get(id).unwrap().added().len(), 1);
let watermark =
Edit::AddWatermark { pages: vec![0], settings: Watermark { text: "Draft".into(), ..Watermark::default() }, file: None, replace: false };
s.apply(id, Edit::Batch { label: "Script".into(), edits: vec![watermark] }).unwrap();
assert_eq!(s.get(id).unwrap().marks().len(), 1);
}
#[test]
fn added_images_rotate_flip_and_crop_as_drawn() {
// A 20×10 image: left half red, right half blue.