mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-09 14:14:11 +00:00
Merge pull request #5396 from storytold/fix/sec-followup-5303
Threads: a frame left alone by a dropped repeat is flowed again
This commit is contained in:
@@ -97,15 +97,25 @@ pub(crate) fn reflow(before: &Document, doc: &mut Document) {
|
||||
// copy its text into the story each time, and write the grown story back for the next thread
|
||||
// to copy again. Only its first place counts.
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
let threads: Vec<Vec<NodeId>> =
|
||||
std::mem::take(&mut doc.text_threads).into_iter().map(|t| t.into_iter().filter(|id| seen.insert(*id)).collect()).collect();
|
||||
// A thread that lost a frame that way is flowed again: its frames' layout was made for the
|
||||
// thread as listed (a frame left alone must lose its threaded continuation).
|
||||
let threads: Vec<(Vec<NodeId>, bool)> = std::mem::take(&mut doc.text_threads)
|
||||
.into_iter()
|
||||
.map(|t| {
|
||||
let listed = t.len();
|
||||
let t: Vec<NodeId> = t.into_iter().filter(|id| seen.insert(*id)).collect();
|
||||
let lost = t.len() != listed;
|
||||
(t, lost)
|
||||
})
|
||||
.collect();
|
||||
let mut kept = vec![];
|
||||
for thread in threads {
|
||||
let changed = thread.iter().any(|id| match (before.node(*id), doc.node(*id)) {
|
||||
(Some(a), Some(b)) => !std::ptr::eq(a, b),
|
||||
(None, None) => false,
|
||||
_ => true,
|
||||
});
|
||||
for (thread, lost) in threads {
|
||||
let changed = lost
|
||||
|| thread.iter().any(|id| match (before.node(*id), doc.node(*id)) {
|
||||
(Some(a), Some(b)) => !std::ptr::eq(a, b),
|
||||
(None, None) => false,
|
||||
_ => true,
|
||||
});
|
||||
// When no frame changed, the thread keeps its area-type frames and their text is not copied.
|
||||
if !changed {
|
||||
let live: Vec<NodeId> = thread.into_iter().filter(|id| text_of(doc, *id).is_some()).collect();
|
||||
|
||||
@@ -58,6 +58,29 @@ fn frames_listed_twice_flow_the_story_once() {
|
||||
assert_eq!(format!("{}{}", plain(fa), plain(fb)), TEXT.repeat(4));
|
||||
}
|
||||
|
||||
/// A frame left alone when a repeated listing is dropped (`[[a, b], [b, c]]` → `[[a, b], [c]]`)
|
||||
/// is flowed again as a story of its own, even when no frame changed: it no longer continues a
|
||||
/// paragraph from the frame before it.
|
||||
#[test]
|
||||
fn a_frame_left_alone_by_a_dropped_repeat_stops_continuing() {
|
||||
let (mut s, a, b) = setup();
|
||||
s.execute("text.thread.create", &json!({})).unwrap();
|
||||
let c =
|
||||
s.execute("text.create", &json!({"x": 400, "y": 10, "text": "Tail", "area": {"width": 150, "height": 60}})).unwrap()["id"].as_u64().unwrap();
|
||||
let mut d = (*s.doc().unwrap().doc).clone();
|
||||
let (fa, fb, fc) = (NodeId(a), NodeId(b), NodeId(c));
|
||||
d.text_threads = vec![vec![fa, fb], vec![fb, fc]];
|
||||
if let Some(NodeKind::Text(t)) = d.node_mut(fc).map(|n| &mut n.kind) {
|
||||
t.first_para_continues = true;
|
||||
}
|
||||
let before = d.clone();
|
||||
reflow(&before, &mut d);
|
||||
assert_eq!(d.text_threads, vec![vec![fa, fb]]);
|
||||
let NodeKind::Text(t) = &d.node(fc).unwrap().kind else { panic!("not text") };
|
||||
assert!(!t.first_para_continues, "an unthreaded frame continues nothing");
|
||||
assert_eq!(t.plain_text(), "Tail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edits_copy_only_the_stories_of_threads_whose_frames_changed() {
|
||||
let (mut s, a, b) = setup();
|
||||
|
||||
Reference in New Issue
Block a user