diff --git a/library/src/layout/flow.rs b/library/src/layout/flow.rs index b05146c94..f47a8f42f 100644 --- a/library/src/layout/flow.rs +++ b/library/src/layout/flow.rs @@ -1,3 +1,5 @@ +use typst::model::{Property, StyleEntry}; + use super::{AlignNode, ColbreakNode, PlaceNode, Spacing, VNode}; use crate::prelude::*; use crate::text::ParNode; @@ -58,6 +60,8 @@ struct FlowLayouter { used: Size, /// The sum of fractions in the current region. fr: Fr, + /// Whether the last block was a paragraph. + last_block_was_par: bool, /// Spacing and layouted blocks. items: Vec, /// Finished frames for previous regions. @@ -92,6 +96,7 @@ impl FlowLayouter { full, used: Size::zero(), fr: Fr::zero(), + last_block_was_par: false, items: vec![], finished: vec![], } @@ -150,8 +155,18 @@ impl FlowLayouter { .unwrap_or(Align::Top), ); + // Disable paragraph indent if this is not a consecutive paragraph. + let reset; + let is_par = block.is::(); + let mut chained = styles; + if !self.last_block_was_par && is_par && !styles.get(ParNode::INDENT).is_zero() { + let property = Property::new(ParNode::INDENT, Length::zero()); + reset = StyleEntry::Property(property); + chained = reset.chain(&styles); + } + // Layout the block itself. - let frames = block.layout_block(world, &self.regions, styles)?; + let frames = block.layout_block(world, &self.regions, chained)?; let len = frames.len(); for (i, frame) in frames.into_iter().enumerate() { // Grow our size, shrink the region and save the frame for later. @@ -166,6 +181,8 @@ impl FlowLayouter { } } + self.last_block_was_par = is_par; + Ok(()) } diff --git a/library/src/layout/mod.rs b/library/src/layout/mod.rs index d6bc91751..f79da71c9 100644 --- a/library/src/layout/mod.rs +++ b/library/src/layout/mod.rs @@ -474,13 +474,14 @@ struct FlowBuilder<'a>(BehavedBuilder<'a>, bool); impl<'a> FlowBuilder<'a> { fn accept(&mut self, content: &Content, styles: StyleChain<'a>) -> bool { - let last_was_parbreak = self.1; - self.1 = false; + let last_was_parbreak = std::mem::replace(&mut self.1, false); if content.is::() { self.1 = true; + return true; } else if content.is::() || content.is::() { self.0.push(content.clone(), styles); + return true; } else if content.has::() { if !last_was_parbreak { let tight = if let Some(node) = content.downcast::() { @@ -505,11 +506,10 @@ impl<'a> FlowBuilder<'a> { self.0.push(above.pack(), styles); self.0.push(content.clone(), styles); self.0.push(below.pack(), styles); - } else { - return false; + return true; } - true + false } fn finish(self, doc: &mut DocBuilder<'a>, styles: StyleChain<'a>) { @@ -545,39 +545,10 @@ impl<'a> ParBuilder<'a> { } fn finish(self, parent: &mut Builder<'a>) { - let (mut children, shared) = self.0.finish(); - if children.is_empty() { - return; + let (children, shared) = self.0.finish(); + if !children.is_empty() { + parent.flow.accept(&ParNode(children).pack(), shared); } - - // Paragraph indent should only apply if the paragraph starts with - // text and follows directly after another paragraph. - let indent = shared.get(ParNode::INDENT); - if !indent.is_zero() - && children - .items() - .find_map(|child| { - if child.is::() || child.is::() { - Some(true) - } else if child.has::() { - Some(false) - } else { - None - } - }) - .unwrap_or_default() - && parent - .flow - .0 - .items() - .rev() - .find(|child| child.has::()) - .map_or(false, |child| child.is::()) - { - children.push_front(HNode::strong(indent.into()).pack()); - } - - parent.flow.accept(&ParNode(children).pack(), shared); } fn is_empty(&self) -> bool { diff --git a/library/src/text/par.rs b/library/src/text/par.rs index 3e72b0347..df02bc3cd 100644 --- a/library/src/text/par.rs +++ b/library/src/text/par.rs @@ -393,6 +393,26 @@ fn collect<'a>( let mut segments = vec![]; let mut iter = par.0.iter().peekable(); + let indent = styles.get(ParNode::INDENT); + if !indent.is_zero() + && par + .0 + .items() + .find_map(|child| { + if child.is::() || child.is::() { + Some(true) + } else if child.has::() { + Some(false) + } else { + None + } + }) + .unwrap_or_default() + { + full.push(SPACING_REPLACE); + segments.push((Segment::Spacing(indent.into()), *styles)); + } + while let Some((child, map)) = iter.next() { let styles = map.chain(styles); let segment = if child.is::() {