mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
First-line indents
Co-Authored-By: Martin Haug <mhaug@live.de>
This commit is contained in:
parent
90132b0d65
commit
49c0bac44d
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
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
28
tests/typ/text/indent.typ
Normal 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
|
||||||
|
دع النص يمطر عليك
|
||||||
|
|
||||||
|
ثم يصبح النص رطبًا وقابل للطرق ويبدو المستند رائعًا.
|
Loading…
x
Reference in New Issue
Block a user