diff --git a/src/formats/odf/mod.rs b/src/formats/odf/mod.rs index e4a64553..85d95910 100644 --- a/src/formats/odf/mod.rs +++ b/src/formats/odf/mod.rs @@ -236,6 +236,50 @@ mod tests { ); } + #[test] + fn continued_sublist_restarts_when_its_parent_advances() { + // Word saves nested lists as ODT with continue-numbering on every + // level; item 2's sublist must read 2.1, not 2.3. + let content = r#" + + + + + + + Subject + Duty A + Duty B + + Price + Payment + + + "#; + let md = crate::document_to_markdown(&parse(&odt_with_content(content)).unwrap()); + assert!(md.contains("1.2. Duty B"), "{md}"); + assert!(md.contains("2.1. Payment"), "{md}"); + + // The same when each sublist names its own list style. + let styled = content + .replace( + "", + r#" + + "#, + ) + .replace( + r#""#, + r#""#, + ); + let md = crate::document_to_markdown(&parse(&odt_with_content(&styled)).unwrap()); + assert!(md.contains("1. Payment"), "{md}"); + assert!(!md.contains("3. Payment"), "{md}"); + } + #[test] fn repeated_rows_parse_content_once() { // A note inside a repeated row must register once, not per copy. diff --git a/src/formats/odf/text.rs b/src/formats/odf/text.rs index da64da40..bf888826 100644 --- a/src/formats/odf/text.rs +++ b/src/formats/odf/text.rs @@ -195,6 +195,12 @@ fn parse_list( } } let number = current.start.saturating_add(current.items.len() as u64); + if !header { + // A new item at this level restarts the levels below it, so a + // `continue-numbering` sublist under it starts afresh. + // Every style: a sublist may name its own list style. + ctx.list_counters.borrow_mut().retain(|(_, d), _| *d <= depth); + } let mut chain = ancestors.to_vec(); chain.push(number); let mut item_blocks = Vec::new();