mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Handle paragraph indent at a later stage
This commit is contained in:
parent
bf59c08a0a
commit
cabd0908e2
@ -1,3 +1,5 @@
|
|||||||
|
use typst::model::{Property, StyleEntry};
|
||||||
|
|
||||||
use super::{AlignNode, ColbreakNode, PlaceNode, Spacing, VNode};
|
use super::{AlignNode, ColbreakNode, PlaceNode, Spacing, VNode};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::text::ParNode;
|
use crate::text::ParNode;
|
||||||
@ -58,6 +60,8 @@ struct FlowLayouter {
|
|||||||
used: Size,
|
used: Size,
|
||||||
/// The sum of fractions in the current region.
|
/// The sum of fractions in the current region.
|
||||||
fr: Fr,
|
fr: Fr,
|
||||||
|
/// Whether the last block was a paragraph.
|
||||||
|
last_block_was_par: bool,
|
||||||
/// Spacing and layouted blocks.
|
/// Spacing and layouted blocks.
|
||||||
items: Vec<FlowItem>,
|
items: Vec<FlowItem>,
|
||||||
/// Finished frames for previous regions.
|
/// Finished frames for previous regions.
|
||||||
@ -92,6 +96,7 @@ impl FlowLayouter {
|
|||||||
full,
|
full,
|
||||||
used: Size::zero(),
|
used: Size::zero(),
|
||||||
fr: Fr::zero(),
|
fr: Fr::zero(),
|
||||||
|
last_block_was_par: false,
|
||||||
items: vec![],
|
items: vec![],
|
||||||
finished: vec![],
|
finished: vec![],
|
||||||
}
|
}
|
||||||
@ -150,8 +155,18 @@ impl FlowLayouter {
|
|||||||
.unwrap_or(Align::Top),
|
.unwrap_or(Align::Top),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Disable paragraph indent if this is not a consecutive paragraph.
|
||||||
|
let reset;
|
||||||
|
let is_par = block.is::<ParNode>();
|
||||||
|
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.
|
// 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();
|
let len = frames.len();
|
||||||
for (i, frame) in frames.into_iter().enumerate() {
|
for (i, frame) in frames.into_iter().enumerate() {
|
||||||
// Grow our size, shrink the region and save the frame for later.
|
// 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,13 +474,14 @@ struct FlowBuilder<'a>(BehavedBuilder<'a>, bool);
|
|||||||
|
|
||||||
impl<'a> FlowBuilder<'a> {
|
impl<'a> FlowBuilder<'a> {
|
||||||
fn accept(&mut self, content: &Content, styles: StyleChain<'a>) -> bool {
|
fn accept(&mut self, content: &Content, styles: StyleChain<'a>) -> bool {
|
||||||
let last_was_parbreak = self.1;
|
let last_was_parbreak = std::mem::replace(&mut self.1, false);
|
||||||
self.1 = false;
|
|
||||||
|
|
||||||
if content.is::<ParbreakNode>() {
|
if content.is::<ParbreakNode>() {
|
||||||
self.1 = true;
|
self.1 = true;
|
||||||
|
return true;
|
||||||
} else if content.is::<VNode>() || content.is::<ColbreakNode>() {
|
} else if content.is::<VNode>() || content.is::<ColbreakNode>() {
|
||||||
self.0.push(content.clone(), styles);
|
self.0.push(content.clone(), styles);
|
||||||
|
return true;
|
||||||
} else if content.has::<dyn LayoutBlock>() {
|
} else if content.has::<dyn LayoutBlock>() {
|
||||||
if !last_was_parbreak {
|
if !last_was_parbreak {
|
||||||
let tight = if let Some(node) = content.downcast::<ListNode>() {
|
let tight = if let Some(node) = content.downcast::<ListNode>() {
|
||||||
@ -505,11 +506,10 @@ impl<'a> FlowBuilder<'a> {
|
|||||||
self.0.push(above.pack(), styles);
|
self.0.push(above.pack(), styles);
|
||||||
self.0.push(content.clone(), styles);
|
self.0.push(content.clone(), styles);
|
||||||
self.0.push(below.pack(), styles);
|
self.0.push(below.pack(), styles);
|
||||||
} else {
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(self, doc: &mut DocBuilder<'a>, styles: StyleChain<'a>) {
|
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>) {
|
fn finish(self, parent: &mut Builder<'a>) {
|
||||||
let (mut children, shared) = self.0.finish();
|
let (children, shared) = self.0.finish();
|
||||||
if children.is_empty() {
|
if !children.is_empty() {
|
||||||
return;
|
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::<TextNode>() || child.is::<SmartQuoteNode>() {
|
|
||||||
Some(true)
|
|
||||||
} else if child.has::<dyn LayoutInline>() {
|
|
||||||
Some(false)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or_default()
|
|
||||||
&& parent
|
|
||||||
.flow
|
|
||||||
.0
|
|
||||||
.items()
|
|
||||||
.rev()
|
|
||||||
.find(|child| child.has::<dyn LayoutBlock>())
|
|
||||||
.map_or(false, |child| child.is::<ParNode>())
|
|
||||||
{
|
|
||||||
children.push_front(HNode::strong(indent.into()).pack());
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.flow.accept(&ParNode(children).pack(), shared);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
|
@ -393,6 +393,26 @@ fn collect<'a>(
|
|||||||
let mut segments = vec![];
|
let mut segments = vec![];
|
||||||
let mut iter = par.0.iter().peekable();
|
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::<TextNode>() || child.is::<SmartQuoteNode>() {
|
||||||
|
Some(true)
|
||||||
|
} else if child.has::<dyn LayoutInline>() {
|
||||||
|
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() {
|
while let Some((child, map)) = iter.next() {
|
||||||
let styles = map.chain(styles);
|
let styles = map.chain(styles);
|
||||||
let segment = if child.is::<SpaceNode>() {
|
let segment = if child.is::<SpaceNode>() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user