diff --git a/crates/typst/src/layout/inline/mod.rs b/crates/typst/src/layout/inline/mod.rs index d79dcba49..9928cb822 100644 --- a/crates/typst/src/layout/inline/mod.rs +++ b/crates/typst/src/layout/inline/mod.rs @@ -73,7 +73,8 @@ pub(crate) fn layout_inline( let lines = linebreak(&engine, &p, region.x - p.hang); // Stack the lines into one frame per region. - finalize(&mut engine, &p, &lines, region, expand) + let shrink = ParElem::shrink_in(styles); + finalize(&mut engine, &p, &lines, region, expand, shrink) } let fragment = cached( @@ -1191,6 +1192,7 @@ fn finalize( lines: &[Line], region: Size, expand: bool, + shrink: bool, ) -> SourceResult { // Determine the paragraph's width: Full width of the region if we // should expand or there's fractional spacing, fit-to-width otherwise. @@ -1207,7 +1209,7 @@ fn finalize( // Stack the lines into one frame per region. let mut frames: Vec = lines .iter() - .map(|line| commit(engine, p, line, width, region.y)) + .map(|line| commit(engine, p, line, width, region.y, shrink)) .collect::>()?; // Prevent orphans. @@ -1243,6 +1245,7 @@ fn commit( line: &Line, width: Abs, full: Abs, + shrink: bool, ) -> SourceResult { let mut remaining = width - line.width - p.hang; let mut offset = Abs::zero(); @@ -1289,12 +1292,12 @@ fn commit( let mut justification_ratio = 0.0; let mut extra_justification = Abs::zero(); - let shrink = line.shrinkability(); + let shrinkability = line.shrinkability(); let stretch = line.stretchability(); - if remaining < Abs::zero() && shrink > Abs::zero() { + if remaining < Abs::zero() && shrinkability > Abs::zero() && shrink { // Attempt to reduce the length of the line, using shrinkability. - justification_ratio = (remaining / shrink).max(-1.0); - remaining = (remaining + shrink).min(Abs::zero()); + justification_ratio = (remaining / shrinkability).max(-1.0); + remaining = (remaining + shrinkability).min(Abs::zero()); } else if line.justify && fr.is_zero() { // Attempt to increase the length of the line, using stretchability. if stretch > Abs::zero() { diff --git a/crates/typst/src/model/par.rs b/crates/typst/src/model/par.rs index cc4a1fcb7..f8a833aca 100644 --- a/crates/typst/src/model/par.rs +++ b/crates/typst/src/model/par.rs @@ -96,6 +96,15 @@ pub struct ParElem { #[resolve] pub hanging_indent: Length, + /// Indicates wheter an overflowing line should be shrunk. + /// + /// This property is set to `false` on raw blocks, because shrinking a line + /// could visually break the indentation. + #[ghost] + #[internal] + #[default(true)] + pub shrink: bool, + /// The contents of the paragraph. #[external] #[required] diff --git a/crates/typst/src/text/raw.rs b/crates/typst/src/text/raw.rs index 2d590d2a9..f0105363f 100644 --- a/crates/typst/src/text/raw.rs +++ b/crates/typst/src/text/raw.rs @@ -16,7 +16,7 @@ use crate::foundations::{ PlainText, Show, ShowSet, Smart, StyleChain, Styles, Synthesize, Value, }; use crate::layout::{BlockElem, Em, HAlignment}; -use crate::model::Figurable; +use crate::model::{Figurable, ParElem}; use crate::syntax::{split_newlines, LinkedNode, Span, Spanned}; use crate::text::{ FontFamily, FontList, Hyphenate, Lang, LinebreakElem, LocalName, Region, @@ -440,13 +440,16 @@ impl Show for Packed { } impl ShowSet for Packed { - fn show_set(&self, _: StyleChain) -> Styles { + fn show_set(&self, styles: StyleChain) -> Styles { let mut out = Styles::new(); out.set(TextElem::set_overhang(false)); out.set(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false)))); out.set(TextElem::set_size(TextSize(Em::new(0.8).into()))); out.set(TextElem::set_font(FontList(vec![FontFamily::new("DejaVu Sans Mono")]))); out.set(SmartQuoteElem::set_enabled(false)); + if self.block(styles) { + out.set(ParElem::set_shrink(false)); + } out } } diff --git a/tests/ref/layout/code-indent-shrink.png b/tests/ref/layout/code-indent-shrink.png new file mode 100644 index 000000000..26f6ec404 Binary files /dev/null and b/tests/ref/layout/code-indent-shrink.png differ diff --git a/tests/typ/layout/code-indent-shrink.typ b/tests/typ/layout/code-indent-shrink.typ new file mode 100644 index 000000000..1527e061c --- /dev/null +++ b/tests/typ/layout/code-indent-shrink.typ @@ -0,0 +1,28 @@ +// Spaces in raw blocks should not be shrunk +// as it would mess up the indentation of code +// https://github.com/typst/typst/issues/3191 + +--- +#set par(justify: true) + +#show raw.where(block: true): block.with( + fill: luma(240), + inset: 10pt, +) + +#block( + width: 60%, + ```py + for x in xs: + print("x=",x) + ``` +) + +--- +// In normal paragraphs, spaces should still be shrunk. +// The first line here serves as a reference, while the second +// uses non-breaking spaces to create an overflowing line +// (which should shrink). +~~~~No shrinking here + +~~~~The~spaces~on~this~line~shrink \ No newline at end of file