Compare commits

..

No commits in common. "6fcc4322845482c1810c26ee7f6fc8f6fed20d7d" and "b90ad470d60f4a90e3ba2e78aa4746fbe08783ab" have entirely different histories.

16 changed files with 104 additions and 202 deletions

View File

@ -22,7 +22,6 @@ use typst_library::text::TextElem;
use typst_library::World; use typst_library::World;
use super::{layout_multi_block, layout_single_block}; use super::{layout_multi_block, layout_single_block};
use crate::modifiers::layout_and_modify;
/// Collects all elements of the flow into prepared children. These are much /// Collects all elements of the flow into prepared children. These are much
/// simpler to handle than the raw elements. /// simpler to handle than the raw elements.
@ -378,9 +377,8 @@ fn layout_single_impl(
route: Route::extend(route), route: Route::extend(route),
}; };
layout_and_modify(styles, |styles| {
layout_single_block(elem, &mut engine, locator, styles, region) layout_single_block(elem, &mut engine, locator, styles, region)
}) .map(|frame| frame.post_processed(styles))
} }
/// A child that encapsulates a prepared breakable block. /// A child that encapsulates a prepared breakable block.
@ -475,8 +473,11 @@ fn layout_multi_impl(
route: Route::extend(route), route: Route::extend(route),
}; };
layout_and_modify(styles, |styles| { layout_multi_block(elem, &mut engine, locator, styles, regions).map(|mut fragment| {
layout_multi_block(elem, &mut engine, locator, styles, regions) for frame in &mut fragment {
frame.post_process(styles);
}
fragment
}) })
} }
@ -578,23 +579,20 @@ impl PlacedChild<'_> {
self.cell.get_or_init(base, |base| { self.cell.get_or_init(base, |base| {
let align = self.alignment.unwrap_or_else(|| Alignment::CENTER); let align = self.alignment.unwrap_or_else(|| Alignment::CENTER);
let aligned = AlignElem::set_alignment(align).wrap(); let aligned = AlignElem::set_alignment(align).wrap();
let styles = self.styles.chain(&aligned);
let mut frame = layout_and_modify(styles, |styles| { let mut frame = crate::layout_frame(
crate::layout_frame(
engine, engine,
&self.elem.body, &self.elem.body,
self.locator.relayout(), self.locator.relayout(),
styles, self.styles.chain(&aligned),
Region::new(base, Axes::splat(false)), Region::new(base, Axes::splat(false)),
) )?;
})?;
if self.float { if self.float {
frame.set_parent(self.elem.location().unwrap()); frame.set_parent(self.elem.location().unwrap());
} }
Ok(frame) Ok(frame.post_processed(self.styles))
}) })
} }

View File

