First-line indents

Co-Authored-By: Martin Haug <mhaug@live.de>
This commit is contained in:
Laurenz 2022-02-24 18:47:43 +01:00
parent 90132b0d65
commit 49c0bac44d
6 changed files with 81 additions and 1 deletions

View File

@ -67,6 +67,11 @@ impl<'a, T: Merge> CollapsingBuilder<'a, T> {
self.staged.push((item, styles, None)); self.staged.push((item, styles, None));
} }
/// Iterate over the contained items.
pub fn items(&self) -> impl DoubleEndedIterator<Item = &T> {
self.builder.items().chain(self.staged.iter().map(|(item, ..)| item))
}
/// Return the finish style vec and the common prefix chain. /// Return the finish style vec and the common prefix chain.
pub fn finish(mut self) -> (StyleVec<T>, StyleChain<'a>) { pub fn finish(mut self) -> (StyleVec<T>, StyleChain<'a>) {
self.flush(false); self.flush(false);

View File

@ -547,6 +547,17 @@ impl<T> StyleVec<T> {
.flat_map(|(map, count)| std::iter::repeat(map).take(*count)); .flat_map(|(map, count)| std::iter::repeat(map).take(*count));
self.items().zip(styles) self.items().zip(styles)
} }
/// Insert an element in the front. The element will share the style of the
/// current first element.
///
/// This method has no effect if the vector is empty.
pub fn push_front(&mut self, item: T) {
if !self.maps.is_empty() {
self.items.insert(0, item);
self.maps[0].1 += 1;
}
}
} }
impl<T> Default for StyleVec<T> { impl<T> Default for StyleVec<T> {
@ -601,6 +612,11 @@ impl<'a, T> StyleVecBuilder<'a, T> {
Some((item, chain)) Some((item, chain))
} }
/// Iterate over the contained items.
pub fn items(&self) -> std::slice::Iter<'_, T> {
self.items.iter()
}
/// Finish building, returning a pair of two things: /// Finish building, returning a pair of two things:
/// - a style vector of items with the non-shared styles /// - a style vector of items with the non-shared styles
/// - a shared prefix chain of styles that apply to all items /// - a shared prefix chain of styles that apply to all items

View File

@ -445,8 +445,36 @@ impl<'a> Builder<'a> {
/// Finish the currently built paragraph. /// Finish the currently built paragraph.
fn finish_par(&mut self, styles: StyleChain<'a>) { fn finish_par(&mut self, styles: StyleChain<'a>) {
let (par, shared) = std::mem::take(&mut self.par).finish(); let (mut par, shared) = std::mem::take(&mut self.par).finish();
if !par.is_empty() { if !par.is_empty() {
// 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()
&& par
.items()
.find_map(|child| match child {
ParChild::Spacing(_) => None,
ParChild::Text(_) => Some(true),
ParChild::Node(_) => Some(false),
})
.unwrap_or_default()
&& self
.flow
.items()
.rev()
.find_map(|child| match child {
FlowChild::Leading => None,
FlowChild::Parbreak => None,
FlowChild::Node(node) => Some(node.is::<ParNode>()),
FlowChild::Spacing(_) => Some(false),
FlowChild::Colbreak => Some(false),
})
.unwrap_or_default()
{
par.push_front(ParChild::Spacing(SpacingKind::Linear(indent)))
}
let node = ParNode(par).pack(); let node = ParNode(par).pack();
self.flow.supportive(FlowChild::Node(node), shared); self.flow.supportive(FlowChild::Node(node), shared);
} }

View File

@ -36,6 +36,8 @@ impl ParNode {
pub const LEADING: Linear = Relative::new(0.65).into(); pub const LEADING: Linear = Relative::new(0.65).into();
/// The extra spacing between paragraphs (dependent on scaled font size). /// The extra spacing between paragraphs (dependent on scaled font size).
pub const SPACING: Linear = Relative::new(0.55).into(); pub const SPACING: Linear = Relative::new(0.55).into();
/// The indent the first line of a consecutive paragraph should have.
pub const INDENT: Linear = Linear::zero();
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Template> { fn construct(_: &mut Context, args: &mut Args) -> TypResult<Template> {
// The paragraph constructor is special: It doesn't create a paragraph // The paragraph constructor is special: It doesn't create a paragraph
@ -75,6 +77,7 @@ impl ParNode {
styles.set_opt(Self::ALIGN, align); styles.set_opt(Self::ALIGN, align);
styles.set_opt(Self::LEADING, args.named("leading")?); styles.set_opt(Self::LEADING, args.named("leading")?);
styles.set_opt(Self::SPACING, args.named("spacing")?); styles.set_opt(Self::SPACING, args.named("spacing")?);
styles.set_opt(Self::INDENT, args.named("indent")?);
Ok(()) Ok(())
} }

BIN
tests/ref/text/indent.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

28
tests/typ/text/indent.typ Normal file
View File

@ -0,0 +1,28 @@
// Test paragraph indent.
---
#set par(indent: 12pt, leading: 5pt, spacing: 0pt)
#set heading(size: 10pt, above: 8pt)
The first paragraph has no indent.
But the second one does.
#image("../../res/tiger.jpg", height: 6pt)
starts a paragraph without indent.
#align(center, image("../../res/rhino.png", width: 1cm))
= Headings
- And lists.
- Have no indent.
Except if you have another paragraph in them.
#set text(8pt, "Noto Sans Arabic")
#set par(lang: "ar", leading: 8pt)
= Arabic
دع النص يمطر عليك
ثم يصبح النص رطبًا وقابل للطرق ويبدو المستند رائعًا.