@ -13,7 +13,6 @@ use typst_syntax::Span;
use typst_utils::Numeric; use typst_utils::Numeric;
use super::*; use super::*;
use crate::modifiers::{layout_and_modify, FrameModifiers, FrameModify};
// The characters by which spacing, inline content and pins are replaced in the // The characters by which spacing, inline content and pins are replaced in the
// paragraph's full text. // paragraph's full text.
@ -37,7 +36,7 @@ pub enum Item<'a> {
/// Fractional spacing between other items. /// Fractional spacing between other items.
Fractional(Fr, Option<(&'a Packed<BoxElem>, Locator<'a>, StyleChain<'a>)>), Fractional(Fr, Option<(&'a Packed<BoxElem>, Locator<'a>, StyleChain<'a>)>),
/// Layouted inline-level content. /// Layouted inline-level content.
Frame(Frame), Frame(Frame, StyleChain<'a>),
/// A tag. /// A tag.
Tag(&'a Tag), Tag(&'a Tag),
/// An item that is invisible and needs to be skipped, e.g. a Unicode /// An item that is invisible and needs to be skipped, e.g. a Unicode
@ -68,7 +67,7 @@ impl<'a> Item<'a> {
match self { match self {
Self::Text(shaped) => shaped.text, Self::Text(shaped) => shaped.text,
Self::Absolute(_, _) | Self::Fractional(_, _) => SPACING_REPLACE, Self::Absolute(_, _) | Self::Fractional(_, _) => SPACING_REPLACE,
Self::Frame(_) => OBJ_REPLACE, Self::Frame(_, _) => OBJ_REPLACE,
Self::Tag(_) => "", Self::Tag(_) => "",
Self::Skip(s) => s, Self::Skip(s) => s,
} }
@ -84,7 +83,7 @@ impl<'a> Item<'a> {
match self { match self {
Self::Text(shaped) => shaped.width, Self::Text(shaped) => shaped.width,
Self::Absolute(v, _) => *v, Self::Absolute(v, _) => *v,
Self::Frame(frame) => frame.width(), Self::Frame(frame, _) => frame.width(),
Self::Fractional(_, _) | Self::Tag(_) => Abs::zero(), Self::Fractional(_, _) | Self::Tag(_) => Abs::zero(),
Self::Skip(_) => Abs::zero(), Self::Skip(_) => Abs::zero(),
} }
@ -211,10 +210,8 @@ pub fn collect<'a>(
InlineItem::Space(space, weak) => { InlineItem::Space(space, weak) => {
collector.push_item(Item::Absolute(space, weak)); collector.push_item(Item::Absolute(space, weak));
} }
InlineItem::Frame(mut frame) => { InlineItem::Frame(frame) => {
frame.modify(&FrameModifiers::get_in(styles)); collector.push_item(Item::Frame(frame, styles));
apply_baseline_shift(&mut frame, styles);
collector.push_item(Item::Frame(frame));
} }
} }
} }
@ -225,11 +222,8 @@ pub fn collect<'a>(
if let Sizing::Fr(v) = elem.width(styles) { if let Sizing::Fr(v) = elem.width(styles) {
collector.push_item(Item::Fractional(v, Some((elem, loc, styles)))); collector.push_item(Item::Fractional(v, Some((elem, loc, styles))));
} else { } else {
let mut frame = layout_and_modify(styles, |styles| { let frame = layout_box(elem, engine, loc, styles, region)?;
layout_box(elem, engine, loc, styles, region) collector.push_item(Item::Frame(frame, styles));
})?;
apply_baseline_shift(&mut frame, styles);
collector.push_item(Item::Frame(frame));
} }
} else if let Some(elem) = child.to_packed::<TagElem>() { } else if let Some(elem) = child.to_packed::<TagElem>() {
collector.push_item(Item::Tag(&elem.tag)); collector.push_item(Item::Tag(&elem.tag));

View File

@ -10,7 +10,6 @@ use typst_library::text::{Lang, TextElem};
use typst_utils::Numeric; use typst_utils::Numeric;
use super::*; use super::*;
use crate::modifiers::layout_and_modify;
const SHY: char = '\u{ad}'; const SHY: char = '\u{ad}';
const HYPHEN: char = '-'; const HYPHEN: char = '-';
@ -94,7 +93,7 @@ impl Line<'_> {
pub fn has_negative_width_items(&self) -> bool { pub fn has_negative_width_items(&self) -> bool {
self.items.iter().any(|item| match item { self.items.iter().any(|item| match item {
Item::Absolute(amount, _) => *amount < Abs::zero(), Item::Absolute(amount, _) => *amount < Abs::zero(),
Item::Frame(frame) => frame.width() < Abs::zero(), Item::Frame(frame, _) => frame.width() < Abs::zero(),
_ => false, _ => false,
}) })
} }
@ -410,11 +409,6 @@ fn should_repeat_hyphen(pred_line: &Line, text: &str) -> bool {
} }
} }
/// Apply the current baseline shift to a frame.
pub fn apply_baseline_shift(frame: &mut Frame, styles: StyleChain) {
frame.translate(Point::with_y(TextElem::baseline_in(styles)));
}
/// Commit to a line and build its frame. /// Commit to a line and build its frame.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn commit( pub fn commit(
@ -515,11 +509,10 @@ pub fn commit(
let amount = v.share(fr, remaining); let amount = v.share(fr, remaining);
if let Some((elem, loc, styles)) = elem { if let Some((elem, loc, styles)) = elem {
let region = Size::new(amount, full); let region = Size::new(amount, full);
let mut frame = layout_and_modify(*styles, |styles| { let mut frame =
layout_box(elem, engine, loc.relayout(), styles, region) layout_box(elem, engine, loc.relayout(), *styles, region)?;
})?; frame.translate(Point::with_y(TextElem::baseline_in(*styles)));
apply_baseline_shift(&mut frame, *styles); push(&mut offset, frame.post_processed(*styles));
push(&mut offset, frame);
} else { } else {
offset += amount; offset += amount;
} }
@ -531,10 +524,12 @@ pub fn commit(
justification_ratio, justification_ratio,
extra_justification, extra_justification,
); );
push(&mut offset, frame); push(&mut offset, frame.post_processed(shaped.styles));
} }
Item::Frame(frame) => { Item::Frame(frame, styles) => {
push(&mut offset, frame.clone()); let mut frame = frame.clone();
frame.translate(Point::with_y(TextElem::baseline_in(*styles)));
push(&mut offset, frame.post_processed(*styles));
} }
Item::Tag(tag) => { Item::Tag(tag) => {
let mut frame = Frame::soft(Size::zero()); let mut frame = Frame::soft(Size::zero());

View File

@ -23,7 +23,7 @@ use typst_library::World;
use self::collect::{collect, Item, Segment, SpanMapper}; use self::collect::{collect, Item, Segment, SpanMapper};
use self::deco::decorate; use self::deco::decorate;
use self::finalize::finalize; use self::finalize::finalize;
use self::line::{apply_baseline_shift, commit, line, Line}; use self::line::{commit, line, Line};
use self::linebreak::{linebreak, Breakpoint}; use self::linebreak::{linebreak, Breakpoint};
use self::prepare::{prepare, Preparation}; use self::prepare::{prepare, Preparation};
use self::shaping::{ use self::shaping::{

View File

@ -20,7 +20,6 @@ use unicode_bidi::{BidiInfo, Level as BidiLevel};
use unicode_script::{Script, UnicodeScript}; use unicode_script::{Script, UnicodeScript};
use super::{decorate, Item, Range, SpanMapper}; use super::{decorate, Item, Range, SpanMapper};
use crate::modifiers::{FrameModifiers, FrameModify};
/// The result of shaping text. /// The result of shaping text.
/// ///
@ -327,7 +326,6 @@ impl<'a> ShapedText<'a> {
offset += width; offset += width;
} }
frame.modify(&FrameModifiers::get_in(self.styles));
frame frame
} }

View File

@ -6,7 +6,6 @@ mod image;
mod inline; mod inline;
mod lists; mod lists;
mod math; mod math;
mod modifiers;
mod pad; mod pad;
mod pages; mod pages;
mod repeat; mod repeat;

View File

@ -1,22 +1,23 @@
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use rustybuzz::Feature; use rustybuzz::Feature;
use smallvec::SmallVec;
use ttf_parser::gsub::{AlternateSubstitution, SingleSubstitution, SubstitutionSubtable}; use ttf_parser::gsub::{AlternateSubstitution, SingleSubstitution, SubstitutionSubtable};
use ttf_parser::opentype_layout::LayoutTable; use ttf_parser::opentype_layout::LayoutTable;
use ttf_parser::{GlyphId, Rect}; use ttf_parser::{GlyphId, Rect};
use typst_library::foundations::StyleChain; use typst_library::foundations::StyleChain;
use typst_library::introspection::Tag; use typst_library::introspection::Tag;
use typst_library::layout::{ use typst_library::layout::{
Abs, Axis, Corner, Em, Frame, FrameItem, Point, Size, VAlignment, Abs, Axis, Corner, Em, Frame, FrameItem, HideElem, Point, Size, VAlignment,
}; };
use typst_library::math::{EquationElem, MathSize}; use typst_library::math::{EquationElem, MathSize};
use typst_library::model::{Destination, LinkElem};
use typst_library::text::{Font, Glyph, Lang, Region, TextElem, TextItem}; use typst_library::text::{Font, Glyph, Lang, Region, TextElem, TextItem};
use typst_library::visualize::Paint; use typst_library::visualize::Paint;
use typst_syntax::Span; use typst_syntax::Span;
use unicode_math_class::MathClass; use unicode_math_class::MathClass;
use super::{stretch_glyph, MathContext, Scaled}; use super::{stretch_glyph, MathContext, Scaled};
use crate::modifiers::{FrameModifiers, FrameModify};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum MathFragment { pub enum MathFragment {
@ -244,7 +245,8 @@ pub struct GlyphFragment {
pub class: MathClass, pub class: MathClass,
pub math_size: MathSize, pub math_size: MathSize,
pub span: Span, pub span: Span,
pub modifiers: FrameModifiers, pub dests: SmallVec<[Destination; 1]>,
pub hidden: bool,
pub limits: Limits, pub limits: Limits,
pub extended_shape: bool, pub extended_shape: bool,
} }
@ -300,7 +302,8 @@ impl GlyphFragment {
accent_attach: Abs::zero(), accent_attach: Abs::zero(),
class, class,
span, span,
modifiers: FrameModifiers::get_in(styles), dests: LinkElem::dests_in(styles),
hidden: HideElem::hidden_in(styles),
extended_shape: false, extended_shape: false,
}; };
fragment.set_id(ctx, id); fragment.set_id(ctx, id);
@ -387,7 +390,7 @@ impl GlyphFragment {
let mut frame = Frame::soft(size); let mut frame = Frame::soft(size);
frame.set_baseline(self.ascent); frame.set_baseline(self.ascent);
frame.push(Point::with_y(self.ascent + self.shift), FrameItem::Text(item)); frame.push(Point::with_y(self.ascent + self.shift), FrameItem::Text(item));
frame.modify(&self.modifiers); frame.post_process_raw(self.dests, self.hidden);
frame frame
} }
@ -513,7 +516,7 @@ impl FrameFragment {
let base_ascent = frame.ascent(); let base_ascent = frame.ascent();
let accent_attach = frame.width() / 2.0; let accent_attach = frame.width() / 2.0;
Self { Self {
frame: frame.modified(&FrameModifiers::get_in(styles)), frame: frame.post_processed(styles),
font_size: TextElem::size_in(styles), font_size: TextElem::size_in(styles),
class: EquationElem::class_in(styles).unwrap_or(MathClass::Normal), class: EquationElem::class_in(styles).unwrap_or(MathClass::Normal),
math_size: EquationElem::size_in(styles), math_size: EquationElem::size_in(styles),

View File

@ -10,7 +10,6 @@ use super::{
delimiter_alignment, GlyphFragment, MathContext, MathFragment, Scaled, delimiter_alignment, GlyphFragment, MathContext, MathFragment, Scaled,
VariantFragment, VariantFragment,
}; };
use crate::modifiers::FrameModify;
/// Maximum number of times extenders can be repeated. /// Maximum number of times extenders can be repeated.
const MAX_REPEATS: usize = 1024; const MAX_REPEATS: usize = 1024;
@ -266,7 +265,7 @@ fn assemble(
let mut frame = Frame::soft(size); let mut frame = Frame::soft(size);
let mut offset = Abs::zero(); let mut offset = Abs::zero();
frame.set_baseline(baseline); frame.set_baseline(baseline);
frame.modify(&base.modifiers); frame.post_process_raw(base.dests, base.hidden);
for (fragment, advance) in selected { for (fragment, advance) in selected {
let pos = match axis { let pos = match axis {

View File

@ -1,110 +0,0 @@
use typst_library::foundations::StyleChain;
use typst_library::layout::{Fragment, Frame, FrameItem, HideElem, Point};
use typst_library::model::{Destination, LinkElem};
/// Frame-level modifications resulting from styles that do not impose any
/// layout structure.
///
/// These are always applied at the highest level of style uniformity.
/// Consequently, they must be applied by all layouters that manually manage
/// styles of their children (because they can produce children with varying
/// styles). This currently includes flow, inline, and math layout.
///
/// Other layouters don't manually need to handle it because their parents that
/// result from realization will take care of it and the styles can only apply
/// to them as a whole, not part of it (since they don't manage styles).
///
/// Currently existing frame modifiers are:
/// - `HideElem::hidden`
/// - `LinkElem::dests`
#[derive(Debug, Clone)]
pub struct FrameModifiers {
/// A destination to link to.
dest: Option<Destination>,
/// Whether the contents of the frame should be hidden.
hidden: bool,
}
impl FrameModifiers {
/// Retrieve all modifications that should be applied per-frame.
pub fn get_in(styles: StyleChain) -> Self {
Self {
dest: LinkElem::current_in(styles),
hidden: HideElem::hidden_in(styles),
}
}
}
/// Applies [`FrameModifiers`].
pub trait FrameModify {
/// Apply the modifiers in-place.
fn modify(&mut self, modifiers: &FrameModifiers);
/// Apply the modifiers, and return the modified result.
fn modified(mut self, modifiers: &FrameModifiers) -> Self
where
Self: Sized,
{
self.modify(modifiers);
self
}
}
impl FrameModify for Frame {
fn modify(&mut self, modifiers: &FrameModifiers) {
if let Some(dest) = &modifiers.dest {
let size = self.size();
self.push(Point::zero(), FrameItem::Link(dest.clone(), size));
}
if modifiers.hidden {
self.hide();
}
}
}
impl FrameModify for Fragment {
fn modify(&mut self, modifiers: &FrameModifiers) {
for frame in self.iter_mut() {
frame.modify(modifiers);
}
}
}
impl<T, E> FrameModify for Result<T, E>
where
T: FrameModify,
{
fn modify(&mut self, props: &FrameModifiers) {
if let Ok(inner) = self {
inner.modify(props);
}
}
}
/// Performs layout and modification in one step.
///
/// This just runs `layout(styles).modified(&FrameModifiers::get_in(styles))`,
/// but with the additional step that redundant modifiers (which are already
/// applied here) are removed from the `styles` passed to `layout`. This is used
/// for the layout of containers like `block`.
pub fn layout_and_modify<F, R>(styles: StyleChain, layout: F) -> R
where
F: FnOnce(StyleChain) -> R,
R: FrameModify,
{
let modifiers = FrameModifiers::get_in(styles);
// Disable the current link internally since it's already applied at this
// level of layout. This means we don't generate redundant nested links,
// which may bloat the output considerably.
let reset;
let outer = styles;
let mut styles = styles;
if modifiers.dest.is_some() {
reset = LinkElem::set_current(None).wrap();
styles = outer.chain(&reset);
}
layout(styles).modified(&modifiers)
}

View File

@ -9,6 +9,7 @@ use std::sync::Arc;
use comemo::Tracked; use comemo::Tracked;
use ecow::{eco_format, EcoString}; use ecow::{eco_format, EcoString};
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
use smallvec::smallvec;
use typst_syntax::Span; use typst_syntax::Span;
use typst_utils::{fat, singleton, LazyHash, SmallBitSet}; use typst_utils::{fat, singleton, LazyHash, SmallBitSet};
@ -499,7 +500,7 @@ impl Content {
/// Link the content somewhere. /// Link the content somewhere.
pub fn linked(self, dest: Destination) -> Self { pub fn linked(self, dest: Destination) -> Self {
self.styled(LinkElem::set_current(Some(dest))) self.styled(LinkElem::set_dests(smallvec![dest]))
} }
/// Set alignments for this content. /// Set alignments for this content.

View File

@ -4,13 +4,16 @@ use std::fmt::{self, Debug, Formatter};
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use std::sync::Arc; use std::sync::Arc;
use smallvec::SmallVec;
use typst_syntax::Span; use typst_syntax::Span;
use typst_utils::{LazyHash, Numeric}; use typst_utils::{LazyHash, Numeric};
use crate::foundations::{cast, dict, Dict, Label, Value}; use crate::foundations::{cast, dict, Dict, Label, StyleChain, Value};
use crate::introspection::{Location, Tag}; use crate::introspection::{Location, Tag};
use crate::layout::{Abs, Axes, FixedAlignment, Length, Point, Size, Transform}; use crate::layout::{
use crate::model::Destination; Abs, Axes, FixedAlignment, HideElem, Length, Point, Size, Transform,
};
use crate::model::{Destination, LinkElem};
use crate::text::TextItem; use crate::text::TextItem;
use crate::visualize::{Color, Curve, FixedStroke, Geometry, Image, Paint, Shape}; use crate::visualize::{Color, Curve, FixedStroke, Geometry, Image, Paint, Shape};
@ -301,6 +304,49 @@ impl Frame {
} }
} }
/// Apply late-stage properties from the style chain to this frame. This
/// includes:
/// - `HideElem::hidden`
/// - `LinkElem::dests`
///
/// This must be called on all frames produced by elements
/// that manually handle styles (because their children can have varying
/// styles). This currently includes flow, par, and equation.
///
/// Other elements don't manually need to handle it because their parents
/// that result from realization will take care of it and the styles can
/// only apply to them as a whole, not part of it (because they don't manage
/// styles).
pub fn post_processed(mut self, styles: StyleChain) -> Self {
self.post_process(styles);
self
}
/// Post process in place.
pub fn post_process(&mut self, styles: StyleChain) {
if !self.is_empty() {
self.post_process_raw(
LinkElem::dests_in(styles),
HideElem::hidden_in(styles),
);
}
}
/// Apply raw late-stage properties from the raw data.
pub fn post_process_raw(&mut self, dests: SmallVec<[Destination; 1]>, hide: bool) {
if !self.is_empty() {
let size = self.size;
self.push_multiple(
dests
.into_iter()
.map(|dest| (Point::zero(), FrameItem::Link(dest, size))),
);
if hide {
self.hide();
}
}
}
/// Hide all content in the frame, but keep metadata. /// Hide all content in the frame, but keep metadata.
pub fn hide(&mut self) { pub fn hide(&mut self) {
Arc::make_mut(&mut self.items).retain_mut(|(_, item)| match item { Arc::make_mut(&mut self.items).retain_mut(|(_, item)| match item {

View File

@ -1,12 +1,13 @@
use std::ops::Deref; use std::ops::Deref;
use ecow::{eco_format, EcoString}; use ecow::{eco_format, EcoString};
use smallvec::SmallVec;
use crate::diag::{bail, warning, At, SourceResult, StrResult}; use crate::diag::{bail, warning, At, SourceResult, StrResult};
use crate::engine::Engine; use crate::engine::Engine;
use crate::foundations::{ use crate::foundations::{
cast, elem, Content, Label, NativeElement, Packed, Repr, Show, ShowSet, Smart, cast, elem, Content, Label, NativeElement, Packed, Repr, Show, Smart, StyleChain,
StyleChain, Styles, TargetElem, TargetElem,
}; };
use crate::html::{attr, tag, HtmlElem}; use crate::html::{attr, tag, HtmlElem};
use crate::introspection::Location; use crate::introspection::Location;
@ -15,7 +16,7 @@ use crate::text::{Hyphenate, TextElem};
/// Links to a URL or a location in the document. /// Links to a URL or a location in the document.
/// ///
/// By default, links do not look any different from normal text. However, /// By default, links are not styled any different from normal text. However,
/// you can easily apply a style of your choice with a show rule. /// you can easily apply a style of your choice with a show rule.
/// ///
/// # Example /// # Example
@ -30,11 +31,6 @@ use crate::text::{Hyphenate, TextElem};
/// ] /// ]
/// ``` /// ```
/// ///
/// # Hyphenation
/// If you enable hyphenation or justification, by default, it will not apply to
/// links to prevent unwanted hyphenation in URLs. You can opt out of this
/// default via `{show link: set text(hyphenate: true)}`.
///
/// # Syntax /// # Syntax
/// This function also has dedicated syntax: Text that starts with `http://` or /// This function also has dedicated syntax: Text that starts with `http://` or
/// `https://` is automatically turned into a link. /// `https://` is automatically turned into a link.
@ -89,10 +85,10 @@ pub struct LinkElem {
})] })]
pub body: Content, pub body: Content,
/// A destination style that should be applied to elements. /// This style is set on the content contained in the `link` element.
#[internal] #[internal]
#[ghost] #[ghost]
pub current: Option<Destination>, pub dests: SmallVec<[Destination; 1]>,
} }
impl LinkElem { impl LinkElem {
@ -123,23 +119,17 @@ impl Show for Packed<LinkElem> {
body body
} }
} else { } else {
match &self.dest { let linked = match &self.dest {
LinkTarget::Dest(dest) => body.linked(dest.clone()), LinkTarget::Dest(dest) => body.linked(dest.clone()),
LinkTarget::Label(label) => { LinkTarget::Label(label) => {
let elem = engine.introspector.query_label(*label).at(self.span())?; let elem = engine.introspector.query_label(*label).at(self.span())?;
let dest = Destination::Location(elem.location().unwrap()); let dest = Destination::Location(elem.location().unwrap());
body.clone().linked(dest) body.clone().linked(dest)
} }
} };
})
}
}
impl ShowSet for Packed<LinkElem> { linked.styled(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false))))
fn show_set(&self, _: StyleChain) -> Styles { })
let mut out = Styles::new();
out.set(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false))));
out
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -75,14 +75,3 @@ Text <hey>
Text <hey> Text <hey>
// Error: 2-20 label `<hey>` occurs multiple times in the document // Error: 2-20 label `<hey>` occurs multiple times in the document
#link(<hey>)[Nope.] #link(<hey>)[Nope.]
--- link-empty-block ---
#link("", block(height: 10pt, width: 100%))
--- issue-758-link-repeat ---
#let url = "https://typst.org/"
#let body = [Hello #box(width: 1fr, repeat[.])]
Inline: #link(url, body)
#link(url, block(inset: 4pt, [Block: ] + body))